Feat/generator 4 iteration (#400)

* chore: move env into src for better build

* chore: removed unused things from webviews

* feat: a better "defaults" - material-theme.config.json

* chore: fix paths for scripts

* feat: new folder "core" with managers

* chore: cleanup all useless things

* chore: update messages to be messages

* refactor: new setAccent command and better material.theme.config entry
This commit is contained in:
Alessio Occhipinti 2019-12-26 11:30:46 +01:00 committed by Mattia Astorino
parent 1ddcebf4c0
commit 72a12df8e1
38 changed files with 422 additions and 502 deletions

1
.gitignore vendored
View file

@ -8,3 +8,4 @@ node_modules/
/ui/ /ui/
build build
dist dist
user.material-theme.config.json

5
env.ts
View file

@ -1,5 +0,0 @@
import * as path from 'path';
export const SRC_FOLDER_PATH = path.resolve('./src');
export const BUILD_FOLDER_PATH = path.resolve('./build');
export const TS_BUILD_FOLDER_PATH = path.resolve('./dist');

109
material-theme.config.json Normal file
View file

@ -0,0 +1,109 @@
{
"accents": {
"Acid Lime": "#C6FF00",
"Blue": "#2979FF",
"Breaking Bad": "#388E3C",
"Bright Teal": "#64FFDA",
"Cyan": "#00BCD4",
"Graphite": "#616161",
"Indigo": "#5C6BC0",
"Lime": "#7CB342",
"Orange": "#FF7042",
"Pink": "#FF4081",
"Purple": "#AB47BC",
"Red": "#E57373",
"Sky": "#84FFFF",
"Tomato": "#F44336",
"Teal": "#80CBC4",
"Yellow": "#FFA000"
},
"accentsProperties": {
"activityBarBadge.background": {
"alpha": 100,
"value": null
},
"list.activeSelectionForeground": {
"alpha": 100,
"value": null
},
"list.inactiveSelectionForeground": {
"alpha": 100,
"value": null
},
"list.highlightForeground": {
"alpha": 100,
"value": null
},
"scrollbarSlider.activeBackground": {
"alpha": 50,
"value": null
},
"editorSuggestWidget.highlightForeground": {
"alpha": 100,
"value": null
},
"textLink.foreground": {
"alpha": 100,
"value": null
},
"progressBar.background": {
"alpha": 100,
"value": null
},
"pickerGroup.foreground": {
"alpha": 100,
"value": null
},
"tab.activeBorder": {
"alpha": 100,
"value": null
},
"notificationLink.foreground": {
"alpha": 100,
"value": null
},
"editorWidget.resizeBorder": {
"alpha": 100,
"value": null
},
"editorWidget.border": {
"alpha": 100,
"value": null
},
"settings.modifiedItemIndicator": {
"alpha": 100,
"value": null
},
"settings.headerForeground": {
"alpha": 100,
"value": null
},
"panelTitle.activeBorder": {
"alpha": 100,
"value": null
},
"breadcrumb.activeSelectionForeground": {
"alpha": 100,
"value": null
},
"menu.selectionForeground": {
"alpha": 100,
"value": null
},
"menubar.selectionForeground": {
"alpha": 100,
"value": null
},
"editor.findMatchBorder": {
"alpha": 100,
"value": null
},
"selection.background": {
"alpha": 40,
"value": null
}
},
"changelog": {
"lastversion": "30.0.0"
}
}

View file

@ -21,7 +21,7 @@
}, },
"engines": { "engines": {
"node": "<=10", "node": "<=10",
"vscode": ">=1.39.0" "vscode": ">=1.1.36"
}, },
"scripts": { "scripts": {
"build": "yarn cleanup && yarn build:ts && yarn build:generate-themes && yarn build:ui", "build": "yarn cleanup && yarn build:ts && yarn build:generate-themes && yarn build:ui",
@ -29,7 +29,7 @@
"lint": "eslint .", "lint": "eslint .",
"build:ui": "node dist/scripts/ui/index.js", "build:ui": "node dist/scripts/ui/index.js",
"build:generate-themes": "node dist/scripts/generator/index.js", "build:generate-themes": "node dist/scripts/generator/index.js",
"build:ts": "tsc -p ./tsconfig.json && ncp dist/src/ build", "build:ts": "tsc -p ./tsconfig.json && ncp dist/src/ build && ncp material-theme.config.json build",
"postinstall": "node ./node_modules/vscode/bin/install && opencollective postinstall && tsc -p tsconfig.json" "postinstall": "node ./node_modules/vscode/bin/install && opencollective postinstall && tsc -p tsconfig.json"
}, },
"categories": [ "categories": [

View file

@ -4,7 +4,7 @@ import * as path from 'path';
import {generateTheme} from '@moxer/vscode-theme-generator'; import {generateTheme} from '@moxer/vscode-theme-generator';
import {ThemeSetting} from './types'; import {ThemeSetting} from './types';
import {getColorSet} from './color-set'; import {getColorSet} from './color-set';
import {BUILD_FOLDER_PATH} from '../../env'; import {BUILD_FOLDER_PATH} from '../../src/env';
const THEME_BUILD_PATH = path.join(BUILD_FOLDER_PATH, 'themes'); const THEME_BUILD_PATH = path.join(BUILD_FOLDER_PATH, 'themes');
const themes = ['default', 'darker', 'lighter', 'ocean', 'palenight']; const themes = ['default', 'darker', 'lighter', 'ocean', 'palenight'];

View file

@ -2,7 +2,7 @@ import * as fs from 'fs-extra';
import * as path from 'path'; import * as path from 'path';
import browserify from 'browserify'; import browserify from 'browserify';
import {BUILD_FOLDER_PATH, SRC_FOLDER_PATH, TS_BUILD_FOLDER_PATH} from '../../env'; import {BUILD_FOLDER_PATH, SRC_FOLDER_PATH, TS_BUILD_FOLDER_PATH} from '../../src/env';
const UI_FOLDER_PATH = path.join(SRC_FOLDER_PATH, 'webviews', 'ui'); const UI_FOLDER_PATH = path.join(SRC_FOLDER_PATH, 'webviews', 'ui');
const UI_JS_FOLDER_PATH = path.join(TS_BUILD_FOLDER_PATH, 'src', 'webviews', 'ui'); const UI_JS_FOLDER_PATH = path.join(TS_BUILD_FOLDER_PATH, 'src', 'webviews', 'ui');
@ -14,7 +14,7 @@ const copyStatics = async (): Promise<void[]> => {
dest: path.join(UI_FOLDER_BUILD_PATH, 'release-notes.html') dest: path.join(UI_FOLDER_BUILD_PATH, 'release-notes.html')
}, { }, {
src: path.join(UI_FOLDER_PATH, 'release-notes', 'style.css'), src: path.join(UI_FOLDER_PATH, 'release-notes', 'style.css'),
dest: path.join(UI_FOLDER_BUILD_PATH, 'style.css') dest: path.join(UI_FOLDER_BUILD_PATH, 'release-notes.css')
}]; }];
return Promise.all(paths.map(async path => fs.copyFile(path.src, path.dest))); return Promise.all(paths.map(async path => fs.copyFile(path.src, path.dest)));

View file

@ -1,3 +0,0 @@
export default {
PURGE_KEY: 'Remove accents'
};

View file

@ -1,67 +0,0 @@
import * as vscode from 'vscode';
import {getDefaultValues, getAccentsProperties} from './../../helpers/fs';
import consts from './consts';
const REGEXP_HEX: RegExp = /^#([0-9A-F]{6}|[0-9A-F]{8})$/i;
/**
* Assigns colours
*/
const assignColorCustomizations = (colour: string): Object => {
const accentsProperties = getAccentsProperties();
const newColour = isValidColour(colour) ? colour : undefined;
return Object.keys(accentsProperties).reduce((acc: any, propName) => {
const accent = accentsProperties[propName];
let colorProp = newColour;
if (colour && accent.alpha < 100) {
colorProp = `${ colour }${ accent.alpha > 10 ? accent.alpha : `0${ accent.alpha }` }`;
}
acc[propName] = colorProp;
return acc;
}, {});
};
/**
* Determines if a string is a valid colour
*/
const isValidColour = (colour: string | null | undefined): boolean =>
typeof colour === 'string' && REGEXP_HEX.test(colour);
/**
* Sets workbench options
*/
const setWorkbenchOptions = (config: any): Thenable<boolean> =>
vscode.workspace.getConfiguration().update('workbench.colorCustomizations', config, true)
.then(() => true, reason => vscode.window.showErrorMessage(reason));
/**
* VSCode command
*/
export default async (accent?: string): Promise<boolean> => {
const themeConfigCommon = getDefaultValues();
const config: any = vscode.workspace.getConfiguration().get('workbench.colorCustomizations');
switch (accent) {
case consts.PURGE_KEY: {
const newConfig = {
...config,
...assignColorCustomizations(undefined)
};
return setWorkbenchOptions(newConfig)
.then(() => Promise.resolve(true));
}
default: {
const newConfig = {
...config,
...assignColorCustomizations(themeConfigCommon.accents[accent])
};
return setWorkbenchOptions(newConfig)
.then(() => Boolean(accent));
}
}
};

View file

@ -1,9 +0,0 @@
import * as vscode from 'vscode';
import {getDefaultValues} from '../../helpers/fs';
import consts from './consts';
export default async () => {
const themeConfigCommon = getDefaultValues();
const options: string[] = Object.keys(themeConfigCommon.accents).concat(consts.PURGE_KEY);
return vscode.window.showQuickPick(options);
};

View file

@ -1,2 +1 @@
export {default as accentsSetter} from './accents-setter'; export {command as setAccent} from './set-accent';
export {default as accentsQuickPick} from './accents-setter/quick-pick';

View file

@ -0,0 +1,55 @@
import {workspace, window} from 'vscode';
import {extensionManager} from '../core/extension-manager';
import {settingsManager} from '../core/settings-manager';
const PURGE_KEY = 'Remove accents';
const isValidColor = (color: string | null | undefined): boolean =>
color && /^#([0-9A-F]{6}|[0-9A-F]{8})$/i.test(color);
const getThemeColorCustomizationsConfig = (accentColor?: string): Record<string, unknown> => {
const {accentsProperties} = extensionManager.getConfig();
const color = isValidColor(accentColor) ? accentColor : undefined;
const themeColorCustomConfig = Object.keys(accentsProperties).reduce((acc: any, propName) => {
const currentProp = accentsProperties[propName];
const shouldModify = color && currentProp.alpha < 100;
const colorProp = shouldModify ? `${color}${currentProp.alpha > 10 ? currentProp.alpha : `0${currentProp.alpha}`}` : color;
acc[propName] = colorProp;
return acc;
}, {});
return themeColorCustomConfig;
};
const updateColorCustomizationsConfig = async (config: any): Promise<boolean> => {
try {
workspace.getConfiguration().update('workbench.colorCustomizations', config, true);
return true;
} catch (error) {
window.showErrorMessage(error);
}
};
const quickPick = async (): Promise<string> => {
const themeConfig = extensionManager.getConfig();
const options: string[] = Object.keys(themeConfig.accents).concat(PURGE_KEY);
return window.showQuickPick(options);
};
export const command = async (): Promise<void> => {
const themeConfig = extensionManager.getConfig();
const currentColorCustomizationsConfig: any = workspace.getConfiguration().get('workbench.colorCustomizations');
const accent = await quickPick();
const config = accent === PURGE_KEY ? {
...currentColorCustomizationsConfig,
...getThemeColorCustomizationsConfig()
} : {
...currentColorCustomizationsConfig,
...getThemeColorCustomizationsConfig(themeConfig.accents[accent])
};
await updateColorCustomizationsConfig(config);
await settingsManager.updateSetting('accent', accent);
};

View file

@ -1,4 +0,0 @@
/**
* File charset
*/
export const CHARSET: string = 'utf-8';

View file

@ -1,14 +0,0 @@
import * as path from 'path';
import {IPaths} from '../interfaces/ipaths';
export const PATHS: IPaths = {
SRC: './src',
THEMES: './out/themes',
UI: './out/ui',
VSIX_SRC_DIR: path.join(__dirname, '../..'), // From "src" dir
VSIX_DIR: path.join(__dirname, '../../..'), // From "out" dir
EXT_DIR: path.join(__dirname, '..')
};
export default PATHS;

View file

@ -0,0 +1,28 @@
import {window} from 'vscode';
import {MESSAGES} from '../helpers/messages';
type AskMessage = {
message: string;
options: {
ok: string;
cancel: string;
};
};
class ChangelogManager {
private readonly askMessage: AskMessage;
constructor(message: AskMessage) {
this.askMessage = message;
}
async askShowChangelog(): Promise<boolean> {
return await window.showInformationMessage(
this.askMessage.message,
this.askMessage.options.ok,
this.askMessage.options.cancel
) === this.askMessage.options.ok;
}
}
export const changelogManager = new ChangelogManager(MESSAGES.CHANGELOG);

View file

@ -0,0 +1,103 @@
import {extensions, workspace, window, Uri} from 'vscode';
import {posix} from 'path';
import {CONFIG_FILE_NAME, USER_CONFIG_FILE_NAME, MATERIAL_THEME_EXT_ID} from '../env';
type MaterialThemeConfig = {
accents: Record<string, string>;
accentsProperties: Record<string, {alpha: number; value: null }>;
changelog?: { lastversion?: string };
};
type InstallationType = {
firstInstall: boolean;
update: boolean;
};
export interface IExtensionManager {
getPackageJSON: () => Record<string, any>;
getConfig: () => MaterialThemeConfig;
getInstallationType: () => {};
updateConfig: (config: Partial<MaterialThemeConfig>) => Promise<void>;
}
class ExtensionManager implements IExtensionManager {
installationType: InstallationType;
private readonly configFileUri: Uri;
private readonly userConfigFileUri: Uri;
private configJSON: MaterialThemeConfig;
constructor() {
const extensionFolderUri = Uri.file(extensions.getExtension(MATERIAL_THEME_EXT_ID).extensionPath);
this.configFileUri = extensionFolderUri.with({path: posix.join(extensionFolderUri.path, CONFIG_FILE_NAME)});
this.userConfigFileUri = extensionFolderUri.with({path: posix.join(extensionFolderUri.path, USER_CONFIG_FILE_NAME)});
this.init();
}
getPackageJSON(): Record<string, any> {
return extensions.getExtension(MATERIAL_THEME_EXT_ID).packageJSON;
}
getConfig(): MaterialThemeConfig {
return this.configJSON;
}
getInstallationType(): InstallationType {
return this.installationType;
}
async updateConfig(config: Partial<MaterialThemeConfig>): Promise<void> {
const newConfig = {...this.configJSON, ...config};
await workspace.fs.writeFile(this.configFileUri, Buffer.from(JSON.stringify(newConfig), 'utf-8'));
}
private isVersionUpdate(userConfig: MaterialThemeConfig): boolean {
const splitVersion = (input: string): {major: number; minor: number; patch: number} => {
const [major, minor, patch] = input.split('.').map(i => parseInt(i, 10));
return {major, minor, patch};
};
const packageJSON = this.getPackageJSON();
const versionCurrent = splitVersion(packageJSON.version);
const versionOld = splitVersion(userConfig.changelog.lastversion);
const update = (
versionCurrent.major > versionOld.major ||
versionCurrent.minor > versionOld.minor ||
versionCurrent.patch > versionOld.patch
);
return update;
}
private async getUserConfig(): Promise<MaterialThemeConfig | undefined> {
try {
const configBuffer = await workspace.fs.readFile(this.userConfigFileUri);
const configContent = Buffer.from(configBuffer).toString('utf8');
return JSON.parse(configContent) as MaterialThemeConfig;
} catch {}
}
private async init(): Promise<void> {
try {
const userConfig = await this.getUserConfig();
this.installationType = {
update: userConfig && this.isVersionUpdate(userConfig),
firstInstall: !userConfig
};
const configBuffer = await workspace.fs.readFile(this.configFileUri);
const configContent = Buffer.from(configBuffer).toString('utf8');
await workspace.fs.writeFile(this.userConfigFileUri, configBuffer);
this.configJSON = JSON.parse(configContent) as MaterialThemeConfig;
} catch (error) {
this.configJSON = {accentsProperties: {}, accents: {}};
window
.showErrorMessage(`Material Theme: there was an error while loading the configuration. Please retry or open an issue: ${String(error)}`);
}
}
}
export const extensionManager = new ExtensionManager();

View file

@ -0,0 +1,28 @@
import {workspace} from 'vscode';
type ThemeCustomSettings = {
accent?: string;
};
export interface ISettingsManager {
getSettings: () => ThemeCustomSettings;
}
class SettingsManager implements ISettingsManager {
private readonly customSettings: ThemeCustomSettings;
constructor() {
this.customSettings = workspace.getConfiguration().get<ThemeCustomSettings>('materialTheme', {});
}
getSettings(): ThemeCustomSettings {
return this.customSettings;
}
async updateSetting(key: keyof ThemeCustomSettings, value: string): Promise<void> {
await workspace.getConfiguration().update(`materialTheme.${key}`, value, true);
}
}
export const settingsManager = new SettingsManager();

8
src/env.ts Normal file
View file

@ -0,0 +1,8 @@
import * as path from 'path';
export const SRC_FOLDER_PATH = path.resolve('./src');
export const BUILD_FOLDER_PATH = path.resolve('./build');
export const TS_BUILD_FOLDER_PATH = path.resolve('./dist');
export const CONFIG_FILE_NAME = 'material-theme.config.json';
export const USER_CONFIG_FILE_NAME = 'user.material-theme.config.json';
export const MATERIAL_THEME_EXT_ID = 'equinusocio.vsc-material-theme';

View file

@ -1,34 +0,0 @@
import {getDefaultValues, getPackageJSON} from './fs';
import {IInstallationType} from '../interfaces/iinstallation-type';
const splitVersion = (input: string): {major: number; minor: number; patch: number} => {
const [major, minor, patch] = input.split('.').map(i => parseInt(i, 10));
return {major, minor, patch};
};
export default (): IInstallationType => {
const out: IInstallationType = {
isUpdate: false,
isFirstInstall: false
};
const defaults = getDefaultValues();
const packageJSON = getPackageJSON();
const isFirstInstall = defaults.changelog === undefined ||
(defaults.changelog !== undefined && typeof defaults.changelog.lastversion !== 'string');
if (isFirstInstall) {
return {...out, isFirstInstall};
}
const versionCurrent = splitVersion(packageJSON.version);
const versionOld = isFirstInstall ? null : splitVersion(defaults.changelog.lastversion);
const isUpdate = !versionOld ||
versionCurrent.major > versionOld.major ||
versionCurrent.minor > versionOld.minor ||
versionCurrent.patch > versionOld.patch;
return {...out, isUpdate};
};

View file

@ -1,47 +0,0 @@
import * as fs from 'fs';
import * as path from 'path';
import {IPackageJSON} from '../interfaces/ipackage.json';
import {CHARSET} from './../consts/files';
import {IDefaults} from '../interfaces/idefaults';
import {PATHS} from '../consts/paths';
export function ensureDir(dirname: string): void {
if (!fs.existsSync(dirname)) {
fs.mkdirSync(dirname);
}
}
export function getDefaultValues(): IDefaults {
const defaults: IDefaults = require(path.join(PATHS.VSIX_DIR, 'defaults.json'));
if (defaults === undefined || defaults === null) {
throw new Error('Cannot find defaults params');
}
return defaults;
}
export function getAbsolutePath(input: string): string {
return path.join(PATHS.VSIX_DIR, input);
}
export function getAccentsProperties() {
return getDefaultValues().accentsProperties;
}
/**
* Gets package JSON
*/
export function getPackageJSON(): IPackageJSON {
return require(path.join(PATHS.VSIX_DIR, './package.json'));
}
/**
* Writes a file inside the vsix directory
*/
export function writeFile(filename: string, filecontent: string): void {
const filePath = path.join(PATHS.VSIX_DIR, filename);
fs.writeFileSync(filePath, filecontent, {encoding: CHARSET});
}

View file

@ -2,7 +2,7 @@ import {
window as Window window as Window
} from 'vscode'; } from 'vscode';
const MESSAGES = { export const MESSAGES = {
CHANGELOG: { CHANGELOG: {
message: 'Material Theme was updated. Check the release notes for more details.', message: 'Material Theme was updated. Check the release notes for more details.',
options: {ok: 'Show me', cancel: 'Maybe later'} options: {ok: 'Show me', cancel: 'Maybe later'}
@ -12,14 +12,7 @@ const MESSAGES = {
} }
}; };
export const changelogMessage = async () => export const installationMessage = async (): Promise<string> =>
await Window.showInformationMessage( Window.showInformationMessage(
MESSAGES.CHANGELOG.message,
MESSAGES.CHANGELOG.options.ok,
MESSAGES.CHANGELOG.options.cancel
) === MESSAGES.CHANGELOG.options.ok;
export const installationMessage = async () =>
await Window.showInformationMessage(
MESSAGES.INSTALLATION.message MESSAGES.INSTALLATION.message
); );

View file

@ -1,55 +0,0 @@
import * as vscode from 'vscode';
import {IDefaults} from './../interfaces/idefaults';
import {IThemeCustomSettings} from './../interfaces/itheme-custom-properties';
import {getPackageJSON} from './fs';
/**
* Gets saved accent
*/
export function getAccent(): string | undefined {
return getCustomSettings().accent;
}
/**
* Gets custom settings
*/
export function getCustomSettings(): IThemeCustomSettings {
return vscode.workspace.getConfiguration().get<IThemeCustomSettings>('materialTheme', {});
}
/**
* Get showReloadNotification
*/
export function isReloadNotificationEnable(): boolean {
return vscode.workspace.getConfiguration().get<boolean>('materialTheme.showReloadNotification');
}
/**
* Checks if a given string could be an accent
*/
export function isAccent(accentName: string, defaults: IDefaults): boolean {
return Boolean(Object.keys(defaults.accents).find(name => name === accentName));
}
/**
* Determines if the passing theme id is a material theme
*/
export function isMaterialTheme(themeName: string): boolean {
const packageJSON = getPackageJSON();
return Boolean(packageJSON.contributes.themes.find(contrib => contrib.label === themeName));
}
/**
* Sets a custom property in custom settings
*/
export function setCustomSetting(settingName: string, value: any): Thenable<string> {
return vscode.workspace.getConfiguration().update(`materialTheme.${settingName}`, value, true).then(() => settingName);
}
/**
* Updates accent name
*/
export function updateAccent(accentName: string): Thenable<string> {
return setCustomSetting('accent', accentName);
}

View file

@ -1,15 +0,0 @@
import * as vscode from 'vscode';
/**
* Gets your current theme ID
*/
export function getCurrentThemeID(): string {
return vscode.workspace.getConfiguration().get<string>('workbench.colorTheme');
}
/**
* Reloads current vscode window.
*/
export function reloadWindow(): void {
vscode.commands.executeCommand('workbench.action.reloadWindow');
}

View file

@ -1,16 +0,0 @@
import * as path from 'path';
import {getDefaultValues, getPackageJSON, writeFile} from './fs';
import {IDefaults} from '../interfaces/idefaults';
const writeDefaults = (defaults: IDefaults) =>
writeFile(path.join('./defaults.json'), JSON.stringify(defaults, null, 2));
export default (): void => {
const defaults = getDefaultValues();
const packageJSON = getPackageJSON();
const newChangelog = {...defaults.changelog, lastversion: packageJSON.version};
const newDefaults = {...defaults, changelog: newChangelog};
writeDefaults(newDefaults);
};

View file

@ -1,4 +0,0 @@
export interface IAccentCustomProperty {
alpha: number;
value: any;
}

View file

@ -1,35 +0,0 @@
import {IGenericObject} from './igeneric-object';
import {IAccentCustomProperty} from './iaccent-custom-property';
export interface IDefaults {
accents: IAccents;
accentsProperties: IGenericObject <IAccentCustomProperty>;
changelog: IChangelog;
themeVariants: IDefaultsThemeVariant;
themeVariantsColours: IDefaultsThemeVariant;
themeVariantsUITheme: IDefaultsThemeVariant;
[Symbol.iterator](): IterableIterator<IDefaults>;
}
export interface IAccents {
teal: string;
[index: string]: string;
}
export interface IChangelog {
lastversion: string;
[Symbol.iterator](): IterableIterator<IChangelog>;
}
export interface IDefaultsThemeVariant {
[index: string]: string;
Darker: string;
DarkerHighContrast: string;
Default: string;
DefaultHighContrast: string;
Light: string;
LightHighContrast: string;
PalenightHighContrast: string;
Ocean: string;
OceanHighContrast: string;
}

View file

@ -1,3 +0,0 @@
export interface IGenericObject<TValue> {
[index: string]: TValue;
}

View file

@ -1,4 +0,0 @@
export interface IInstallationType {
isUpdate: boolean;
isFirstInstall: boolean;
}

View file

@ -1,52 +0,0 @@
import {IGenericObject} from '../interfaces/igeneric-object';
export interface IPackageJSONBadge {
description: string;
href: string;
url: string;
}
export interface IPackageJSONContributes {
commands: IPackageJSONCommand[];
configuration: IPackageJSONConfiguration;
themes: IPackageJSONTheme[];
}
export interface IPackageJSONConfiguration {
properties: {};
}
export interface IPackageJSONCommand {
category: string;
command: string;
title: string;
}
export interface IPackageJSONTheme {
label: string;
path: string;
uiTheme: string;
}
export interface IPackageJSON {
activationEvents: string[];
badges: IPackageJSONBadge[];
contributes: IPackageJSONContributes;
bugs: IGenericObject<string>;
categories: string[];
description: string;
displayName: string;
engines: IGenericObject<string>;
galleryBanner: IGenericObject<string>;
homepage: string;
icon: string;
license: string;
main: string;
name: string;
preview: boolean;
publisher: string;
repository: IGenericObject<string>;
scripts: IGenericObject<string>;
version: string;
devDependencies: IGenericObject<string>;
}

View file

@ -1,23 +0,0 @@
export interface IPaths {
/**
* Src dir
*/
SRC: string;
/**
* Themes dir
*/
THEMES: string;
/**
* Extension directory
*/
VSIX_DIR: string;
VSIX_SRC_DIR: string;
/**
* Internal Extensions directory
*/
EXT_DIR: string;
/**
* UI directory
*/
UI: string;
}

View file

@ -1,3 +0,0 @@
export interface IThemeCustomSettings {
accent?: string;
}

View file

@ -4,33 +4,25 @@ import {
} from 'vscode'; } from 'vscode';
import * as ThemeCommands from './commands'; import * as ThemeCommands from './commands';
import {updateAccent} from './helpers/settings'; import {installationMessage} from './helpers/messages';
import {changelogMessage, installationMessage} from './helpers/messages';
import checkInstallation from './helpers/check-installation';
import writeChangelog from './helpers/write-changelog';
import {ReleaseNotesWebview} from './webviews/ReleaseNotes'; import {ReleaseNotesWebview} from './webviews/ReleaseNotes';
import {changelogManager} from './core/changelog-manager';
import {extensionManager} from './core/extension-manager';
export async function activate(context: ExtensionContext): Promise<void> { export async function activate(context: ExtensionContext): Promise<void> {
const installationType = checkInstallation();
const releaseNotesView = new ReleaseNotesWebview(context); const releaseNotesView = new ReleaseNotesWebview(context);
const installationType = extensionManager.getInstallationType();
writeChangelog(); // TODO: BEFORE RELEASE add new message for new install because with the refactor also updates will be considered as new install, for the first time
if (installationType.firstInstall) {
if (installationType.isFirstInstall) {
await installationMessage(); await installationMessage();
} }
const shouldShowChangelog = (installationType.isFirstInstall || installationType.isUpdate) && await changelogMessage(); if ((installationType.firstInstall || installationType.update) && await changelogManager.askShowChangelog()) {
if (shouldShowChangelog) { await releaseNotesView.show();
releaseNotesView.show();
} }
// Registering commands // Registering commands
Commands.registerCommand('materialTheme.setAccent', async () => { Commands.registerCommand('materialTheme.setAccent', ThemeCommands.setAccent);
const accentPicked = await ThemeCommands.accentsQuickPick();
await ThemeCommands.accentsSetter(accentPicked);
await updateAccent(accentPicked);
});
Commands.registerCommand('materialTheme.showReleaseNotes', async () => releaseNotesView.show()); Commands.registerCommand('materialTheme.showReleaseNotes', async () => releaseNotesView.show());
} }

View file

@ -1,44 +1,45 @@
import {WebviewController} from './Webview'; // WIP
import { // Import {WebviewController} from './Webview';
workspace as Workspace // import {
} from 'vscode'; // workspace as Workspace
import {ISettingsBootstrap} from './interfaces'; // } from 'vscode';
import {getCustomSettings} from '../helpers/settings'; // import {ISettingsBootstrap} from './interfaces';
import {getDefaultValues} from '../helpers/fs'; // import {getCustomSettings} from '../helpers/settings';
// import {getDefaultValues} from '../helpers/fs';
export class SettingsWebview extends WebviewController<ISettingsBootstrap> { // export class SettingsWebview extends WebviewController<ISettingsBootstrap> {
get filename(): string { // get filename(): string {
return 'settings.html'; // return 'settings.html';
} // }
get id(): string { // get id(): string {
return 'materialTheme.settings'; // return 'materialTheme.settings';
} // }
get title(): string { // get title(): string {
return 'Material Theme Settings'; // return 'Material Theme Settings';
} // }
/** // /**
* This will be called by the WebviewController when init the view // * This will be called by the WebviewController when init the view
* passing as `window.bootstrap` to the view. // * passing as `window.bootstrap` to the view.
*/ // */
getBootstrap(): ISettingsBootstrap { // getBootstrap(): ISettingsBootstrap {
return { // return {
config: getCustomSettings(), // config: getCustomSettings(),
defaults: getDefaultValues(), // defaults: getDefaultValues(),
scope: 'user', // scope: 'user',
scopes: this.getAvailableScopes() // scopes: this.getAvailableScopes()
}; // };
} // }
private getAvailableScopes(): Array<['user' | 'workspace', string]> { // private getAvailableScopes(): Array<['user' | 'workspace', string]> {
const scopes: Array<['user' | 'workspace', string]> = [['user', 'User']]; // const scopes: Array<['user' | 'workspace', string]> = [['user', 'User']];
return scopes // return scopes
.concat( // .concat(
Workspace.workspaceFolders?.length ? // Workspace.workspaceFolders?.length ?
['workspace', 'Workspace'] : // ['workspace', 'Workspace'] :
[] // []
); // );
} // }
} // }

View file

@ -12,8 +12,7 @@ import {
Uri Uri
} from 'vscode'; } from 'vscode';
import {getCustomSettings} from '../helpers/settings'; import {Invalidates, Message} from './interfaces';
import {Invalidates, Message, ISettingsChangedMessage} from './interfaces';
export abstract class WebviewController<TBootstrap> extends Disposable { export abstract class WebviewController<TBootstrap> extends Disposable {
private panel: WebviewPanel | undefined; private panel: WebviewPanel | undefined;
@ -38,7 +37,7 @@ export abstract class WebviewController<TBootstrap> extends Disposable {
const html = await this.getHtml(); const html = await this.getHtml();
const rootPath = Uri const rootPath = Uri
.file(this.context.asAbsolutePath('./out')) .file(this.context.asAbsolutePath('./build'))
.with({scheme: 'vscode-resource'}).toString(); .with({scheme: 'vscode-resource'}).toString();
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap` // Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
@ -93,32 +92,32 @@ export abstract class WebviewController<TBootstrap> extends Disposable {
private async getHtml(): Promise<string> { private async getHtml(): Promise<string> {
const doc = await Workspace const doc = await Workspace
.openTextDocument(this.context.asAbsolutePath(path.join('out/ui', this.filename))); .openTextDocument(this.context.asAbsolutePath(path.join('build/ui', this.filename)));
return doc.getText(); return doc.getText();
} }
private async postMessage(message: Message, invalidates: Invalidates = 'all'): Promise<boolean> { // Private async postMessage(message: Message, invalidates: Invalidates = 'all'): Promise<boolean> {
if (this.panel === undefined) { // if (this.panel === undefined) {
return false; // return false;
} // }
const result = await this.panel.webview.postMessage(message); // const result = await this.panel.webview.postMessage(message);
// If post was ok, update invalidateOnVisible if different than default // // If post was ok, update invalidateOnVisible if different than default
if (!result && this.invalidateOnVisible !== 'all') { // if (!result && this.invalidateOnVisible !== 'all') {
this.invalidateOnVisible = invalidates; // this.invalidateOnVisible = invalidates;
} // }
return result; // return result;
} // }
private async postUpdatedConfiguration(): Promise<boolean> { // Private async postUpdatedConfiguration(): Promise<boolean> {
// Post full raw configuration // // Post full raw configuration
return this.postMessage({ // return this.postMessage({
type: 'settingsChanged', // type: 'settingsChanged',
config: getCustomSettings() // config: getCustomSettings()
} as ISettingsChangedMessage, 'config'); // } as ISettingsChangedMessage, 'config');
} // }
private onPanelDisposed(): void { private onPanelDisposed(): void {
if (this.disposablePanel) { if (this.disposablePanel) {
@ -142,7 +141,8 @@ export abstract class WebviewController<TBootstrap> extends Disposable {
switch (invalidContext) { switch (invalidContext) {
case 'config': case 'config':
// Post the new configuration to the view // Post the new configuration to the view
return this.postUpdatedConfiguration(); // return this.postUpdatedConfiguration();
return;
default: default:
return this.show(); return this.show();
} }

View file

@ -1,6 +1,3 @@
import {IThemeCustomSettings} from '../interfaces/itheme-custom-properties';
import {IDefaults} from '../interfaces/idefaults';
export interface IChangeType { export interface IChangeType {
children: Array<{ children: Array<{
text: string; text: string;
@ -22,7 +19,7 @@ export interface IPostNormalized {
} }
export interface ISettingsChangedMessage { export interface ISettingsChangedMessage {
type: 'settingsChanged'; type: 'settingsChanged';
config: IThemeCustomSettings; config: {};
} }
export interface ISaveSettingsMessage { export interface ISaveSettingsMessage {
@ -39,13 +36,13 @@ export type Message = ISaveSettingsMessage | ISettingsChangedMessage;
export type Invalidates = 'all' | 'config' | undefined; export type Invalidates = 'all' | 'config' | undefined;
export interface IBootstrap { export interface IBootstrap {
config: IThemeCustomSettings; config: {};
} }
export interface ISettingsBootstrap extends IBootstrap { export interface ISettingsBootstrap extends IBootstrap {
scope: 'user' | 'workspace'; scope: 'user' | 'workspace';
scopes: Array<['user' | 'workspace', string]>; scopes: Array<['user' | 'workspace', string]>;
defaults: IDefaults; defaults: {};
} }
declare global { declare global {

View file

@ -1,4 +1,4 @@
import * as sanityClient from '@sanity/client'; import sanityClient from '@sanity/client';
import {IPost, IPostNormalized} from '../../interfaces'; import {IPost, IPostNormalized} from '../../interfaces';

View file

@ -1,11 +1,11 @@
import {ISettingsBootstrap} from '../../interfaces'; import {ISettingsBootstrap} from '../../interfaces';
import accentsSelector from './lib/accents-selector'; // Import accentsSelector from './lib/accents-selector';
const run = (): void => { const run = (): void => {
bind(); bind();
const {config, defaults} = window.bootstrap as ISettingsBootstrap; const {config, defaults} = window.bootstrap as ISettingsBootstrap;
accentsSelector('[data-setting="accentSelector"]', defaults.accents, config.accent); // AccentsSelector('[data-setting="accentSelector"]', defaults.accents, config.accent);
console.log(defaults); console.log(defaults);
console.log(config); console.log(config);

View file

@ -1,4 +1,4 @@
import {IAccents} from '../../../../interfaces/idefaults'; // Import {IAccents} from '../../../../interfaces/idefaults';
const templateSingleAccent = (accentName: string, accentColor: string): string => { const templateSingleAccent = (accentName: string, accentColor: string): string => {
const dashAccentName = accentName.toLowerCase().replace(/ /gi, '-'); const dashAccentName = accentName.toLowerCase().replace(/ /gi, '-');
@ -9,7 +9,7 @@ const templateSingleAccent = (accentName: string, accentColor: string): string =
`; `;
}; };
export default (containerSelector: string, accentsObject: IAccents, currentAccent: string): void => { export default (containerSelector: string, accentsObject: Record<string, string>, currentAccent: string): void => {
const container = document.querySelector(containerSelector); const container = document.querySelector(containerSelector);
for (const accentKey of Object.keys(accentsObject)) { for (const accentKey of Object.keys(accentsObject)) {

View file

@ -19,8 +19,7 @@
"./types", "./types",
"./src/**/*", "./src/**/*",
"./test/**/*", "./test/**/*",
"./scripts/**/*", "./scripts/**/*"
"./env.ts"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",