diff --git a/src/cm/themes/index.js b/src/cm/themes/index.js index a10145e3e..c81be5925 100644 --- a/src/cm/themes/index.js +++ b/src/cm/themes/index.js @@ -12,6 +12,10 @@ import solarizedLight, { } from "./solarizedLight"; import tokyoNight, { config as tokyoNightConfig } from "./tokyoNight"; import tokyoNightDay, { config as tokyoNightDayConfig } from "./tokyoNightDay"; +import tomorrowNight, { config as tomorrowNightConfig } from "./tomorrowNight"; +import tomorrowNightBright, { + config as tomorrowNightBrightConfig, +} from "./tomorrowNightBright"; import vscodeDark, { config as vscodeDarkConfig } from "./vscodeDark"; const oneDarkConfig = { @@ -207,6 +211,20 @@ addTheme( () => tokyoNight(), tokyoNightConfig, ); +addTheme( + tomorrowNightConfig.name, + "Tomorrow Night", + !!tomorrowNightConfig.dark, + () => tomorrowNight(), + tomorrowNightConfig, +); +addTheme( + tomorrowNightBrightConfig.name, + "Tomorrow Night Bright", + !!tomorrowNightBrightConfig.dark, + () => tomorrowNightBright(), + tomorrowNightBrightConfig, +); addTheme( monokaiConfig.name, "Monokai", diff --git a/src/cm/themes/tomorrowNight.js b/src/cm/themes/tomorrowNight.js new file mode 100644 index 000000000..ef09700e7 --- /dev/null +++ b/src/cm/themes/tomorrowNight.js @@ -0,0 +1,155 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +// Palette adapted from Tomorrow Night (Chris Kempson) +export const config = { + name: "tomorrowNight", + dark: true, + background: "#1D1F21", + foreground: "#C5C8C6", + selection: "#373B41", + cursor: "#AEAFAD", + dropdownBackground: "#1D1F21", + dropdownBorder: "#4B4E55", + activeLine: "#282A2E", + lineNumber: "#4B4E55", + lineNumberActive: "#C5C8C6", + matchingBracket: "#282A2E", + keyword: "#B294BB", + storage: "#B294BB", + variable: "#CC6666", + parameter: "#DE935F", + function: "#81A2BE", + string: "#B5BD68", + constant: "#DE935F", + type: "#F0C674", + class: "#F0C674", + number: "#DE935F", + comment: "#969896", + heading: "#81A2BE", + invalid: "#DF5F5F", + regexp: "#CC6666", + operator: "#8ABEB7", + tag: "#CC6666", +}; + +export const tomorrowNightTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { + borderBottom: `1px solid ${config.dropdownBorder}`, + }, + ".cm-panels.cm-panels-bottom": { + borderTop: `1px solid ${config.dropdownBorder}`, + }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const tomorrowNightHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.operator }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.tagName, color: config.tag }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function tomorrowNight() { + return [tomorrowNightTheme, syntaxHighlighting(tomorrowNightHighlightStyle)]; +} + +export default tomorrowNight; diff --git a/src/cm/themes/tomorrowNightBright.js b/src/cm/themes/tomorrowNightBright.js new file mode 100644 index 000000000..7fb6b25bf --- /dev/null +++ b/src/cm/themes/tomorrowNightBright.js @@ -0,0 +1,158 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +// Palette adapted from Tomorrow Night Bright (Chris Kempson) +export const config = { + name: "tomorrowNightBright", + dark: true, + background: "#000000", + foreground: "#DEDEDE", + selection: "#424242", + cursor: "#9F9F9F", + dropdownBackground: "#000000", + dropdownBorder: "#343434", + activeLine: "#2A2A2A", + lineNumber: "#343434", + lineNumberActive: "#DEDEDE", + matchingBracket: "#2A2A2A", + keyword: "#C397D8", + storage: "#C397D8", + variable: "#D54E53", + parameter: "#E78C45", + function: "#7AA6DA", + string: "#B9CA4A", + constant: "#E78C45", + type: "#E7C547", + class: "#E7C547", + number: "#E78C45", + comment: "#969896", + heading: "#7AA6DA", + invalid: "#DF5F5F", + regexp: "#D54E53", + operator: "#70C0B1", + tag: "#D54E53", +}; + +export const tomorrowNightBrightTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { + borderBottom: `1px solid ${config.dropdownBorder}`, + }, + ".cm-panels.cm-panels-bottom": { + borderTop: `1px solid ${config.dropdownBorder}`, + }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const tomorrowNightBrightHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.operator }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.tagName, color: config.tag }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function tomorrowNightBright() { + return [ + tomorrowNightBrightTheme, + syntaxHighlighting(tomorrowNightBrightHighlightStyle), + ]; +} + +export default tomorrowNightBright; diff --git a/src/pages/plugins/plugins.js b/src/pages/plugins/plugins.js index a0f0bcbe9..92c5e433b 100644 --- a/src/pages/plugins/plugins.js +++ b/src/pages/plugins/plugins.js @@ -52,6 +52,12 @@ export default function PluginsInclude(updates) { let isSearching = false; let currentFilter = null; const LIMIT = 50; + const SUPPORTED_EDITOR = "cm"; + + const withSupportedEditor = (url) => { + const separator = url.includes("?") ? "&" : "?"; + return `${url}${separator}supported_editor=${SUPPORTED_EDITOR}`; + }; Contextmenu({ toggler: $add, @@ -337,7 +343,7 @@ export default function PluginsInclude(updates) { if (!query) return []; try { const response = await fetch( - `${constants.API_BASE}/plugins?name=${query}`, + withSupportedEditor(`${constants.API_BASE}/plugins?name=${query}`), ); const plugins = await response.json(); // Map the plugins to Item elements and return @@ -418,11 +424,15 @@ export default function PluginsInclude(updates) { let response; if (filterState.value === "top_rated") { response = await fetch( - `${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`, + withSupportedEditor( + `${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`, + ), ); } else { response = await fetch( - `${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`, + withSupportedEditor( + `${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`, + ), ); } const items = await response.json(); @@ -461,7 +471,7 @@ export default function PluginsInclude(updates) { try { const page = filterState.nextPage; const response = await fetch( - `${constants.API_BASE}/plugins?page=${page}&limit=${LIMIT}`, + withSupportedEditor(`${constants.API_BASE}/plugins?page=${page}&limit=${LIMIT}`), ); const data = await response.json(); filterState.nextPage = page + 1; @@ -557,7 +567,9 @@ export default function PluginsInclude(updates) { $list.all.setAttribute("empty-msg", strings["loading..."]); - const response = await fetch(`${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`); + const response = await fetch( + withSupportedEditor(`${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`), + ); const newPlugins = await response.json(); if (newPlugins.length < LIMIT) { diff --git a/src/sidebarApps/extensions/index.js b/src/sidebarApps/extensions/index.js index 01e83bd64..0a396cf9d 100644 --- a/src/sidebarApps/extensions/index.js +++ b/src/sidebarApps/extensions/index.js @@ -33,6 +33,12 @@ let isLoading = false; let currentFilter = null; let filterHasMore = true; let isFilterLoading = false; +const SUPPORTED_EDITOR = "cm"; + +function withSupportedEditor(url) { + const separator = url.includes("?") ? "&" : "?"; + return `${url}${separator}supported_editor=${SUPPORTED_EDITOR}`; +} const $header = (
@@ -140,7 +146,9 @@ async function loadMorePlugins() { startLoading($explore); const response = await fetch( - `${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`, + withSupportedEditor( + `${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`, + ), ); const newPlugins = await response.json(); @@ -224,7 +232,9 @@ async function searchPlugin() { try { $searchResult.classList.add("loading"); const plugins = await fsOperation( - Url.join(constants.API_BASE, `plugins?name=${query}`), + withSupportedEditor( + Url.join(constants.API_BASE, `plugins?name=${query}`), + ), ).readFile("json"); installedPlugins = await listInstalledPlugins(); @@ -411,7 +421,9 @@ async function loadExplore() { hasMore = true; const response = await fetch( - `${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`, + withSupportedEditor( + `${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`, + ), ); const plugins = await response.json(); @@ -454,11 +466,15 @@ async function getFilteredPlugins(filterState) { let response; if (filterState.value === "top_rated") { response = await fetch( - `${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`, + withSupportedEditor( + `${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`, + ), ); } else { response = await fetch( - `${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`, + withSupportedEditor( + `${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`, + ), ); } const items = await response.json(); @@ -497,7 +513,9 @@ async function getFilteredPlugins(filterState) { try { const page = filterState.nextPage; const response = await fetch( - `${constants.API_BASE}/plugins?page=${page}&limit=${LIMIT}`, + withSupportedEditor( + `${constants.API_BASE}/plugins?page=${page}&limit=${LIMIT}`, + ), ); const data = await response.json(); filterState.nextPage = page + 1;