| 1 | import { themes } from "./extensionhandler"; |
| 2 | import { info } from "tauri-plugin-log-api"; |
| 3 | import { get, writable } from "svelte/store"; |
| 4 | import { termTheme, updateTermTheme } from "../lib/Terminal.svelte"; |
| 5 | import { setColorScheme, setEditorTheme } from "../lib/Editor.svelte"; |
| 6 | import { EditorView } from "@codemirror/view"; |
| 7 | import { HighlightStyle } from "@codemirror/language" |
| 8 | |
| 9 | export function getThemes() { |
| 10 | return get(themes); |
| 11 | } |
| 12 | |
| 13 | const stylesheet = document.styleSheets[0].cssRules[0] as CSSStyleRule; |
| 14 | export const is_dark_theme = writable(true); |
| 15 | export const editorTheme = writable(EditorView.theme({})); |
| 16 | export const editorHighlightStyle = writable(HighlightStyle.define([])) |
| 17 | export async function loadTheme(name: string) { |
| 18 | let theme = get(themes).find(n => n.name === name); |
| 19 | info(`Loading theme: ${name}...`, {file: "themehandler.ts", line: 16}); |
| 20 | is_dark_theme.set(theme.scheme === "dark"); |
| 21 | |
| 22 | |
| 23 | // load base theme |
| 24 | let json = await import(`./extensions/default_themes/themes/default_${theme.scheme}.json`); |
| 25 | let { tokenStyles } = await import(`./extensions/default_themes/script`); |
| 26 | const tokens = tokenStyles[theme.scheme]; |
| 27 | processStyles(json); |
| 28 | |
| 29 | // load custom theme if it exists |
| 30 | //const path = await join(await homeDir(), ".svara", "extensions"); |
| 31 | //if (await exists(path)) { |
| 32 | //const custom_themes = await readDir(path); |
| 33 | //} |
| 34 | |
| 35 | setColorScheme(); |
| 36 | termTheme.set({ |
| 37 | "black": getThemeProperty("terminal-black"), |
| 38 | "red": getThemeProperty("terminal-red"), |
| 39 | "green": getThemeProperty("terminal-green"), |
| 40 | "yellow": getThemeProperty("terminal-yellow"), |
| 41 | "blue": getThemeProperty("terminal-blue"), |
| 42 | "magenta": getThemeProperty("terminal-magenta"), |
| 43 | "cyan": getThemeProperty("terminal-cyan"), |
| 44 | "white": getThemeProperty("terminal-white"), |
| 45 | "brightBlack": getThemeProperty("terminal-brightBlack"), |
| 46 | "brightRed": getThemeProperty("terminal-brightRed"), |
| 47 | "brightGreen": getThemeProperty("terminal-brightGreen"), |
| 48 | "brightYellow": getThemeProperty("terminal-brightYellow"), |
| 49 | "brightBlue": getThemeProperty("terminal-brightBlue"), |
| 50 | "brightMagenta": getThemeProperty("terminal-brightMagenta"), |
| 51 | "brightCyan": getThemeProperty("terminal-brightCyan"), |
| 52 | "brightWhite": getThemeProperty("terminal-brightWhite"), |
| 53 | |
| 54 | "background": getThemeProperty("terminal-background"), |
| 55 | "foreground": getThemeProperty("terminal-foreground") |
| 56 | }) |
| 57 | |
| 58 | editorTheme.set(EditorView.theme( |
| 59 | { |
| 60 | "&": { |
| 61 | color: getThemeProperty("editor-foreground"), |
| 62 | backgroundColor: getThemeProperty("editor-background"), |
| 63 | }, |
| 64 | ".cm-content": { |
| 65 | caretColor: getThemeProperty("editor-foreground") |
| 66 | }, |
| 67 | |
| 68 | "&.cm-focused .cm-cursor": { |
| 69 | borderLeftColor: getThemeProperty("editor-foreground") |
| 70 | }, |
| 71 | |
| 72 | "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, ::selection": { |
| 73 | backgroundColor: "#4d5054" |
| 74 | }, |
| 75 | ".cm-activeLine": { |
| 76 | backgroundColor: getThemeProperty("editor-activeLineBackground"), |
| 77 | }, |
| 78 | ".cm-gutters": { |
| 79 | backgroundColor: getThemeProperty("editor-background"), |
| 80 | color: getThemeProperty("editor-gutterForeground"), |
| 81 | border: "none" |
| 82 | }, |
| 83 | ".cm-activeLineGutter": { |
| 84 | backgroundColor: getThemeProperty("editor-gutterActiveBackground"), |
| 85 | color: getThemeProperty("editor-gutterActiveForeground") |
| 86 | }, |
| 87 | ".cm-tooltip": { |
| 88 | border: `1px solid ${getThemeProperty("editor-tooltipBorder")}`, |
| 89 | backgroundColor: getThemeProperty("editor-tooltipBackground"), |
| 90 | color: getThemeProperty("editor-tooltipForeground"), |
| 91 | }, |
| 92 | ".cm-tooltip-autocomplete": { |
| 93 | "& > ul": { |
| 94 | maxHeight: "12em !important", |
| 95 | fontWeight: "500" |
| 96 | }, |
| 97 | "& > ul > li[aria-selected]": { |
| 98 | backgroundColor: getThemeProperty("editor-tooltipActiveBackground"), |
| 99 | color: getThemeProperty("editor-tooltipActiveForeground") |
| 100 | }, |
| 101 | "& > ul > li": { |
| 102 | padding: "2px 3px !important" |
| 103 | } |
| 104 | }, |
| 105 | ".cm-completionMatchedText": { |
| 106 | textDecoration: "none", |
| 107 | color: getThemeProperty("editor-tooltipCompletionForeground") |
| 108 | }, |
| 109 | "&.cm-focused .cm-matchingBracket": { |
| 110 | backgroundColor: "transparent", |
| 111 | outline: "0.5px solid #5c5c5c" |
| 112 | } |
| 113 | }, |
| 114 | { dark: get(is_dark_theme) } |
| 115 | )) |
| 116 | editorHighlightStyle.set(HighlightStyle.define(tokens)); |
| 117 | |
| 118 | setEditorTheme(); |
| 119 | updateTermTheme(); |
| 120 | |
| 121 | info("Theme loaded sucessfully.", {file: "themehandler.ts", line: 35}); |
| 122 | } |
| 123 | function processStyles(json) { |
| 124 | const theme: any = Object.entries(json.theme); |
| 125 | for (const entries of theme) { |
| 126 | const [category, component] = entries[0].split("."); |
| 127 | const property = `--${category}-${component}`; |
| 128 | const value = entries[1] === "transparent" || "" ? "transparent" : entries[1]; |
| 129 | stylesheet.style.setProperty(property, value); |
| 130 | } |
| 131 | } |
| 132 | export function getThemeProperty(styleName: string) { |
| 133 | for (const style of stylesheet.style) { |
| 134 | if (style === `--${styleName}`) { |
| 135 | return stylesheet.style.getPropertyValue(style); |
| 136 | } |
| 137 | } |
| 138 | return "purple"; |
| 139 | } |