소스 검색

Adds welcome & settings pages (wip)

main
Eric Amodio 6 년 전
부모
커밋
b180ecc1e2
24개의 변경된 파일8421개의 추가작업 그리고 338개의 파일을 삭제
  1. +3
    -1
      .gitignore
  2. +5
    -0
      .vscodeignore
  3. +1
    -1
      README.md
  4. +0
    -18
      images/gitlens-icon.svg
  5. +13
    -2
      package.json
  6. +3
    -2
      src/configuration.ts
  7. +7
    -0
      src/container.ts
  8. +68
    -0
      src/pageProvider.ts
  9. +0
    -0
      src/ui/config.ts
  10. +6964
    -0
      src/ui/package-lock.json
  11. +42
    -0
      src/ui/package.json
  12. +344
    -0
      src/ui/scss/main.scss
  13. +101
    -0
      src/ui/settings/app.ts
  14. +136
    -0
      src/ui/settings/index.html
  15. +4
    -0
      src/ui/settings/index.ts
  16. +95
    -0
      src/ui/shared/colors.ts
  17. +44
    -0
      src/ui/shared/dom.ts
  18. +23
    -0
      src/ui/tsconfig.json
  19. +132
    -0
      src/ui/webpack.config.js
  20. +32
    -0
      src/ui/welcome/app.ts
  21. +85
    -0
      src/ui/welcome/index.html
  22. +4
    -0
      src/ui/welcome/index.ts
  23. +2
    -1
      tsconfig.json

+ 3
- 1
.gitignore 파일 보기

@ -1,2 +1,4 @@
out
node_modules
node_modules
settings.html
welcome.html

+ 5
- 0
.vscodeignore 파일 보기

@ -1,11 +1,16 @@
!images/dark/**
!images/light/**
!images/gitlens-icon.png
!images/screenshot-line-blame-annotation.png
!images/screenshot-code-lens.png
!images/screenshot-status-bar.png
!images/screenshot-git-custom-view-repository.png
images/**
.vscode/**
.vscode-test/**
test/**
src/**
out/ui/**
**/*.map
.github/**
.gitignore

+ 1
- 1
README.md 파일 보기

@ -10,7 +10,7 @@
# GitLens
GitLens **supercharges** the built-in Visual Studio Code Git capabilities. It helps you to **visualize code authorship** at a glance via Git blame annotations and code lens, **seamlessly navigate and explore** the history of a file or branch, **gain valuable insights** via powerful comparison commands, and so much more.
GitLens **supercharges** the Git capabilities built into Visual Studio Code. It helps you to **visualize code authorship** at a glance via Git blame annotations and code lens, **seamlessly navigate and explore** the history of a file or branch, **gain valuable insights** via powerful comparison commands, and so much more.
GitLens provides an unobtrusive blame annotation at the end of the current line, a status bar item showing the commit information (author and date, by default) of the current line, code lens showing the most recent commit and # of authors of the file and/or code block, and many commands for exploring commits and histories, comparing and navigating revisions, stash access, repository status, and more. GitLens is also [highly customizable](#extension-settings) to meet your specific needs — find code lens intrusive or the current line blame annotation distracting — no problem, it is easy to [turn them off or change how they behave](#extension-settings).

+ 0
- 18
images/gitlens-icon.svg 파일 보기

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 93 93" style="enable-background:new 0 0 93 93;" xml:space="preserve">
<g>
<path fill="#F05133" d="M90,41.8L49.9,1.7c-2.3-2.3-6.1-2.3-8.4,0L33.2,10l10.6,10.6c2.5-0.8,5.3-0.3,7.2,1.7c2,2,2.5,4.8,1.7,7.3
l10.2,10.2c2.5-0.8,5.3-0.3,7.3,1.7c2.8,2.7,2.8,7.2,0,10s-7.2,2.8-10,0c-2.1-2.1-2.6-5.1-1.5-7.7l-9.5-9.5v25
c0.7,0.3,1.3,0.8,1.9,1.3c2.8,2.7,2.8,7.2,0,10c-2.8,2.7-7.2,2.7-10,0c-2.8-2.8-2.8-7.2,0-10c0.7-0.7,1.5-1.2,2.3-1.5V33.8
c-0.8-0.3-1.6-0.9-2.3-1.5c-2.1-2.1-2.6-5.1-1.5-7.7L29.2,14.2L1.7,41.7c-2.3,2.3-2.3,6.1,0,8.4l40.1,40.1c2.3,2.3,6.1,2.3,8.4,0
l39.9-39.9C92.4,47.9,92.4,44.1,90,41.8z"/>
</g>
<g>
<path fill="#FFFFFF" d="M38.1,56.9l-9-9c1.2-1.6,1.9-3.5,1.9-5.6c0-5.2-4.2-9.4-9.4-9.4s-9.4,4.2-9.4,9.4s4.2,9.4,9.4,9.4
c2.1,0,4.1-0.7,5.6-1.9l9,9c0.3,0.3,0.6,0.4,0.9,0.4c0.3,0,0.7-0.1,0.9-0.4C38.6,58.2,38.6,57.4,38.1,56.9z M21.6,49.7
c-4.1,0-7.5-3.4-7.5-7.5s3.4-7.5,7.5-7.5s7.5,3.4,7.5,7.5S25.7,49.7,21.6,49.7z"/>
<path fill="#FFFFFF" d="M27,41.7c0.1,0,0.2,0,0.2,0c0.5-0.1,0.8-0.6,0.7-1.2c-0.5-1.7-1.5-3.1-3.1-4c-1.5-0.9-3.3-1.1-5-0.7
c-0.5,0.1-0.8,0.6-0.7,1.2c0.1,0.5,0.6,0.8,1.2,0.7c1.2-0.3,2.5-0.2,3.6,0.5c1.1,0.6,1.9,1.6,2.2,2.9C26.2,41.4,26.6,41.7,27,41.7z"/>
<circle fill="#FFFFFF" cx="27.1" cy="43.9" r="0.9"/>
</g>
</svg>

+ 13
- 2
package.json 파일 보기

@ -1073,6 +1073,16 @@
}
],
"commands": [
{
"command": "gitlens.showSettingsPage",
"title": "Open Settings",
"category": "GitLens"
},
{
"command": "gitlens.showWelcomePage",
"title": "Welcome",
"category": "GitLens"
},
{
"command": "gitlens.diffDirectory",
"title": "Directory Compare Working Tree with...",
@ -3231,8 +3241,9 @@
"*"
],
"scripts": {
"build": "npm run lint && tsc -m commonjs -p ./",
"bundle": "npm run lint && webpack --env.production",
"build": "npm run lint && tsc -m commonjs -p ./ && npm run build-ui",
"build-ui": "webpack --context ./src/ui --config ./src/ui/webpack.config.js",
"bundle": "npm run lint && webpack --env.production --context ./src/ui --config ./src/ui/webpack.config.js && webpack --env.production",
"clean": "git clean -Xdf",
"lint": "tslint --project tslint.json",
"pack": "vsce package",

+ 3
- 2
src/configuration.ts 파일 보기

@ -1,10 +1,10 @@
'use strict';
export * from './config';
export * from './ui/config';
export { ExtensionKey };
import { Functions } from './system';
import { ConfigurationChangeEvent, ConfigurationTarget, Event, EventEmitter, ExtensionContext, Uri, workspace } from 'vscode';
import { IConfig, KeyMap } from './config';
import { IConfig, KeyMap } from './ui/config';
import { CommandContext, ExtensionKey, setCommandContext } from './constants';
import { Container } from './container';
import { clearGravatarCache } from './gitService';
@ -30,6 +30,7 @@ export class Configuration {
if (!e.affectsConfiguration(ExtensionKey, null!)) return;
Container.resetConfig();
Container.pages.refresh();
if (configuration.changed(e, configuration.name('defaultGravatarsStyle').value)) {
clearGravatarCache();

+ 7
- 0
src/container.ts 파일 보기

@ -11,6 +11,7 @@ import { GitExplorer } from './views/gitExplorer';
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
import { GitService } from './gitService';
import { Keyboard } from './keyboard';
import { PageProvider } from './pageProvider';
import { ResultsExplorer } from './views/resultsExplorer';
export class Container {
@ -29,6 +30,7 @@ export class Container {
context.subscriptions.push(this._currentLineController = new CurrentLineController());
context.subscriptions.push(this._codeLensController = new CodeLensController());
context.subscriptions.push(this._keyboard = new Keyboard());
context.subscriptions.push(this._pageProvider = new PageProvider());
if (config.gitExplorer.enabled) {
context.subscriptions.push(this._gitExplorer = new GitExplorer());
@ -98,6 +100,11 @@ export class Container {
return this._currentLineController;
}
private static _pageProvider: PageProvider;
static get pages() {
return this._pageProvider;
}
private static _resultsExplorer: ResultsExplorer | undefined;
static get resultsExplorer() {
if (this._resultsExplorer === undefined) {

+ 68
- 0
src/pageProvider.ts 파일 보기

@ -0,0 +1,68 @@
'use strict';
import { commands, ConfigurationTarget, Disposable, Event, EventEmitter, TextDocumentContentProvider, Uri, ViewColumn, workspace } from 'vscode';
import { Container } from './container';
import { configuration } from './configuration';
import { Logger } from './logger';
const settingsUri = Uri.parse('gitlens://authority/settings');
const welcomeUri = Uri.parse('gitlens://authority/welcome');
export class PageProvider extends Disposable implements TextDocumentContentProvider {
private readonly _onDidChange = new EventEmitter<Uri>();
get onDidChange(): Event<Uri> {
return this._onDidChange.event;
}
private readonly _disposable: Disposable;
constructor() {
super(() => this.dispose());
this._disposable = Disposable.from(
workspace.registerTextDocumentContentProvider(settingsUri.scheme, this),
commands.registerCommand('gitlens.showSettingsPage', this.showSettings, this),
commands.registerCommand('gitlens.showWelcomePage', this.showWelcome, this),
commands.registerCommand('gitlens.saveSettings', this.save, this)
);
}
dispose() {
this._disposable.dispose();
}
async provideTextDocumentContent(uri: Uri): Promise<string> {
const doc = await workspace.openTextDocument(Uri.file(Container.context.asAbsolutePath(`${uri.path}.html`)));
let text = doc.getText()
.replace(/{{root}}/g, Uri.file(Container.context.asAbsolutePath('.')).toString());
if (text.includes('\'{{config}}\'')) {
text = text.replace(/'{{config}}'/g, JSON.stringify(Container.config));
}
return text;
}
refresh(uri?: Uri) {
Logger.log('PageProvider.refresh');
this._onDidChange.fire(uri || settingsUri);
}
async save(changes: { [key: string]: any }) {
Logger.log(`PageProvider.save: changes=${JSON.stringify(changes)}`);
for (const key in changes) {
await configuration.update(key, changes[key], ConfigurationTarget.Global);
}
}
async showSettings() {
return await commands.executeCommand('vscode.previewHtml', settingsUri, ViewColumn.Active, 'GitLens Settings');
}
async showWelcome() {
return await commands.executeCommand('vscode.previewHtml', welcomeUri, ViewColumn.Active, 'Welcome to GitLens');
}
}

src/config.ts → src/ui/config.ts 파일 보기


+ 6964
- 0
src/ui/package-lock.json
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 42
- 0
src/ui/package.json 파일 보기

@ -0,0 +1,42 @@
{
"name": "gitlens-ui",
"version": "0.0.1",
"author": {
"name": "Eric Amodio",
"email": "eamodio@gmail.com"
},
"engines": {
"node": ">= 6.11.0"
},
"license": "SEE LICENSE IN LICENSE",
"description": "",
"homepage": "https://github.com/eamodio/vscode-gitlens/blob/master/README.md",
"bugs": {
"url": "https://github.com/eamodio/vscode-gitlens/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/eamodio/vscode-gitlens.git"
},
"private": true,
"scripts": {
"build": "webpack --env.production",
"build-dev": "webpack"
},
"devDependencies": {
"@types/node": "9.3.0",
"@types/webpack": "3.8.2",
"css-loader": "0.28.8",
"extract-text-webpack-plugin": "3.0.2",
"html-webpack-inline-source-plugin": "0.0.9",
"html-webpack-plugin": "2.30.1",
"node-sass": "4.7.2",
"sass-loader": "6.0.6",
"style-loader": "0.19.1",
"tslint": "5.9.1",
"ts-loader": "3.2.0",
"typescript": "2.6.2",
"uglifyjs-webpack-plugin": "1.1.6",
"webpack": "3.10.0"
}
}

+ 344
- 0
src/ui/scss/main.scss 파일 보기

@ -0,0 +1,344 @@
html {
height: 100%;
}
body {
background-color: var(--background-color);
color: var(--color);
font-family: var(--font-family);
height: 100%;
line-height: 1.4em;
}
a {
border: 0;
color: var(--link-color);
font-weight: 400;
outline: none;
text-decoration: none;
&:not([href]):not([tabindex]):focus,
&:not([href]):not([tabindex]):hover {
color: inherit;
text-decoration: none;
}
&:focus {
.vscode-light & {
outline-color: var(--background-color--darken-30);
}
.vscode-dark & {
outline-color: var(--background-color--lighten-30);
}
}
}
b {
font-weight: 600;
}
h1 {
padding: 0;
margin: 0;
border: none;
font-weight: 400;
font-size: 2.77em;
white-space: nowrap;
}
h2 {
font-weight: 200;
margin: 1em 0 0.3em 0;
font-size: 1.5em;
line-height: normal;
white-space: nowrap;
}
header {
display: flex;
flex-wrap: wrap;
align-items: center;
margin-bottom: 3em;
}
input, select, button {
margin: 0;
}
input {
background: none;
border: none;
cursor: pointer;
margin: 0;
padding: 0 10px;
&:focus {
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
outline: none;
}
&[type="checkbox"] {
margin: -2px .25em 0 .25em;
vertical-align: middle;
}
}
label {
cursor : pointer;
}
section {
display: flex;
flex-wrap: wrap;
padding: 1rem;
margin-bottom: 1em;
.vscode-light & {
background-color: var(--background-color--darken-05);
}
.vscode-dark & {
background-color: var(--background-color--lighten-05);
}
}
select {
color: var(--color);
cursor: pointer;
margin: 0.5em 0.25em 0 0.25em;
padding: 2px;
.vscode-light & {
background-color: var(--background-color--darken-05);
}
.vscode-dark & {
background-color: var(--background-color--lighten-05);
}
}
select option {
.vscode-light & {
background-color: var(--background-color--darken-05);
}
.vscode-dark & {
background-color: var(--background-color--lighten-05);
}
}
ul {
font-size: 1em;
list-style: none;
margin: 0;
padding: 0;
}
.container {
align-items: center;
display: flex;
justify-content: center;
min-width: 100%;
min-height: 100%;
}
.content {
margin-top: 3em;
max-width: 1200px;
min-width: 450px;
width: 90%;
}
.header__blurb {
color: var(--color--75);
flex: 58% 2 1;
font-size: 1.2em;
font-weight: 200;
margin: 0 3em;
}
.header__logo {
display: flex;
flex-wrap: nowrap;
padding-top: 2.5em;
}
.header__subtitle {
color: var(--color--50);
display: block;
font-size: 2em;
margin-top: .8em;
white-space: nowrap;
}
.icon {
background-color: var(--color);
width: 19px;
height: 24px;
display: inline-block;
margin-bottom: -9px;
}
.icon__info {
-webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125"><path fill="none" d="M0 0h100v100H0z"/><path d="M50 21a29 29 0 1 0 29 29 29 29 0 0 0-29-29zm0 55a26 26 0 1 1 26-26 26 26 0 0 1-26 26z"/><path d="M48 45l-1 1v18l1 1h4l1-1V46l-1-1zm0-10l-1 1v4l1 1h4l1-1v-4l-1-1z"/></svg>');
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125"><path fill="none" d="M0 0h100v100H0z"/><path d="M50 21a29 29 0 1 0 29 29 29 29 0 0 0-29-29zm0 55a26 26 0 1 1 26-26 26 26 0 0 1-26 26z"/><path d="M48 45l-1 1v18l1 1h4l1-1V46l-1-1zm0-10l-1 1v4l1 1h4l1-1v-4l-1-1z"/></svg>');
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
.image__logo {
max-width: 64px;
max-height: 64px;
margin-top: -5px;
margin-right: 1em;
}
.image__preview {
border-radius: 8px;
box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.8), 0px 0px 12px 1px rgba(0, 0, 0, 0.5);
}
.label__hint {
color: var(--color--75);
display: block;
font-weight: 200;
margin: 1em 2em;
}
.list-button {
margin: 5px 1px;
padding: 12px 10px;
width: calc(100% - 2px);
height: 5em;
font-size: 1em;
text-align: left;
cursor: pointer;
white-space: nowrap;
font-family: inherit;
border: none;
color: var(--color);
max-width: 475px;
.vscode-light & {
background-color: var(--background-color--darken-05);
}
.vscode-dark & {
background-color: var(--background-color--lighten-05);
}
&:hover, &:focus {
.vscode-light & {
background-color: var(--background-color--darken-075);
}
.vscode-dark & {
background-color: var(--background-color--lighten-075);
}
}
&:focus {
outline: 0;
.vscode-light & {
border: 1px solid var(--background-color--darken-15);
}
.vscode-dark & {
border: 1px solid var(--background-color--lighten-15);
}
}
* {
overflow: hidden;
text-overflow: ellipsis;
}
h3 {
font-weight: 400;
font-size: 1em;
margin: 0;
margin-bottom: .25em;
}
.detail {
color: var(--color--75);
display: inline-block;
width: 100%;
}
}
.section__preview {
flex: 40% 1 1;
text-align: end;
min-width: 300px;
}
.section__settings {
display: flex;
flex: 100% 1 0;
flex-wrap: wrap;
margin-right: 1em;
}
.section__header {
display: flex;
align-items: baseline;
flex: 100% 0 0;
flex-wrap: wrap;
margin-bottom: 2em;
}
.section__title {
flex: 100% 1 0;
margin: 0;
}
.section__title-hint {
color: var(--color--75);
font-weight: 200;
margin: 0.25em 0;
}
.section__welcome {
margin: 1em 0;
p {
font-size: 1.1em;
font-weight: 200;
margin: 1em 0.25em;
max-width: calc(475px - 0.5em);
line-height: 1.275;
}
}
.section-group__main {
min-width: 0;
}
.section-group__sidebar {
margin-left: 3em;
}
.section-groups {
display: flex;
justify-content: space-around;
margin: 0 1em;
}
.settings-group {
margin-bottom: 1em;
flex: 2 1;
min-width: 300px;
}
.settings-group__setting {
margin-bottom: 1em;
}
.sidebar-group {
margin-top: 1em;
}

+ 101
- 0
src/ui/settings/app.ts 파일 보기

@ -0,0 +1,101 @@
'use strict';
import { DOM } from './../shared/dom';
import { initializeColorPalette } from '../shared/colors';
import { IConfig } from './../config';
const config: IConfig = (window as any).gitlens.config;
const changes: { [key: string]: any } = Object.create(null);
export class App {
private readonly _commandRelay: HTMLAnchorElement;
constructor() {
console.log('SettingsApp.ctor');
this._commandRelay = DOM.getElementById<HTMLAnchorElement>('commandRelay');
initializeColorPalette();
this.initializeState();
const onChecked = this.onChecked.bind(this);
DOM.listenAll('input[type="checkbox"],input[type="radio"]', 'change', function(this: HTMLInputElement) { onChecked(this); });
const onSelected = this.onSelected.bind(this);
DOM.listenAll('select', 'change', function(this: HTMLInputElement) { onSelected(this); });
}
private onChecked(element: HTMLInputElement) {
console.log(`SettingsApp.onChange: name=${element.name}, checked=${element.checked}, value=${element.value}`);
let value;
if (element.checked) {
value = element.value === 'on' ? true : element.value;
}
else {
value = false;
}
changes[element.name] = value;
for (const el of document.querySelectorAll<HTMLInputElement | HTMLSelectElement>(`[data-readonly="${element.name}"]`)) {
if (el.tagName === 'SELECT') {
el.disabled = !value;
}
else {
(el as HTMLInputElement).readOnly = !value;
}
}
this.applyChanges();
}
private onSelected(element: HTMLSelectElement) {
const value = element.options[element.selectedIndex].value;
console.log(`SettingsApp.onSelected: name=${element.name}, value=${value}`);
changes[element.name] = value;
this.applyChanges();
}
private applyChanges() {
const args = JSON.stringify(changes);
console.log(`SettingsApp.applyChanges: changes=${args}`);
const command = 'command:gitlens.saveSettings?' + encodeURI(args);
setTimeout(() => this.executeCommand(command), 0);
}
private executeCommand(command: string | undefined) {
if (command === undefined) return;
console.log(`SettingsApp.executeCommand: command=${command}`);
this._commandRelay.setAttribute('href', command);
this._commandRelay.click();
}
private initializeState() {
console.log('SettingsApp.initializeState');
DOM.getElementById<HTMLInputElement>(`blame.line.enabled`).checked = config.blame.line.enabled;
let element = DOM.getElementById<HTMLSelectElement>(`blame.line.annotationType`)!;
element.querySelector<HTMLOptionElement>(`option[value='${config.blame.line.annotationType}']`)!.selected = true;
if (config.blame.line.enabled) {
element.disabled = false;
}
DOM.getElementById<HTMLInputElement>(`statusBar.enabled`).checked = config.statusBar.enabled;
DOM.getElementById<HTMLInputElement>(`codeLens.enabled`).checked = config.codeLens.enabled;
DOM.getElementById<HTMLInputElement>(`gitExplorer.enabled`).checked = config.gitExplorer.enabled;
element = DOM.getElementById<HTMLSelectElement>(`gitExplorer.view`)!;
element.querySelector<HTMLOptionElement>(`option[value='${config.gitExplorer.view}']`)!.selected = true;
element = DOM.getElementById<HTMLSelectElement>(`keymap`)!;
element.querySelector<HTMLOptionElement>(`option[value='${config.keymap}']`)!.selected = true;
}
}

+ 136
- 0
src/ui/settings/index.html 파일 보기

@ -0,0 +1,136 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src *; style-src 'self'; script-src 'nonce-gitlens'"> -->
</head>
<body>
<div class="container">
<div class="content">
<header>
<div class="header__logo">
<img class="image__logo" src="{{root}}/images/gitlens-icon.png">
<div>
<h1>GitLens</h1>
<p class="header__subtitle">Git supercharged</p>
</div>
</div>
<p class="header__blurb">
GitLens <b>supercharges</b> the Git capabilities built into Visual Studio Code. It helps you to <b>visualize code authorship</b> at a glance via Git blame annotations and code lens, <b>seamlessly navigate and explore</b> Git repositories, <b>gain valuable insights</b> via powerful comparison commands, and so much more.
</p>
</header>
<section>
<div class="section__header">
<h2 class="section__title">Line Annotations <a title="Learn more" href="https://github.com/eamodio/vscode-gitlens#git-blame-annotations"><i class="icon icon__info"></i></a></h2>
<p class="section__title-hint">Adds an unobtrusive Git blame annotation to the end of the current line</p>
</div>
<div class="section__settings">
<div class="settings-group">
<div class="settings-group__setting">
<input id="blame.line.enabled" name="blame.line.enabled" type="checkbox"></input>
<label for="blame.line.enabled">Show Git blame annotations for the current line</label>
<select id="blame.line.annotationType" name="blame.line.annotationType" data-readonly="blame.line.enabled" disabled>
<option value="trailing">at the end of the line</option>
<option value="hover">on hover</option>
</select>
</div>
</div>
<div class="section__preview">
<img class="image__preview" src="{{root}}/images/screenshot-line-blame-annotation.png"></img>
</div>
</div>
</section>
<section>
<div class="section__header">
<h2 class="section__title">Code Lens <a title="Learn more" href="https://github.com/eamodio/vscode-gitlens#git-code-lens"><i class="icon icon__info"></i></a></h2>
<p class="section__title-hint">Adds Git authorship code lens to the top of the file and on code blocks</p>
</div>
<p></p>
<div class="section__settings">
<div class="settings-group">
<div class="settings-group__setting">
<input id="codeLens.enabled" name="codeLens.enabled" type="checkbox"></input>
<label for="codeLens.enabled">Show Git Code Lens</label>
</div>
</div>
<div class="section__preview">
<img class="image__preview" src="{{root}}/images/screenshot-code-lens.png"></img>
</div>
</div>
</section>
<section>
<div class="section__header">
<h2 class="section__title">Status Bar <a title="Learn more" href="https://github.com/eamodio/vscode-gitlens#git-blame-annotations"><i class="icon icon__info"></i></a></h2>
<p class="section__title-hint">Adds Git blame information about the current line to the status bar</p>
</div>
<div class="section__settings">
<div class="settings-group">
<div class="settings-group__setting">
<input id="statusBar.enabled" name="statusBar.enabled" type="checkbox"></input>
<label for="statusBar.enabled">Show Git blame information in the status bar</label>
</div>
</div>
<div class="section__preview">
<img class="image__preview" src="{{root}}/images/screenshot-status-bar.png"></img>
</div>
</div>
</section>
<section>
<div class="section__header">
<h2 class="section__title">GitLens Explorer <a title="Learn more" href="https://github.com/eamodio/vscode-gitlens#navigate-and-explore"><i class="icon icon__info"></i></a></h2>
<p class="section__title-hint">Adds a GitLens view to the Explorer activity to explore repositories or file histories</p>
</div>
<p></p>
<div class="section__settings">
<div class="settings-group">
<div class="settings-group__setting">
<input id="gitExplorer.enabled" name="gitExplorer.enabled" type="checkbox"></input>
<label for="gitExplorer.enabled">Show the GitLens explorer</label>
</div>
<div class="settings-group__setting">
<label for="gitExplorer.view">Start the GitLens explorer in</label>
<select id="gitExplorer.view" name="gitExplorer.view">
<option value="auto">the last selected view</option>
<option value="repository">repository view</option>
<option value="history">file history view</option>
</select>
<!-- <label class="label__hint" for="gitExplorer.view">Search for <b><i>gitlens</i></b> in the <a title="Open Keyboard Shortcuts" href="command:workbench.action.openGlobalKeybindings">Keyboard Shortcuts</a> editor to see the shortcuts and to customize them further</label> -->
</div>
</div>
<div class="section__preview">
<img class="image__preview" src="{{root}}/images/screenshot-git-custom-view-repository.png"></img>
</div>
</div>
</section>
<section>
<div class="section__header">
<h2 class="section__title">Keyboard Shortcuts</h2>
</div>
<div class="section__settings">
<div class="settings-group">
<label for="keymap">Choose which set of keyboard shortcuts to use:</label>
<select id="keymap" name="keymap">
<option value="standard">standard shortcuts (<code>Alt</code> based)</option>
<option value="chorded">chorded shortcuts (<code>Ctrl+Alt+G`</code> based)</option>
<option value="none">no shortcuts</option>
</select>
<label class="label__hint" for="keymap">Search for <b><i>gitlens</i></b> in the <a title="Open Keyboard Shortcuts" href="command:workbench.action.openGlobalKeybindings">Keyboard Shortcuts</a> editor to see the shortcuts and to customize them further</label>
</div>
</div>
</section>
</div>
</div>
<a id="commandRelay" style="display: none"></a>
<script type="text/javascript">
window.gitlens = { config: '{{config}}' };
</script>
</body>
</html>

+ 4
- 0
src/ui/settings/index.ts 파일 보기

@ -0,0 +1,4 @@
'use strict';
import { App } from './app';
new App();

+ 95
- 0
src/ui/shared/colors.ts 파일 보기

@ -0,0 +1,95 @@
const cssColorRegEx = /^(?:(#?)([0-9a-f]{3}|[0-9a-f]{6})|((?:rgb|hsl)a?)\((-?\d+%?)[,\s]+(-?\d+%?)[,\s]+(-?\d+%?)[,\s]*(-?[\d\.]+%?)?\))$/i;
function adjustLight(color: number, amount: number) {
const cc = color + amount;
const c = amount < 0
? cc < 0 ? 0 : cc
: cc > 255 ? 255 : cc;
const hex = Math.round(c).toString(16);
return hex.length > 1 ? hex : `0${hex}`;
}
export function darken(color: string, percentage: number) {
return lighten(color, -percentage);
}
export function lighten(color: string, percentage: number) {
const rgb = toRgb(color);
if (rgb == null) return color;
const [r, g, b] = rgb;
percentage = (255 * percentage) / 100;
return `#${adjustLight(r, percentage)}${adjustLight(g, percentage)}${adjustLight(b, percentage)}`;
}
export function initializeColorPalette() {
const onColorThemeChanged = () => {
const body = document.body;
const computedStyle = getComputedStyle(body);
const bodyStyle = body.style;
let color = computedStyle.getPropertyValue('--color').trim();
const rgb = toRgb(color);
if (rgb != null) {
const [r, g, b] = rgb;
bodyStyle.setProperty('--color--75', `rgba(${r}, ${g}, ${b}, 0.75)`);
bodyStyle.setProperty('--color--50', `rgba(${r}, ${g}, ${b}, 0.5)`);
}
color = computedStyle.getPropertyValue('--background-color').trim();
bodyStyle.setProperty('--background-color--lighten-05', lighten(color, 5));
bodyStyle.setProperty('--background-color--darken-05', darken(color, 5));
bodyStyle.setProperty('--background-color--lighten-075', lighten(color, 7.5));
bodyStyle.setProperty('--background-color--darken-075', darken(color, 7.5));
bodyStyle.setProperty('--background-color--lighten-15', lighten(color, 15));
bodyStyle.setProperty('--background-color--darken-15', darken(color, 15));
bodyStyle.setProperty('--background-color--lighten-30', lighten(color, 30));
bodyStyle.setProperty('--background-color--darken-30', darken(color, 30));
};
const observer = new MutationObserver(onColorThemeChanged);
observer.observe(document.body, { attributes: true, attributeFilter: ['class'] });
onColorThemeChanged();
return observer;
}
export function toRgb(color: string) {
color = color.trim();
const result = cssColorRegEx.exec(color);
if (result == null) return null;
if (result[1] === '#') {
const hex = result[2];
switch (hex.length) {
case 3:
return [
parseInt(hex[0] + hex[0], 16),
parseInt(hex[1] + hex[1], 16),
parseInt(hex[2] + hex[2], 16)
];
case 6:
return [
parseInt(hex.substring(0, 2), 16),
parseInt(hex.substring(2, 4), 16),
parseInt(hex.substring(4, 6), 16)
];
}
return null;
}
switch (result[3]) {
case 'rgb':
case 'rgba':
return [
parseInt(result[4], 10),
parseInt(result[5], 10),
parseInt(result[6], 10)
];
default:
return null;
}
}

+ 44
- 0
src/ui/shared/dom.ts 파일 보기

@ -0,0 +1,44 @@
'use strict';
export namespace DOM {
export function getElementById<T extends HTMLElement>(id: string): T {
return document.getElementById(id) as T;
}
// export function query<T extends HTMLElement>(selectors: string): T;
// export function query<T extends HTMLElement>(element: HTMLElement, selectors: string): T;
// export function query<T extends HTMLElement>(elementOrselectors: string | HTMLElement, selectors?: string): T {
// let element: Document | HTMLElement;
// if (typeof elementOrselectors === 'string') {
// element = document;
// selectors = elementOrselectors;
// }
// else {
// element = elementOrselectors;
// }
// return element.querySelector(selectors) as T;
// }
// export function queryAll<T extends Element>(selectors: string): T;
// export function queryAll<T extends Element>(element: HTMLElement, selectors: string): T;
// export function queryAll<T extends Element>(elementOrselectors: string | HTMLElement, selectors?: string): T {
// let element: Document | HTMLElement;
// if (typeof elementOrselectors === 'string') {
// element = document;
// selectors = elementOrselectors;
// }
// else {
// element = elementOrselectors;
// }
// return element.querySelectorAll(selectors) as NodeList<T>;
// }
export function listenAll(selector: string, name: string, listener: EventListenerOrEventListenerObject) {
const els = document.querySelectorAll(selector);
for (const el of els) {
el.addEventListener(name, listener, false);
}
}
}

+ 23
- 0
src/ui/tsconfig.json 파일 보기

@ -0,0 +1,23 @@
{
"version": "2.0.0",
"compileOnSave": false,
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"lib": [ "es5", "dom", "dom.iterable", "es2015", "es2015.iterable", "es2016" ],
"module": "es2015",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "out",
"removeComments": true,
"rootDir": ".",
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "es2016"
},
"exclude": [
"node_modules"
]
}

+ 132
- 0
src/ui/webpack.config.js 파일 보기

@ -0,0 +1,132 @@
'use strict';
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = function(env, argv) {
if (env === undefined) {
env = {};
}
const minify = !!env.production;
const prefixCss = true;
const sourceMaps = !env.production;
const plugins = [
new webpack.optimize.ModuleConcatenationPlugin(),
new ExtractTextPlugin({
filename: 'main.css'
}),
new HtmlWebpackPlugin({
excludeAssets: [/.*\.main\.js/],
excludeChunks: ['welcome'],
template: 'settings/index.html',
filename: path.resolve(__dirname, '../..', 'settings.html'),
inject: true,
inlineSource: env.production ? '.(js|css)$' : undefined,
// inlineSource: '.(js|css)$',
minify: minify
? {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true
}
: false
}),
new HtmlWebpackPlugin({
excludeAssets: [/.*\.main\.js/],
excludeChunks: ['settings'],
template: 'welcome/index.html',
filename: path.resolve(__dirname, '../..', 'welcome.html'),
inject: true,
inlineSource: env.production ? '.(js|css)$' : undefined,
// inlineSource: '.(js|css)$',
minify: minify
? {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true
}
: false
}),
new HtmlWebpackInlineSourcePlugin(),
new UglifyJsPlugin({
parallel: true,
sourceMap: sourceMaps,
uglifyOptions: {
ecma: 5,
compress: minify,
mangle: minify,
output: {
beautify: !minify,
comments: false,
ecma: 5
},
sourceMap: sourceMaps,
}
})
];
return {
// This is ugly having main.scss on both bundles, but if it is added separately it will generate a js bundle :(
entry: {
settings: ['./settings/index.ts', './scss/main.scss'],
welcome: ['./welcome/index.ts', './scss/main.scss']
// main: ['./scss/main.scss']
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../../', 'out/ui'),
publicPath: '{{root}}/out/ui/'
},
resolve: {
extensions: ['.ts', '.js'],
modules: [path.resolve(__dirname), 'node_modules']
},
devtool: sourceMaps ? 'inline-source-map' : false,
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
minimize: minify,
sourceMap: sourceMaps,
url: false
}
},
{
loader: 'sass-loader',
options: {
sourceMap: sourceMaps
}
}
]
}),
exclude: /node_modules/
}
]
},
plugins: plugins
};
};

+ 32
- 0
src/ui/welcome/app.ts 파일 보기

@ -0,0 +1,32 @@
'use strict';
import { DOM } from './../shared/dom';
import { initializeColorPalette } from '../shared/colors';
export class App {
private readonly _commandRelay: HTMLAnchorElement;
constructor() {
console.log('WelcomeApp.ctor');
this._commandRelay = DOM.getElementById<HTMLAnchorElement>('commandRelay');
initializeColorPalette();
const onClicked = this.onClicked.bind(this);
DOM.listenAll('button[data-href]', 'click', function(this: HTMLButtonElement) { onClicked(this); });
}
private onClicked(element: HTMLButtonElement) {
this.executeCommand(element.dataset.href);
}
private executeCommand(command: string | undefined) {
if (command === undefined) return;
console.log(`WelcomeApp.executeCommand: command=${command}`);
this._commandRelay.setAttribute('href', command);
this._commandRelay.click();
}
}

+ 85
- 0
src/ui/welcome/index.html 파일 보기

@ -0,0 +1,85 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src *; style-src 'self'; script-src 'nonce-gitlens'"> -->
</head>
<body>
<div class="container">
<div class="content">
<header>
<div class="header__logo">
<img class="image__logo" src="{{root}}/images/gitlens-icon.png">
<div>
<h1>GitLens</h1>
<p class="header__subtitle">Git supercharged</p>
</div>
</div>
<p class="header__blurb">
GitLens <b>supercharges</b> the Git capabilities built into Visual Studio Code. It helps you to <b>visualize code authorship</b> at a glance via Git blame annotations and code lens, <b>seamlessly navigate and explore</b> Git repositories, <b>gain valuable insights</b> via powerful comparison commands, and so much more.
</p>
</header>
<div class="section-groups">
<div class="section-group__main">
<div class="section__welcome">
<h2>Welcome</h2>
<p>
Thank you for taking the time to try GitLens!
<br />
GitLens is powerful, feature rich, and highly configurable, so please be sure to open the <a title="Open GitLens Settings" href="command:gitlens.showSettingsPage">GitLens settings page</a> to tailor it to suit your needs.
</p>
</div>
<div class="section__customize">
<h2>Customize</h2>
<ul>
<li><button class="list-button" data-href="command:gitlens.showSettingsPage"><h3>Open GitLens Settings</h3><span class="detail">Customize common GitLens settings in an easy to use editor</span></button></li>
<li><button class="list-button" data-href="command:workbench.action.openGlobalSettings"><h3>Open User Settings</h3> <span class="detail">Search for <b><i>gitlens</i></b> to see and customize all GitLens settings</span></button></li>
<li><button class="list-button" data-href="command:workbench.action.openGlobalKeybindings"><h3>Open Keyboard Shortcuts</h3> <span class="detail">Search for <b><i>gitlens</i></b> to see and customize GitLens keyboard shortcuts</span></button></li>
</ul>
</div>
<div class="section__learn">
<h2>Learn</h2>
<ul>
<li class="showCommands"><button class="list-button" data-href="command:workbench.action.showCommands"><h3>Find and run all GitLens commands</h3><span class="detail">Search for <b><i>gitlens</i></b> to access and search for GitLens commands from the Command Palette</span></button></li>
</ul>
</div>
</div>
<div class="section-group__sidebar">
<div class="sidebar-group sidebar-group__show-support">
<h2>Show Your Support</h2>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#review-details">Write a Review</a></li>
<li><a href="https://github.com/eamodio/vscode-gitlens">Star or Fork me on GitHub</a></li>
<li><a href="https://twitter.com/eamodio">Follow me on Twitter</a></li>
<!-- <li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#review-details">Become a Patron</a></li> -->
<li><a href="http://amod.io">Hire me</a></li>
</ul>
</div>
<div class="sidebar-group sidebar-group__help">
<h2>Help</h2>
<ul>
<li><a href="https://github.com/eamodio/vscode-gitlens/blob/master/README.md">Documentation</a></li>
<li><a href="https://github.com/eamodio/vscode-gitlens/issues">Questions &amp; Issues</a></li>
<li><a href="https://join.slack.com/t/vscode-dev-community/shared_invite/enQtMjIxOTgxNDE3NzM0LWU5M2ZiZDU1YjBlMzdlZjA2YjBjYzRhYTM5NTgzMTAxMjdiNWU0ZmQzYWI3MWU5N2Q1YjBiYmQ4MzY0NDE1MzY">Slack</a><small> &nbsp;&nbsp;&mdash;&nbsp; #gitlens channel</small></li>
<li><a href="https://twitter.com/eamodio">Twitter</a><small> &nbsp;&nbsp;&mdash;&nbsp; #gitlens hashtag</small></li>
</ul>
</div>
<div class="sidebar-group sidebar-group__resources">
<h2>Resources</h2>
<ul>
<li><a href="https://marketplace.visualstudio.com/items/eamodio.gitlens/changelog">Changelog</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">Marketplace</a></li>
<li><a href="https://github.com/eamodio/vscode-gitlens">GitHub</a></li>
<li><a href="https://marketplace.visualstudio.com/items/eamodio.gitlens/license">License</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<a id="commandRelay" style="display: none"></a>
</body>
</html>

+ 4
- 0
src/ui/welcome/index.ts 파일 보기

@ -0,0 +1,4 @@
'use strict';
import { App } from './app';
new App();

+ 2
- 1
tsconfig.json 파일 보기

@ -19,6 +19,7 @@
"exclude": [
"node_modules",
"test",
".vscode-test"
".vscode-test",
"src/ui",
]
}

불러오는 중...
취소
저장