Compare commits
5 commits
theo/remov
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3993b87f3d | ||
![]() |
8e6057db6a | ||
![]() |
3bb59faf7f | ||
![]() |
1014de4096 | ||
![]() |
c83c3583a9 |
13 changed files with 53 additions and 3356 deletions
5
LICENSE
5
LICENSE
|
@ -186,7 +186,10 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2024 Theo Browne
|
||||
Copyright 2025 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");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
18
README.md
18
README.md
|
@ -1,7 +1,9 @@
|
|||
|
||||
# Material Theme (But I won't sue you)
|
||||
|
||||
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.
|
||||
> **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. 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.
|
||||
|
||||
|
@ -86,20 +88,6 @@ 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
|
||||
|
||||
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",
|
||||
"displayName": "Material Theme (But I Won't Sue You)",
|
||||
"description": "A Apache-2 licensed fork of Material Theme with no threats of legal action",
|
||||
"version": "35.0.0",
|
||||
"version": "35.0.2",
|
||||
"publisher": "t3dotgg",
|
||||
"license": "Apache-2.0",
|
||||
"author": "Theo",
|
||||
|
@ -23,17 +23,15 @@
|
|||
"vscode": "^1.51.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "run-s cleanup build:ts build:generate-themes build:ui",
|
||||
"build": "run-s cleanup build:ts build:generate-themes",
|
||||
"cleanup": "rimraf build && rimraf dist",
|
||||
"lint": "eslint .",
|
||||
"build:ui": "node dist/scripts/ui/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",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install && tsc -p tsconfig.json"
|
||||
},
|
||||
"categories": [
|
||||
"Themes",
|
||||
"Other"
|
||||
"Themes"
|
||||
],
|
||||
"keywords": [
|
||||
"VSCode",
|
||||
|
@ -175,7 +173,7 @@
|
|||
"fs-extra": "9.0.1",
|
||||
"ncp": "2.0.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"standard-version": "9.5.0",
|
||||
"rimraf": "3.0.2",
|
||||
"typescript": "4.1.3",
|
||||
"vscode": "1.1.37"
|
||||
},
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
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,16 +17,10 @@ type PackageJSON = {
|
|||
};
|
||||
};
|
||||
|
||||
type InstallationType = {
|
||||
firstInstall: boolean;
|
||||
update: boolean;
|
||||
};
|
||||
|
||||
export interface IExtensionManager {
|
||||
init: (context: ExtensionContext) => Promise<void>;
|
||||
getPackageJSON: () => PackageJSON;
|
||||
getConfig: () => MaterialThemeConfig;
|
||||
getInstallationType: () => Record<string, unknown>;
|
||||
updateConfig: (config: Partial<MaterialThemeConfig>) => Promise<void>;
|
||||
VERSION_KEY: string;
|
||||
}
|
||||
|
@ -36,7 +30,6 @@ class ExtensionManager implements IExtensionManager {
|
|||
return 'vsc-material-theme.version';
|
||||
}
|
||||
|
||||
installationType: InstallationType;
|
||||
private readonly configFileUri: Uri;
|
||||
private readonly userConfigFileUri: Uri;
|
||||
private configJSON: MaterialThemeConfig;
|
||||
|
@ -55,10 +48,6 @@ class ExtensionManager implements IExtensionManager {
|
|||
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'));
|
||||
|
@ -67,62 +56,27 @@ class ExtensionManager implements IExtensionManager {
|
|||
async init(context: ExtensionContext): Promise<void> {
|
||||
try {
|
||||
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 configContent = Buffer.from(configBuffer).toString('utf8');
|
||||
|
||||
this.configJSON = JSON.parse(configContent) as MaterialThemeConfig;
|
||||
|
||||
// Update version in user config
|
||||
const userConfigUpdate = {...this.configJSON, changelog: {lastversion: packageJSON.version}};
|
||||
await workspace.fs.writeFile(
|
||||
this.userConfigFileUri,
|
||||
Buffer.from(JSON.stringify(userConfigUpdate), 'utf-8')
|
||||
);
|
||||
|
||||
// Store version in global state
|
||||
await context.globalState.update(this.VERSION_KEY, packageJSON.version);
|
||||
} catch (error) {
|
||||
this.configJSON = {accentsProperties: {}, accents: {}};
|
||||
await window
|
||||
.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();
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// 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'] :
|
||||
// []
|
||||
// );
|
||||
// }
|
||||
// }
|
|
@ -1,161 +0,0 @@
|
|||
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;
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
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>;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
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();
|
|
@ -1,26 +0,0 @@
|
|||
// 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);
|
||||
}
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
<!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>
|
|
@ -1,4 +0,0 @@
|
|||
.AccentsRadioContainer > div {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
Loading…
Add table
Reference in a new issue