Compare commits
No commits in common. "main" and "theo/remove-potential-danger" have entirely different histories.
main
...
theo/remov
13 changed files with 3356 additions and 53 deletions
5
LICENSE
5
LICENSE
|
@ -186,10 +186,7 @@
|
||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright 2025 Theo Browne
|
Copyright 2024 Theo Browne
|
||||||
Copyright and license for original Material Theme project can be found at
|
|
||||||
|
|
||||||
https://github.com/Dramaga11/vsc-material-theme/blob/main/LICENSE
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
18
README.md
18
README.md
|
@ -1,9 +1,7 @@
|
||||||
|
|
||||||
# Material Theme (But I won't sue you)
|
# Material Theme (But I won't sue you)
|
||||||
|
|
||||||
> **Note:** The original Material Theme has been removed from the marketplace due to [distributing malware through their extensions](https://news.ycombinator.com/item?id=43181591). This fork has been thoroughly audited and is completely safe to use. I have personally audited every line, and removed a TON of unnecessary stuff to be sure. The VS Code team is auditing it as well just to be extra safe.
|
So, uh, the guy who made the VS Code Material Theme is threatening everyone who uses it in their products. He [seems to have forgotten it was originally licensed under the Apache License, 2.0.](https://github.com/Dramaga11/vsc-material-theme/blob/main/LICENSE). He wiped the commit history to make it look like it was always his weird fake license.
|
||||||
|
|
||||||
So, uh, the guy who made the VS Code Material Theme is threatening everyone who uses it in their products. He [seems to have forgotten it was originally licensed under the Apache License, 2.0.](https://github.com/Dramaga11/vsc-material-theme/blob/main/LICENSE). He wiped the commit history to make it look like it was always his weird fake license. Check out my [blog post for more info](https://t3.gg/blog/post/equinusocio).
|
|
||||||
|
|
||||||
What he has done is fraudulent and shameful. I have created this fork to maintain the original license and keep the project alive.
|
What he has done is fraudulent and shameful. I have created this fork to maintain the original license and keep the project alive.
|
||||||
|
|
||||||
|
@ -88,6 +86,20 @@ Learn how to customize every part of this theme by using Visual Studio Code API.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Official Portings
|
||||||
|
|
||||||
|
You can find all the official portings and resources [here](https://github.com/material-theme/vsc-material-theme/discussions/1279).
|
||||||
|
|
||||||
|
## Want to use the legacy version?
|
||||||
|
|
||||||
|
If you're looking for the deprecated Community Material Theme [you can find it here](https://github.com/material-theme/vsc-material-theme/discussions/1278). This version has been deprecated and removed from the official marketplace.
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
This project exists thanks to all the people who contribute. [[Contribute]](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
<p align="center"><a href="http://www.apache.org/licenses/LICENSE-2.0"><img src="https://img.shields.io/badge/License-Apache_2.0-5E81AC.svg?style=flat-square"/></a></p>
|
||||||
|
|
||||||
## Attribution
|
## Attribution
|
||||||
|
|
||||||
The code in this project was [previously hosted at this url](https://github.com/material-theme/vsc-material-theme), but the original author has wiped all history of it, making it incredibly hard to credit him and the other original contributors. Full credit has been preserved in the git history here to our best ability.
|
The code in this project was [previously hosted at this url](https://github.com/material-theme/vsc-material-theme), but the original author has wiped all history of it, making it incredibly hard to credit him and the other original contributors. Full credit has been preserved in the git history here to our best ability.
|
||||||
|
|
2975
package-lock.json
generated
2975
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -2,7 +2,7 @@
|
||||||
"name": "vsc-material-theme-but-i-wont-sue-you",
|
"name": "vsc-material-theme-but-i-wont-sue-you",
|
||||||
"displayName": "Material Theme (But I Won't Sue You)",
|
"displayName": "Material Theme (But I Won't Sue You)",
|
||||||
"description": "A Apache-2 licensed fork of Material Theme with no threats of legal action",
|
"description": "A Apache-2 licensed fork of Material Theme with no threats of legal action",
|
||||||
"version": "35.0.2",
|
"version": "35.0.0",
|
||||||
"publisher": "t3dotgg",
|
"publisher": "t3dotgg",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"author": "Theo",
|
"author": "Theo",
|
||||||
|
@ -23,15 +23,17 @@
|
||||||
"vscode": "^1.51.0"
|
"vscode": "^1.51.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "run-s cleanup build:ts build:generate-themes",
|
"build": "run-s cleanup build:ts build:generate-themes build:ui",
|
||||||
"cleanup": "rimraf build && rimraf dist",
|
"cleanup": "rimraf build && rimraf dist",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
|
"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 && ncp material-theme.config.json build",
|
"build:ts": "tsc -p ./tsconfig.json && ncp dist/src/ build && ncp material-theme.config.json build",
|
||||||
"postinstall": "node ./node_modules/vscode/bin/install && tsc -p tsconfig.json"
|
"postinstall": "node ./node_modules/vscode/bin/install && tsc -p tsconfig.json"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"Themes"
|
"Themes",
|
||||||
|
"Other"
|
||||||
],
|
],
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"VSCode",
|
"VSCode",
|
||||||
|
@ -173,7 +175,7 @@
|
||||||
"fs-extra": "9.0.1",
|
"fs-extra": "9.0.1",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
"npm-run-all": "4.1.5",
|
"npm-run-all": "4.1.5",
|
||||||
"rimraf": "3.0.2",
|
"standard-version": "9.5.0",
|
||||||
"typescript": "4.1.3",
|
"typescript": "4.1.3",
|
||||||
"vscode": "1.1.37"
|
"vscode": "1.1.37"
|
||||||
},
|
},
|
||||||
|
|
17
scripts/ui/index.ts
Normal file
17
scripts/ui/index.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import * as fs from 'fs-extra';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import {BUILD_FOLDER_PATH} from '../../src/env';
|
||||||
|
|
||||||
|
const UI_FOLDER_BUILD_PATH = path.join(BUILD_FOLDER_PATH, 'ui');
|
||||||
|
|
||||||
|
const run = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await fs.mkdirp(UI_FOLDER_BUILD_PATH);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('ERROR build:ui:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void run();
|
|
@ -17,10 +17,16 @@ type PackageJSON = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type InstallationType = {
|
||||||
|
firstInstall: boolean;
|
||||||
|
update: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export interface IExtensionManager {
|
export interface IExtensionManager {
|
||||||
init: (context: ExtensionContext) => Promise<void>;
|
init: (context: ExtensionContext) => Promise<void>;
|
||||||
getPackageJSON: () => PackageJSON;
|
getPackageJSON: () => PackageJSON;
|
||||||
getConfig: () => MaterialThemeConfig;
|
getConfig: () => MaterialThemeConfig;
|
||||||
|
getInstallationType: () => Record<string, unknown>;
|
||||||
updateConfig: (config: Partial<MaterialThemeConfig>) => Promise<void>;
|
updateConfig: (config: Partial<MaterialThemeConfig>) => Promise<void>;
|
||||||
VERSION_KEY: string;
|
VERSION_KEY: string;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +36,7 @@ class ExtensionManager implements IExtensionManager {
|
||||||
return 'vsc-material-theme.version';
|
return 'vsc-material-theme.version';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
installationType: InstallationType;
|
||||||
private readonly configFileUri: Uri;
|
private readonly configFileUri: Uri;
|
||||||
private readonly userConfigFileUri: Uri;
|
private readonly userConfigFileUri: Uri;
|
||||||
private configJSON: MaterialThemeConfig;
|
private configJSON: MaterialThemeConfig;
|
||||||
|
@ -48,6 +55,10 @@ class ExtensionManager implements IExtensionManager {
|
||||||
return this.configJSON;
|
return this.configJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getInstallationType(): InstallationType {
|
||||||
|
return this.installationType;
|
||||||
|
}
|
||||||
|
|
||||||
async updateConfig(config: Partial<MaterialThemeConfig>): Promise<void> {
|
async updateConfig(config: Partial<MaterialThemeConfig>): Promise<void> {
|
||||||
const newConfig = {...this.configJSON, ...config};
|
const newConfig = {...this.configJSON, ...config};
|
||||||
await workspace.fs.writeFile(this.configFileUri, Buffer.from(JSON.stringify(newConfig), 'utf-8'));
|
await workspace.fs.writeFile(this.configFileUri, Buffer.from(JSON.stringify(newConfig), 'utf-8'));
|
||||||
|
@ -56,27 +67,62 @@ class ExtensionManager implements IExtensionManager {
|
||||||
async init(context: ExtensionContext): Promise<void> {
|
async init(context: ExtensionContext): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const packageJSON = this.getPackageJSON();
|
const packageJSON = this.getPackageJSON();
|
||||||
|
const userConfig = await this.getUserConfig();
|
||||||
|
const mementoStateVersion = context.globalState.get(this.VERSION_KEY);
|
||||||
|
const themeNeverUsed = mementoStateVersion === undefined || typeof mementoStateVersion !== 'string';
|
||||||
|
|
||||||
|
this.installationType = {
|
||||||
|
update: userConfig && this.isVersionUpdate(userConfig, packageJSON),
|
||||||
|
firstInstall: !userConfig && themeNeverUsed
|
||||||
|
};
|
||||||
|
|
||||||
|
// Theme not used before across devices
|
||||||
|
if (themeNeverUsed) {
|
||||||
|
await context.globalState.update(this.VERSION_KEY, packageJSON.version);
|
||||||
|
}
|
||||||
|
|
||||||
// Load configuration
|
|
||||||
const configBuffer = await workspace.fs.readFile(this.configFileUri);
|
const configBuffer = await workspace.fs.readFile(this.configFileUri);
|
||||||
const configContent = Buffer.from(configBuffer).toString('utf8');
|
const configContent = Buffer.from(configBuffer).toString('utf8');
|
||||||
|
|
||||||
this.configJSON = JSON.parse(configContent) as MaterialThemeConfig;
|
this.configJSON = JSON.parse(configContent) as MaterialThemeConfig;
|
||||||
|
|
||||||
// Update version in user config
|
|
||||||
const userConfigUpdate = {...this.configJSON, changelog: {lastversion: packageJSON.version}};
|
const userConfigUpdate = {...this.configJSON, changelog: {lastversion: packageJSON.version}};
|
||||||
await workspace.fs.writeFile(
|
await workspace.fs.writeFile(
|
||||||
this.userConfigFileUri,
|
this.userConfigFileUri,
|
||||||
Buffer.from(JSON.stringify(userConfigUpdate), 'utf-8')
|
Buffer.from(JSON.stringify(userConfigUpdate), 'utf-8')
|
||||||
);
|
);
|
||||||
|
|
||||||
// Store version in global state
|
|
||||||
await context.globalState.update(this.VERSION_KEY, packageJSON.version);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.configJSON = {accentsProperties: {}, accents: {}};
|
this.configJSON = {accentsProperties: {}, accents: {}};
|
||||||
await window
|
await window
|
||||||
.showErrorMessage(`Material Theme: there was an error while loading the configuration. Please retry or open an issue: ${String(error)}`);
|
.showErrorMessage(`Material Theme: there was an error while loading the configuration. Please retry or open an issue: ${String(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isVersionUpdate(userConfig: MaterialThemeConfig, packageJSON: PackageJSON): 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 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 {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const extensionManager = new ExtensionManager();
|
export const extensionManager = new ExtensionManager();
|
||||||
|
|
45
src/webviews/Settings.ts
Normal file
45
src/webviews/Settings.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// WIP
|
||||||
|
// Import {WebviewController} from './Webview';
|
||||||
|
// import {
|
||||||
|
// workspace as Workspace
|
||||||
|
// } from 'vscode';
|
||||||
|
// import {ISettingsBootstrap} from './interfaces';
|
||||||
|
// import {getCustomSettings} from '../helpers/settings';
|
||||||
|
// import {getDefaultValues} from '../helpers/fs';
|
||||||
|
|
||||||
|
// export class SettingsWebview extends WebviewController<ISettingsBootstrap> {
|
||||||
|
// get filename(): string {
|
||||||
|
// return 'settings.html';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get id(): string {
|
||||||
|
// return 'materialTheme.settings';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get title(): string {
|
||||||
|
// return 'Material Theme Settings';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * This will be called by the WebviewController when init the view
|
||||||
|
// * passing as `window.bootstrap` to the view.
|
||||||
|
// */
|
||||||
|
// getBootstrap(): ISettingsBootstrap {
|
||||||
|
// return {
|
||||||
|
// config: getCustomSettings(),
|
||||||
|
// defaults: getDefaultValues(),
|
||||||
|
// scope: 'user',
|
||||||
|
// scopes: this.getAvailableScopes()
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private getAvailableScopes(): Array<['user' | 'workspace', string]> {
|
||||||
|
// const scopes: Array<['user' | 'workspace', string]> = [['user', 'User']];
|
||||||
|
// return scopes
|
||||||
|
// .concat(
|
||||||
|
// Workspace.workspaceFolders?.length ?
|
||||||
|
// ['workspace', 'Workspace'] :
|
||||||
|
// []
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
161
src/webviews/Webview.ts
Normal file
161
src/webviews/Webview.ts
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import {
|
||||||
|
workspace as Workspace,
|
||||||
|
|
||||||
|
Disposable,
|
||||||
|
ExtensionContext,
|
||||||
|
WebviewPanel,
|
||||||
|
ViewColumn,
|
||||||
|
window,
|
||||||
|
WebviewPanelOnDidChangeViewStateEvent,
|
||||||
|
Uri
|
||||||
|
} from 'vscode';
|
||||||
|
|
||||||
|
import {Invalidates, Message} from './interfaces';
|
||||||
|
|
||||||
|
export abstract class WebviewController<TBootstrap> extends Disposable {
|
||||||
|
private panel: WebviewPanel | undefined;
|
||||||
|
private disposablePanel: Disposable | undefined;
|
||||||
|
private invalidateOnVisible: Invalidates;
|
||||||
|
private readonly context: ExtensionContext;
|
||||||
|
|
||||||
|
constructor(context: ExtensionContext) {
|
||||||
|
// Applying dispose callback for our disposable function
|
||||||
|
super(() => this.dispose());
|
||||||
|
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
if (this.disposablePanel) {
|
||||||
|
this.disposablePanel.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async show(): Promise<void> {
|
||||||
|
const html = await this.getHtml();
|
||||||
|
|
||||||
|
// If panel already opened just reveal
|
||||||
|
if (this.panel !== undefined) {
|
||||||
|
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
|
||||||
|
const fullHtml = this.replaceInPanel(html);
|
||||||
|
this.panel.webview.html = fullHtml;
|
||||||
|
return this.panel.reveal(ViewColumn.Active);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.panel = window.createWebviewPanel(
|
||||||
|
this.id,
|
||||||
|
this.title,
|
||||||
|
ViewColumn.Active,
|
||||||
|
{
|
||||||
|
retainContextWhenHidden: true,
|
||||||
|
enableFindWidget: true,
|
||||||
|
enableCommandUris: true,
|
||||||
|
enableScripts: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Applying listeners
|
||||||
|
this.disposablePanel = Disposable.from(
|
||||||
|
this.panel,
|
||||||
|
this.panel.onDidDispose(this.onPanelDisposed, this),
|
||||||
|
this.panel.onDidChangeViewState(this.onViewStateChanged, this),
|
||||||
|
this.panel.webview.onDidReceiveMessage(this.onMessageReceived, this)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
|
||||||
|
const fullHtml = this.replaceInPanel(html);
|
||||||
|
|
||||||
|
this.panel.webview.html = fullHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onMessageReceived(event: Message): void {
|
||||||
|
if (event === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`WebviewEditor.onMessageReceived: type=${event.type}, data=${JSON.stringify(event)}`);
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case 'saveSettings':
|
||||||
|
// TODO: update settings
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private replaceInPanel(html: string): string {
|
||||||
|
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
|
||||||
|
const fullHtml = html
|
||||||
|
.replace(/{{root}}/g, this.panel.webview.asWebviewUri(Uri.file(this.context.asAbsolutePath('./build'))).toString())
|
||||||
|
.replace(/{{cspSource}}/g, this.panel.webview.cspSource)
|
||||||
|
.replace('\'{{bootstrap}}\'', JSON.stringify(this.getBootstrap()));
|
||||||
|
|
||||||
|
return fullHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getHtml(): Promise<string> {
|
||||||
|
const doc = await Workspace
|
||||||
|
.openTextDocument(this.context.asAbsolutePath(path.join('build/ui', this.filename)));
|
||||||
|
return doc.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private async postMessage(message: Message, invalidates: Invalidates = 'all'): Promise<boolean> {
|
||||||
|
// if (this.panel === undefined) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const result = await this.panel.webview.postMessage(message);
|
||||||
|
|
||||||
|
// // If post was ok, update invalidateOnVisible if different than default
|
||||||
|
// if (!result && this.invalidateOnVisible !== 'all') {
|
||||||
|
// this.invalidateOnVisible = invalidates;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Private async postUpdatedConfiguration(): Promise<boolean> {
|
||||||
|
// // Post full raw configuration
|
||||||
|
// return this.postMessage({
|
||||||
|
// type: 'settingsChanged',
|
||||||
|
// config: getCustomSettings()
|
||||||
|
// } as ISettingsChangedMessage, 'config');
|
||||||
|
// }
|
||||||
|
|
||||||
|
private onPanelDisposed(): void {
|
||||||
|
if (this.disposablePanel) {
|
||||||
|
this.disposablePanel.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.panel = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async onViewStateChanged(event: WebviewPanelOnDidChangeViewStateEvent): Promise<void> {
|
||||||
|
console.log('WebviewEditor.onViewStateChanged', event.webviewPanel.visible);
|
||||||
|
|
||||||
|
if (!this.invalidateOnVisible || !event.webviewPanel.visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the view since it can be outdated
|
||||||
|
const invalidContext = this.invalidateOnVisible;
|
||||||
|
this.invalidateOnVisible = undefined;
|
||||||
|
|
||||||
|
switch (invalidContext) {
|
||||||
|
case 'config':
|
||||||
|
// Post the new configuration to the view
|
||||||
|
// return this.postUpdatedConfiguration();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return this.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract get filename(): string;
|
||||||
|
abstract get id(): string;
|
||||||
|
abstract get title(): string;
|
||||||
|
abstract getBootstrap(): TBootstrap;
|
||||||
|
}
|
33
src/webviews/interfaces.ts
Normal file
33
src/webviews/interfaces.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
export interface ISettingsChangedMessage {
|
||||||
|
type: 'settingsChanged';
|
||||||
|
config: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISaveSettingsMessage {
|
||||||
|
type: 'saveSettings';
|
||||||
|
changes: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
removes: string[];
|
||||||
|
scope: 'user' | 'workspace';
|
||||||
|
uri: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Message = ISaveSettingsMessage | ISettingsChangedMessage;
|
||||||
|
export type Invalidates = 'all' | 'config' | undefined;
|
||||||
|
|
||||||
|
export interface IBootstrap {
|
||||||
|
config: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISettingsBootstrap extends IBootstrap {
|
||||||
|
scope: 'user' | 'workspace';
|
||||||
|
scopes: Array<['user' | 'workspace', string]>;
|
||||||
|
defaults: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
bootstrap: IBootstrap | ISettingsBootstrap | Record<string, unknown>;
|
||||||
|
}
|
||||||
|
}
|
20
src/webviews/ui/settings/index.ts
Normal file
20
src/webviews/ui/settings/index.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import {ISettingsBootstrap} from '../../interfaces';
|
||||||
|
// Import accentsSelector from './lib/accents-selector';
|
||||||
|
|
||||||
|
const run = (): void => {
|
||||||
|
bind();
|
||||||
|
|
||||||
|
const {config, defaults} = window.bootstrap as ISettingsBootstrap;
|
||||||
|
// AccentsSelector('[data-setting="accentSelector"]', defaults.accents, config.accent);
|
||||||
|
|
||||||
|
console.log(defaults);
|
||||||
|
console.log(config);
|
||||||
|
};
|
||||||
|
|
||||||
|
const bind = (): void => {
|
||||||
|
document.querySelector('#fixIconsCTA').addEventListener('click', () => {
|
||||||
|
console.log('Test click');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
run();
|
26
src/webviews/ui/settings/lib/accents-selector.ts
Normal file
26
src/webviews/ui/settings/lib/accents-selector.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Import {IAccents} from '../../../../interfaces/idefaults';
|
||||||
|
|
||||||
|
const templateSingleAccent = (accentName: string, accentColor: string): string => {
|
||||||
|
const dashAccentName = accentName.toLowerCase().replace(/ /gi, '-');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<label for="${dashAccentName}" data-color="${accentColor}">${accentName}</label>
|
||||||
|
<input type="radio" name="accents" id="${dashAccentName}" value="${dashAccentName}" />
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (containerSelector: string, accentsObject: Record<string, string>, currentAccent: string): void => {
|
||||||
|
const container = document.querySelector(containerSelector);
|
||||||
|
|
||||||
|
for (const accentKey of Object.keys(accentsObject)) {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.innerHTML = templateSingleAccent(accentKey, accentsObject[accentKey]);
|
||||||
|
|
||||||
|
if (accentKey === currentAccent) {
|
||||||
|
el.setAttribute('selected', 'true');
|
||||||
|
el.querySelector('input').setAttribute('checked', 'checked');
|
||||||
|
}
|
||||||
|
|
||||||
|
container.appendChild(el);
|
||||||
|
}
|
||||||
|
};
|
39
src/webviews/ui/settings/settings.html
Normal file
39
src/webviews/ui/settings/settings.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Material Theme Settings Editor</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{root}}/ui/settings/style.css">
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/@native-elements/native-elements/dist/native-elements.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Material Theme Settings Editor (preview)</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<button ne-button tabindex="2" autofocus>Button</button>
|
||||||
|
|
||||||
|
<div class="SettingsContainer">
|
||||||
|
<div>
|
||||||
|
<label>Fix file icons</label>
|
||||||
|
<input id="fixIconsCTA" type="submit" value="Fix">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="AccentsRadioContainer" data-setting="accentSelector">
|
||||||
|
<!-- Populated by js -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<input value="Example input">
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.bootstrap = '{{bootstrap}}';
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="{{root}}/ui/settings.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
4
src/webviews/ui/settings/style.css
Normal file
4
src/webviews/ui/settings/style.css
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.AccentsRadioContainer > div {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue