@ -1,2 +1,4 @@ | |||
out | |||
node_modules | |||
node_modules | |||
settings.html | |||
welcome.html |
@ -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> |
@ -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'); | |||
} | |||
} |
@ -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" | |||
} | |||
} |
@ -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; | |||
} |
@ -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; | |||
} | |||
} |
@ -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> |
@ -0,0 +1,4 @@ | |||
'use strict'; | |||
import { App } from './app'; | |||
new App(); |
@ -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; | |||
} | |||
} |
@ -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); | |||
} | |||
} | |||
} |
@ -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" | |||
] | |||
} |
@ -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 | |||
}; | |||
}; |
@ -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(); | |||
} | |||
} |
@ -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 & Issues</a></li> | |||
<li><a href="https://join.slack.com/t/vscode-dev-community/shared_invite/enQtMjIxOTgxNDE3NzM0LWU5M2ZiZDU1YjBlMzdlZjA2YjBjYzRhYTM5NTgzMTAxMjdiNWU0ZmQzYWI3MWU5N2Q1YjBiYmQ4MzY0NDE1MzY">Slack</a><small> — #gitlens channel</small></li> | |||
<li><a href="https://twitter.com/eamodio">Twitter</a><small> — #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> |
@ -0,0 +1,4 @@ | |||
'use strict'; | |||
import { App } from './app'; | |||
new App(); |