diff --git a/app/index.css b/app/index.css index 660cf835..e366d09c 100644 --- a/app/index.css +++ b/app/index.css @@ -224,25 +224,27 @@ body { --text-color-secondary: #888; --text-color-detail: #757a89; --text-color-disabled: #888; - --bg-primary: #555; - --bg-primary-border: #444; - --bg-primary-active: #575757; - --bg-primary-hover: #666; - --bg-window: #3d3d3d; - --bg-window-inactive: #626262; - --bg-secondary: #373737; - --bg-secondary-border: #333; - --bg-secondary-active: #555; - --bg-secondary-hover: #454545; - - --bg-editable-overlay: rgb(255, 255, 255, 0.2); - --bg-editable-overlay-active: rgb(255, 255, 255, 0.1); - --bg-input: rgba(35, 35, 35, 0.309); - --bg-input-hover: rgba(79, 79, 79, 0.309); - --bg-input-active: rgba(50, 50, 50, 0.309); - --bg-input-border: rgba(0, 0, 0, 0.3); - --bg-widget: rgba(0, 0, 0, 0.5); - --bg-tooltip: rgba(20, 20, 20, 0.95); + --primary-bg: #555; + --primary-border: #444; + --primary-bg-active: #575757; + --primary-bg-hover: #666; + --navbar-bg: #3d3d3d; + --navbar-bg-inactive: #626262; + --window-bg: #3d3d3d; + --window-border: #00000000; + --secondary-bg: #373737; + --secondary-border: #333; + --secondary-bg-active: #555; + --secondary-bg-hover: #454545; + + --editable-overlay-hover: rgb(255, 255, 255, 0.2); + --editable-overlay-active: rgb(255, 255, 255, 0.1); + --input-bg: rgba(35, 35, 35, 0.309); + --input-bg-hover: rgba(79, 79, 79, 0.309); + --input-bg-active: rgba(50, 50, 50, 0.309); + --input-border: rgba(0, 0, 0, 0.3); + --widget-bg: rgba(0, 0, 0, 0.5); + --tooltip-bg: rgba(20, 20, 20, 0.95); } body { @@ -287,11 +289,13 @@ html { border-radius: 5px; position: fixed; box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.6); + border: 1px solid var(--window-border); + overflow: hidden; } .navbar { align-items: center; - background: var(--bg-window); - border-bottom: 1px solid var(--bg-primary-border); + background: var(--navbar-bg); + border-bottom: 1px solid var(--primary-border); border-top-left-radius: 5px; border-top-right-radius: 5px; display: flex; @@ -302,7 +306,7 @@ html { gap: 3px; } .window:not(.focused) > .navbar { - background: var(--bg-window-inactive); + background: var(--navbar-bg-inactive); border-bottom: 1px solid transparent; } @@ -328,7 +332,7 @@ html { filter: none; } button { - background: var(--bg-input); + background: var(--input-bg); border: 0.5px solid rgba(0, 0, 0, 0.6); border-radius: 5px; padding: 4px 7px; @@ -371,14 +375,14 @@ button.delete { color: white; } button:disabled { - filter: brightness(0.8); + opacity: 0.5; transform: none; box-shadow: none; cursor: not-allowed; } .view { - background-color: var(--bg-window); + background-color: var(--window-bg); font-size: 15px; overflow: hidden; } @@ -474,7 +478,8 @@ button:disabled { align-items: center; } .dir-selector { - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); border-radius: 5px 5px 0 0; flex: 1; height: 100%; @@ -485,7 +490,8 @@ button:disabled { display: flex; flex-direction: row; column-gap: 5px; - background-color: var(--bg-tertiary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); margin-bottom: 5px; padding: 4px; border-radius: 0 0 5px 5px; @@ -497,13 +503,13 @@ button:disabled { opacity: 0.3; } .info.selected { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .info.selected:hover { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .info:hover { - background-color: var(--bg-secondary-hover); + background-color: var(--secondary-bg-hover); } .options-icon { display: none; @@ -537,7 +543,8 @@ textarea { align-items: center; } .recent-selector { - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); border-radius: 5px 5px 0 0; flex: 1; height: 100%; @@ -566,13 +573,13 @@ textarea { font-size: 14px; } .recent-item.selected { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .recent-item.selected:hover { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .recent-item:hover { - background-color: var(--bg-secondary-hover); + background-color: var(--secondary-bg-hover); } .recent-item .recent-path { font-style: italic; @@ -610,7 +617,8 @@ textarea { #menubar { display: flex; - background-color: var(--bg-primary); + background-color: var(--primary-bg); + border-bottom: 1px solid var(--secondary-border); } .menu-item { @@ -630,8 +638,8 @@ textarea { #menubar .menubar-dropdown { display: none; - background-color: var(--bg-primary); - border: 1px solid var(--bg-primary-border); + background-color: var(--primary-bg); + border: 1px solid var(--primary-border); position: absolute; border-radius: 5px; } @@ -672,7 +680,7 @@ textarea { } .menu-item:not(.disabled) > .menu-hover:hover { - background-color: var(--bg-primary-hover); + background-color: var(--primary-bg-hover); } .animated .menu-hover { @@ -680,7 +688,7 @@ textarea { } .separator { - border: 0.2px solid var(--bg-secondary); + border: 0.2px solid var(--secondary-bg); margin: 4px; height: 1px; } @@ -701,14 +709,16 @@ textarea { .chart-list { height: 100%; - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); border-radius: 5px; overflow: scroll; } .chart-info { height: 100%; - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); border-radius: 5px; word-break: break-all; padding: 15px; @@ -731,7 +741,7 @@ textarea { .chart-list-item { display: flex; align-items: center; - border: 0.2px solid var(--bg-secondary-border); + border: 0.2px solid var(--secondary-border); cursor: pointer; } @@ -740,15 +750,15 @@ textarea { } .chart-list-item.selected { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .chart-list-item:active { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .chart-list-item:not(.selected):hover { - background-color: var(--bg-secondary-hover); + background-color: var(--secondary-bg-hover); } .chart-list-item .Beginner { @@ -852,11 +862,11 @@ div.inlineEdit { } div.inlineEdit[contenteditable="true"]:hover { - background: var(--bg-editable-overlay); + background: var(--editable-overlay-hover); } div.inlineEdit[contenteditable="true"]:focus { - background: var(--bg-editable-overlay-active); + background: var(--editable-overlay-active); outline: none; overflow: auto; text-overflow: clip; @@ -933,8 +943,8 @@ div.inlineEdit[contenteditable="true"]:focus { input[type="text"], input[type="number"] { - background: var(--bg-input); - border: 1px solid var(--bg-input-border); + background: var(--input-bg); + border: 1px solid var(--input-border); border-radius: 3px; padding: 0 3px; flex: 1; @@ -991,8 +1001,8 @@ input.right { } .dropdown-selected { - background-color: var(--bg-input); - border: 1px solid var(--bg-input-border); + background-color: var(--input-bg); + border: 1px solid var(--input-border); border-radius: 3px; width: 100%; height: 100%; @@ -1021,15 +1031,15 @@ input.right { margin-left: auto; } .dropdown-selected:hover:not(.disabled):not(:active) { - background: var(--bg-editable-overlay); + background: var(--editable-overlay-hover); } .dropdown-selected:active { - background: var(--bg-editable-overlay); + background: var(--editable-overlay-hover); } .dropdown-items { position: absolute; - background: var(--bg-primary); + background: var(--primary-bg); max-height: 200px; overflow: auto; z-index: 5; @@ -1062,11 +1072,11 @@ input.right { } .dropdown-item:hover { - background: var(--bg-primary-hover); + background: var(--primary-bg-hover); } .dropdown-item:active { - background: var(--bg-primary-active); + background: var(--primary-bg-active); } @keyframes dropdown-enter { @@ -1081,7 +1091,8 @@ input.right { } .pref-selector { - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); border-radius: 0 0 5px 5px; flex: 1; height: 100%; @@ -1097,7 +1108,7 @@ input.right { padding: 1px 0; } .pref-label:hover { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .flex-row { @@ -1154,7 +1165,7 @@ input.right { .spinner-btns { display: grid; grid-template-rows: 1fr 1fr; - border: 1px solid var(--bg-input-border); + border: 1px solid var(--input-border); border-left: none; border-top-right-radius: 3px; border-bottom-right-radius: 3px; @@ -1169,30 +1180,21 @@ input.right { border-radius: 0; height: 100%; width: 10px; + height: 9px; border: none; min-width: auto; } -.spinner-btns button::after { - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAAbklEQVRIie2PMQqAMAxFXwfP6qJVPIjYzcOKdUkhQ0BaCoLkLS3k818CjuN8ztApYzIDl7xvmalFsAIZuIFozKPMMrC0CAJwKIkuGVX5KdkmLEm3ci1JSlLKU49yLSmXVG1es0EANvnvInKcP/AA784fpjlWwNQAAAAASUVORK5CYII=") - no-repeat center center; - background-size: contain; - position: absolute; - width: 10px; - height: 10px; - content: ""; -} - -.spinner-btns .spinner-up::after { - transform: rotate(180deg); +.spinner-btns .spinner-up svg { + rotate: 180deg; } .spinner-up { - background: linear-gradient(0deg, var(--bg-input-active), var(--bg-input)); + background: linear-gradient(0deg, var(--input-bg-active), var(--input-bg)); } .spinner-down { - background: linear-gradient(180deg, var(--bg-input-active), var(--bg-input)); + background: linear-gradient(180deg, var(--input-bg-active), var(--input-bg)); } .slider { @@ -1308,7 +1310,7 @@ input[type="range"] { } .playback-bar { - background-color: var(--bg-widget); + background-color: var(--widget-bg); } #status-widget:not(.collapsed) .playback-bar { @@ -1336,10 +1338,10 @@ input[type="range"] { } #status-widget button:hover:not(.active) { - background-color: var(--bg-editable-overlay); + background-color: var(--editable-overlay-hover); } #status-widget button.active { - background-color: var(--bg-editable-overlay-active); + background-color: var(--editable-overlay-active); } #status-widget button:disabled { filter: brightness(0.2) saturate(0.4); @@ -1410,7 +1412,7 @@ input[type="range"] { } #status-widget .edit-fancy-button.active { - background-color: var(--bg-editable-overlay-active); + background-color: var(--editable-overlay-active); } #status-widget .edit-fancy-button img { @@ -1449,18 +1451,18 @@ input[type="range"] { } .edit-timing-container { - background-color: var(--bg-widget); + background-color: var(--widget-bg); height: 48px; } #status-widget .edit-bar .edit-bar-left { - background-color: var(--bg-widget); + background-color: var(--widget-bg); display: flex; flex-direction: row; } .note-placeholder-right { flex: 1; - background-color: var(--bg-widget); + background-color: var(--widget-bg); height: 48px; } @@ -1475,7 +1477,7 @@ input[type="range"] { transform-origin: top center; display: flex; flex-direction: column; - background-color: var(--bg-window); + background-color: var(--window-bg); border-radius: 5px; padding: 8px; align-items: center; @@ -1740,7 +1742,8 @@ input[type="range"] { .track-grid { display: flex; flex-direction: row; - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); padding: 4px; border-radius: 3px; width: 468.08px; @@ -1759,7 +1762,8 @@ input[type="range"] { height: 30px; display: flex; flex-direction: row; - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); padding: 4px; border-radius: 3px; gap: 4px; @@ -1827,8 +1831,8 @@ input[type="range"] { display: flex; position: absolute; flex-direction: column; - background-color: var(--bg-primary); - border: 1px solid var(--bg-primary-border); + background-color: var(--primary-bg); + border: 1px solid var(--primary-border); caret-color: transparent; font-size: 15px; border-radius: 5px; @@ -1881,8 +1885,8 @@ input[type="range"] { } #context-menu .menubar-dropdown { - background-color: var(--bg-primary); - border: 1px solid var(--bg-primary-border); + background-color: var(--primary-bg); + border: 1px solid var(--primary-border); position: absolute; left: 100%; top: 0; @@ -1954,7 +1958,8 @@ input[type="range"] { .pref-section-scroller, .pref-option-scroller { - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); overflow: auto; padding: 5px; border-radius: 5px; @@ -1993,13 +1998,13 @@ input[type="range"] { .pref-section.selected, .pref-section.selected:hover { - background-color: var(--bg-secondary-active); + background-color: var(--secondary-bg-active); } .pref-section:hover, .pref-keybind:hover, .pref-item:hover { - background-color: var(--bg-secondary-hover); + background-color: var(--secondary-bg-hover); } .pref-option-scroller { @@ -2133,21 +2138,21 @@ input[type="range"] { } .tippy-box[data-theme~="sm"] { - background-color: var(--bg-tooltip); + background-color: var(--tooltip-bg); color: var(--text-color); } .tippy-box[data-theme~="sm"][data-placement^="top"] > .tippy-arrow::before { - border-top-color: var(--bg-tooltip); + border-top-color: var(--tooltip-bg); } .tippy-box[data-theme~="sm"][data-placement^="bottom"] > .tippy-arrow::before { - border-bottom-color: var(--bg-tooltip); + border-bottom-color: var(--tooltip-bg); } .tippy-box[data-theme~="sm"][data-placement^="left"] > .tippy-arrow::before { - border-left-color: var(--bg-tooltip); + border-left-color: var(--tooltip-bg); } .tippy-box[data-theme~="sm"][data-placement^="right"] > .tippy-arrow::before { - border-right-color: var(--bg-tooltip); + border-right-color: var(--tooltip-bg); } .export-container { @@ -2175,7 +2180,8 @@ input[type="range"] { .export-output { flex: 1; border-radius: 5px; - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); padding: 5px; white-space: pre-wrap; word-break: break-all; @@ -2186,7 +2192,7 @@ input[type="range"] { } .export-output:hover { - background-color: var(--bg-secondary-hover); + background-color: var(--secondary-bg-hover); } .animated .export-output { @@ -2389,7 +2395,8 @@ input[type="color"] { flex-direction: row; align-items: center; margin: 10px 5px; - background: var(--bg-secondary); + background: var(--secondary-bg); + border: 1px solid var(--secondary-border); font-size: 13px; border-radius: 5px; } @@ -2417,7 +2424,8 @@ input[type="color"] { width: 370px; flex: 1; min-height: 0; - background: var(--bg-secondary); + background: var(--secondary-bg); + border: 1px solid var(--secondary-border); border-radius: 5px; position: relative; } @@ -2522,7 +2530,8 @@ input[type="color"] { flex-direction: row; user-select: none; gap: 24px; - background-color: var(--bg-widget); + background-color: var(--secondary-bg); + border-bottom: 1px solid var(--secondary-border); padding: 0px 10px; font-size: 15px; overflow-x: auto; @@ -2534,6 +2543,7 @@ input[type="color"] { #playback-options.collapsed { height: 0px; + border-bottom: 0px solid var(--secondary-border); } .playback-options-title { @@ -2577,7 +2587,7 @@ input[type="color"] { border: none; outline: none; filter: none; - background-color: var(--bg-input); + background-color: var(--input-bg); border-radius: 5px; width: 12px; height: 20px; @@ -2589,13 +2599,13 @@ input[type="color"] { #playback-options .po-spinner .po-spinner-btn:first-of-type { border-top-right-radius: 0px; border-bottom-right-radius: 0px; - border: 1px var(--bg-input-border) solid; + border: 1px var(--input-border) solid; } #playback-options .po-spinner .po-spinner-btn:last-of-type { border-top-left-radius: 0px; border-bottom-left-radius: 0px; - border: 1px var(--bg-input-border) solid; + border: 1px var(--input-border) solid; } #playback-options .po-spinner-btn:disabled { @@ -2603,19 +2613,19 @@ input[type="color"] { } #playback-options .po-spinner-btn:hover:not(:disabled) { - background-color: var(--bg-input-hover); + background-color: var(--input-bg-hover); } #playback-options .po-spinner-btn:active:not(:disabled) { - background-color: var(--bg-input-active); + background-color: var(--input-bg-active); } #playback-options .po-spinner-input { - background-color: var(--bg-input); + background-color: var(--input-bg); border-left: none; border-right: none; - border-top: 1px solid var(--bg-input-border); - border-bottom: 1px solid var(--bg-input-border); + border-top: 1px solid var(--input-border); + border-bottom: 1px solid var(--input-border); border-radius: 0; width: 42px; height: 20px; @@ -2625,7 +2635,7 @@ input[type="color"] { } #playback-options .po-spinner-input:hover { - background-color: var(--bg-input-hover); + background-color: var(--input-bg-hover); } #playback-options .po-spinner-input:disabled { @@ -2651,8 +2661,8 @@ input[type="color"] { } .po-toggle { - background-color: var(--bg-input); - border: 1px solid var(--bg-input-border); + background-color: var(--input-bg); + border: 1px solid var(--input-border); display: flex; flex-direction: row; gap: 5px; @@ -2677,28 +2687,26 @@ input[type="color"] { .po-toggle-highlight { position: absolute; - background-color: var(--bg-editable-overlay-active); + background-color: var(--editable-overlay-active); border-radius: 5px; pointer-events: none; } -.po-checkbox { - height: 20px; - width: 20px; +.ico-checkbox { padding: 1px; border-radius: 2px; } -.po-checkbox:hover { - background: var(--bg-editable-overlay); +.ico-checkbox:hover { + background: var(--editable-overlay-hover); } -.po-checkbox:active { - background: var(--bg-editable-overlay-active); +.ico-checkbox:active { + background: var(--editable-overlay-active); } .animated .po-toggle > *, -.animated .po-checkbox { +.animated .ico-checkbox { transition: 0.15s ease-in-out; } @@ -2746,7 +2754,8 @@ input[type="color"] { width: 100%; gap: 15px; padding: 10px; - background: var(--bg-secondary); + background: var(--secondary-bg); + border: 1px solid var(--secondary-border); margin-top: 10px; border-radius: 5px; overflow: auto; @@ -2817,26 +2826,28 @@ input[type="color"] { } .theme-color-grid { - display: grid; - grid-template-columns: repeat(5, 1fr); - gap: 15px; + display: flex; + flex-direction: column; + gap: 5px; font-size: 12px; - text-align: center; - background-color: var(--bg-secondary); + background-color: var(--secondary-bg); + border: 1px solid var(--secondary-border); padding: 15px; overflow: auto; } -.theme-generator-grid { +.theme-group-label { + font-size: 16px; +} + +.theme-picker-grid { display: grid; - grid-template-columns: repeat(2, 1fr); + grid-template-columns: repeat(4, 1fr); + color: var(--text-color-secondary); gap: 15px; - font-size: 12px; + font-size: 15px; text-align: center; - background-color: var(--bg-secondary); - padding: 15px; - margin-bottom: 15px; - height: 170px; + padding: 5px; overflow: auto; } diff --git a/app/src/App.ts b/app/src/App.ts index 0ea54180..338e51e9 100644 --- a/app/src/App.ts +++ b/app/src/App.ts @@ -353,7 +353,7 @@ export class App { EventHandler.on("themeChanged", () => { this.renderer.background.color = new Color( - Themes.getCurrentTheme()["bg-editor"] + Themes.getCurrentTheme()["editor-bg"] ).toNumber() }) diff --git a/app/src/data/ThemeData.ts b/app/src/data/ThemeData.ts index a1134d9f..f7760114 100644 --- a/app/src/data/ThemeData.ts +++ b/app/src/data/ThemeData.ts @@ -1,30 +1,33 @@ import { Color } from "pixi.js" +import { ThemeWindow } from "../gui/window/ThemeWindow" export const THEME_VAR_WHITELIST = [ "accent-color", - "bg-editor", - "bg-widget", - "bg-editable-overlay", - "bg-editable-overlay-active", + "editor-bg", + "widget-bg", + "editable-overlay-hover", + "editable-overlay-active", "text-color", "text-color-secondary", "text-color-detail", "text-color-disabled", - "bg-primary", - "bg-primary-border", - "bg-primary-active", - "bg-primary-hover", - "bg-secondary", - "bg-secondary-border", - "bg-secondary-active", - "bg-secondary-hover", - "bg-tooltip", - "bg-input", - "bg-input-active", - "bg-input-hover", - "bg-input-border", - "bg-window", - "bg-window-inactive", + "primary-bg", + "primary-border", + "primary-bg-active", + "primary-bg-hover", + "secondary-bg", + "secondary-border", + "secondary-bg-active", + "secondary-bg-hover", + "tooltip-bg", + "input-bg", + "input-bg-active", + "input-bg-hover", + "input-border", + "navbar-bg", + "navbar-bg-inactive", + "window-bg", + "window-border", ] as const export type ThemeProperty = (typeof THEME_VAR_WHITELIST)[number] @@ -37,6 +40,161 @@ export type Theme = { [key in ThemeProperty]: Color } +export type ThemeGroup = { + name: string + ids: { + id: ThemeProperty + label: string + }[] +} + +export const THEME_GROUPS: ThemeGroup[] = [ + { + name: "main", + ids: [ + { + id: "accent-color", + label: "accent-color", + }, + { + id: "widget-bg", + label: "widget-bg", + }, + { + id: "tooltip-bg", + label: "tooltip-bg", + }, + { + id: "editor-bg", + label: "editor-bg", + }, + ], + }, + { + name: "text-color", + ids: [ + { + id: "text-color", + label: "primary", + }, + { + id: "text-color-secondary", + label: "secondary", + }, + { + id: "text-color-detail", + label: "detail", + }, + { + id: "text-color-disabled", + label: "disabled", + }, + ], + }, + { + name: "primary-bg", + ids: [ + { + id: "primary-bg", + label: "base", + }, + { + id: "primary-bg-active", + label: "active", + }, + { + id: "primary-bg-hover", + label: "hover", + }, + { + id: "primary-border", + label: "border", + }, + ], + }, + { + name: "secondary-bg", + ids: [ + { + id: "secondary-bg", + label: "base", + }, + { + id: "secondary-bg-active", + label: "active", + }, + { + id: "secondary-bg-hover", + label: "hover", + }, + { + id: "secondary-border", + label: "border", + }, + ], + }, + { + name: "navbar", + ids: [ + { + id: "navbar-bg", + label: "active", + }, + { + id: "navbar-bg-inactive", + label: "inactive", + }, + ], + }, + { + name: "editable-overlay", + ids: [ + { + id: "editable-overlay-hover", + label: "hover", + }, + { + id: "editable-overlay-active", + label: "active", + }, + ], + }, + { + name: "input", + ids: [ + { + id: "input-bg", + label: "background", + }, + { + id: "input-bg-active", + label: "active", + }, + { + id: "input-bg-hover", + label: "hover", + }, + { + id: "input-border", + label: "border", + }, + ], + }, + { + name: "window", + ids: [ + { + id: "window-bg", + label: "background", + }, + { + id: "window-border", + label: "border", + }, + ], + }, +] + export const THEME_PROPERTY_DESCRIPTIONS: { [key in ThemeProperty]: string } = { @@ -47,26 +205,115 @@ export const THEME_PROPERTY_DESCRIPTIONS: { "text-color-detail": "Detail text color, used for text in timing event boxes", "text-color-disabled": "Used for texts relating to empty/disabled things (ex. no files in directory picker)", - "bg-primary": "Primary background, used for menubar, context/dropdown menus", - "bg-primary-border": "", - "bg-primary-active": "", - "bg-primary-hover": "", - "bg-window": "Window navbar background", - "bg-window-inactive": "", - "bg-secondary": "Secondary background, used for subareas in menus", - "bg-secondary-border": "", - "bg-secondary-active": "", - "bg-secondary-hover": "", - "bg-editable-overlay": + "primary-bg": "Primary background, used for menubar, context/dropdown menus", + "primary-border": "", + "primary-bg-active": "", + "primary-bg-hover": "", + "navbar-bg": "Window navbar background", + "navbar-bg-inactive": "", + "window-bg": "Window background", + "window-border": "", + "secondary-bg": "Secondary background, used for subareas in menus", + "secondary-border": "", + "secondary-bg-active": "", + "secondary-bg-hover": "", + "editable-overlay-hover": "Overlay on top of editable items (status widget buttons, playback option toggles, textareas)", - "bg-editable-overlay-active": "", - "bg-input": "Background color for input", - "bg-input-active": "", - "bg-input-hover": "", - "bg-input-border": "", - "bg-widget": "Widget background", - "bg-tooltip": "Color of these tooltips", - "bg-editor": "Editor background", + "editable-overlay-active": "", + "input-bg": "Background color for input", + "input-bg-active": "", + "input-bg-hover": "", + "input-border": "", + "widget-bg": "Widget background", + "tooltip-bg": "Color of these tooltips", + "editor-bg": "Editor background", +} + +export type ThemeColorLinks = { + [key in ThemeProperty]?: (this: ThemeWindow, c: Color) => Color +} + +export const THEME_GENERATOR_LINKS: { + [key in ThemeProperty]?: ThemeColorLinks +} = { + "primary-bg": { + "primary-border": function (c) { + return this.lighten(c, 10).setAlpha(0xbb) + }, + "primary-bg-active": function (c) { + return this.lighten(c, 10) + }, + "primary-bg-hover": function (c) { + return this.lighten(c, 30) + }, + "widget-bg": function (c) { + return this.add(c, -50).setAlpha(0x88) + }, + "navbar-bg": function (c) { + return this.lighten(c, -10) + }, + "text-color": function (c) { + return this.average(c) > 0.5 ? new Color("#000") : new Color("#fff") + }, + "input-bg": function (c) { + return this.average(c) < 0.5 ? new Color("#000") : new Color("#fff") + }, + "input-border": function (c) { + return this.average(c) > 0.5 + ? this.add(c, -30).setAlpha(0x77) + : this.add(c, +30).setAlpha(0x77) + }, + "tooltip-bg": function (c) { + return this.lighten(c, -10).setAlpha(0xee) + }, + "secondary-bg": function (c) { + return this.lighten(c, -20) + }, + "editor-bg": function (c) { + return this.lighten(c, -60) + }, + }, + "secondary-bg": { + "secondary-border": function (c) { + return this.lighten(c, 10).setAlpha(0xbb) + }, + "secondary-bg-active": function (c) { + return this.lighten(c, 10) + }, + "secondary-bg-hover": function (c) { + return this.lighten(c, 30) + }, + }, + "navbar-bg": { + "navbar-bg-inactive": function (c) { + return this.lighten(c, -33) + }, + "window-bg": function (c) { + return new Color(c) + }, + }, + "text-color": { + "text-color-secondary": function (c) { + return new Color(c).setAlpha(0x77 / 0xff) + }, + "text-color-detail": function (c) { + return new Color(c).setAlpha(0x44 / 0xff) + }, + "text-color-disabled": function (c) { + return new Color(c).setAlpha(0x88 / 0xff) + }, + }, + "input-bg": { + "input-border": function (c) { + return this.lighten(c, 10).setAlpha(0xbb) + }, + "input-bg-active": function (c) { + return this.lighten(c, 10) + }, + "input-bg-hover": function (c) { + return this.lighten(c, 30) + }, + }, } export const DEFAULT_THEMES: Record = { @@ -76,25 +323,27 @@ export const DEFAULT_THEMES: Record = { "text-color-secondary": new Color("#888"), "text-color-detail": new Color("#757a89"), "text-color-disabled": new Color("#888"), - "bg-primary": new Color("#555"), - "bg-primary-border": new Color("#444"), - "bg-primary-active": new Color("#575757"), - "bg-primary-hover": new Color("#666"), - "bg-window": new Color("#3d3d3d"), - "bg-window-inactive": new Color("#626262"), - "bg-secondary": new Color("#373737"), - "bg-secondary-border": new Color("#333"), - "bg-secondary-active": new Color("#555"), - "bg-secondary-hover": new Color("#454545"), - "bg-editable-overlay": new Color("rgb(255, 255, 255, 0.1)"), - "bg-editable-overlay-active": new Color("rgb(255, 255, 255, 0.2)"), - "bg-input": new Color("rgba(35, 35, 35, 0.309)"), - "bg-input-active": new Color("rgba(50, 50, 50, 0.309)"), - "bg-input-hover": new Color("rgba(79, 79, 79, 0.309)"), - "bg-input-border": new Color("rgba(0, 0, 0, 0.3)"), - "bg-widget": new Color("rgba(0, 0, 0, 0.5)"), - "bg-tooltip": new Color("rgba(20, 20, 20, 0.95)"), - "bg-editor": new Color("#18191c"), + "primary-bg": new Color("#555"), + "primary-border": new Color("#444"), + "primary-bg-active": new Color("#575757"), + "primary-bg-hover": new Color("#666"), + "navbar-bg": new Color("#3d3d3d"), + "navbar-bg-inactive": new Color("#626262"), + "window-bg": new Color("#3d3d3d"), + "window-border": new Color("#00000000"), + "secondary-bg": new Color("#373737"), + "secondary-border": new Color("#333"), + "secondary-bg-active": new Color("#555"), + "secondary-bg-hover": new Color("#454545"), + "editable-overlay-hover": new Color("rgb(255, 255, 255, 0.1)"), + "editable-overlay-active": new Color("rgb(255, 255, 255, 0.2)"), + "input-bg": new Color("rgba(35, 35, 35, 0.309)"), + "input-bg-active": new Color("rgba(50, 50, 50, 0.309)"), + "input-bg-hover": new Color("rgba(79, 79, 79, 0.309)"), + "input-border": new Color("rgba(0, 0, 0, 0.3)"), + "widget-bg": new Color("rgba(0, 0, 0, 0.5)"), + "tooltip-bg": new Color("rgba(20, 20, 20, 0.95)"), + "editor-bg": new Color("#18191c"), }, amethyst: { "accent-color": new Color("rgb(23, 131, 208)"), @@ -102,25 +351,27 @@ export const DEFAULT_THEMES: Record = { "text-color-secondary": new Color("#e4b3ff78"), "text-color-detail": new Color("#e4b3ff45"), "text-color-disabled": new Color("#e4b3ff87"), - "bg-primary": new Color("#3a1a75ff"), - "bg-primary-border": new Color("#3f1c80ba"), - "bg-primary-active": new Color("#3f1c80ff"), - "bg-primary-hover": new Color("#4b2198ff"), - "bg-window": new Color("#341769ff"), - "bg-window-inactive": new Color("#220f46ff"), - "bg-secondary": new Color("#2e145dff"), - "bg-secondary-border": new Color("#321666ba"), - "bg-secondary-active": new Color("#321666ff"), - "bg-secondary-hover": new Color("#3b1a78ff"), - "bg-editable-overlay": new Color("rgb(255, 255, 255, 0.1)"), - "bg-editable-overlay-active": new Color("rgb(255, 255, 255, 0.2)"), - "bg-input": new Color("rgba(35, 35, 35, 0.309)"), - "bg-input-active": new Color("rgba(50, 50, 50, 0.309)"), - "bg-input-hover": new Color("rgba(79, 79, 79, 0.309)"), - "bg-input-border": new Color("#58389378"), - "bg-widget": new Color("#08004387"), - "bg-tooltip": new Color("#341769ed"), - "bg-editor": new Color("#170a2e"), + "primary-bg": new Color("#3a1a75ff"), + "primary-border": new Color("#3f1c80ba"), + "primary-bg-active": new Color("#3f1c80ff"), + "primary-bg-hover": new Color("#4b2198ff"), + "navbar-bg": new Color("#341769ff"), + "navbar-bg-inactive": new Color("#220f46ff"), + "window-bg": new Color("#341769ff"), + "window-border": new Color("#00000000"), + "secondary-bg": new Color("#2e145dff"), + "secondary-border": new Color("#321666ba"), + "secondary-bg-active": new Color("#321666ff"), + "secondary-bg-hover": new Color("#3b1a78ff"), + "editable-overlay-hover": new Color("rgb(255, 255, 255, 0.1)"), + "editable-overlay-active": new Color("rgb(255, 255, 255, 0.2)"), + "input-bg": new Color("rgba(35, 35, 35, 0.309)"), + "input-bg-active": new Color("rgba(50, 50, 50, 0.309)"), + "input-bg-hover": new Color("rgba(79, 79, 79, 0.309)"), + "input-border": new Color("#58389378"), + "widget-bg": new Color("#08004387"), + "tooltip-bg": new Color("#341769ed"), + "editor-bg": new Color("#170a2e"), }, nord: { "accent-color": new Color("rgb(23, 131, 208)"), @@ -128,50 +379,110 @@ export const DEFAULT_THEMES: Record = { "text-color-secondary": new Color("#d9dee878"), "text-color-detail": new Color("#d9dee845"), "text-color-disabled": new Color("#d9dee887"), - "bg-primary": new Color("#2e3440ff"), - "bg-primary-border": new Color("#323946ba"), - "bg-primary-active": new Color("#323946ff"), - "bg-primary-hover": new Color("#3b4353ff"), - "bg-window": new Color("#292e39ff"), - "bg-window-inactive": new Color("#2f333c"), - "bg-secondary": new Color("#242933ff"), - "bg-secondary-border": new Color("#272d38ba"), - "bg-secondary-active": new Color("#272d38ff"), - "bg-secondary-hover": new Color("#2e3542ff"), - "bg-editable-overlay": new Color("rgb(255, 255, 255, 0.1)"), - "bg-editable-overlay-active": new Color("rgb(255, 255, 255, 0.2)"), - "bg-input": new Color("rgba(35, 35, 35, 0.309)"), - "bg-input-active": new Color("rgba(50, 50, 50, 0.309)"), - "bg-input-hover": new Color("rgba(79, 79, 79, 0.309)"), - "bg-input-border": new Color("#4c525e78"), - "bg-widget": new Color("#00020e87"), - "bg-tooltip": new Color("#292e39ed"), - "bg-editor": new Color("#18191c"), + "primary-bg": new Color("#2e3440ff"), + "primary-border": new Color("#323946ba"), + "primary-bg-active": new Color("#323946ff"), + "primary-bg-hover": new Color("#3b4353ff"), + "navbar-bg": new Color("#292e39ff"), + "navbar-bg-inactive": new Color("#2f333c"), + "window-bg": new Color("#292e39ff"), + "window-border": new Color("#00000000"), + "secondary-bg": new Color("#242933ff"), + "secondary-border": new Color("#272d38ba"), + "secondary-bg-active": new Color("#272d38ff"), + "secondary-bg-hover": new Color("#2e3542ff"), + "editable-overlay-hover": new Color("rgb(255, 255, 255, 0.1)"), + "editable-overlay-active": new Color("rgb(255, 255, 255, 0.2)"), + "input-bg": new Color("rgba(35, 35, 35, 0.309)"), + "input-bg-active": new Color("rgba(50, 50, 50, 0.309)"), + "input-bg-hover": new Color("rgba(79, 79, 79, 0.309)"), + "input-border": new Color("#4c525e78"), + "widget-bg": new Color("#00020e87"), + "tooltip-bg": new Color("#292e39ed"), + "editor-bg": new Color("#18191c"), }, light: { - "accent-color": new Color("#ff5c74ff"), + "accent-color": new Color("#ff594cff"), "text-color": new Color("#000000ff"), "text-color-secondary": new Color("#00000078"), "text-color-detail": new Color("#00000045"), "text-color-disabled": new Color("#00000087"), - "bg-primary": new Color("#ffffffff"), - "bg-primary-border": new Color("#b5b5b5ff"), - "bg-primary-active": new Color("#ebebebff"), - "bg-primary-hover": new Color("#fff0f6ff"), - "bg-window": new Color("#edededff"), - "bg-window-inactive": new Color("#d1d1d1ff"), - "bg-secondary": new Color("#d9d9d9ff"), - "bg-secondary-border": new Color("#c7c7c7ff"), - "bg-secondary-active": new Color("#f0f0f0ff"), - "bg-secondary-hover": new Color("#e3e3e3ff"), - "bg-editable-overlay": new Color("#ff5c743d"), - "bg-editable-overlay-active": new Color("#ff5c7473"), - "bg-input": new Color("#ebebebff"), - "bg-input-active": new Color("#e0e0e0ff"), - "bg-input-hover": new Color("#ffffffff"), - "bg-input-border": new Color("#9e9e9eff"), - "bg-widget": new Color("#f7f7f7e5"), - "bg-tooltip": new Color("#ffffffff"), - "bg-editor": new Color("#cfcfcfff"), + "primary-bg": new Color("#ffffffff"), + "primary-border": new Color("#b5b5b5ff"), + "primary-bg-active": new Color("#ebebebff"), + "primary-bg-hover": new Color("#ffd4d1ff"), + "navbar-bg": new Color("#edededff"), + "navbar-bg-inactive": new Color("#d1d1d1ff"), + "window-bg": new Color("#edededff"), + "window-border": new Color("#00000000"), + "secondary-bg": new Color("#d9d9d9ff"), + "secondary-border": new Color("#c7c7c7ff"), + "secondary-bg-active": new Color("#f0f0f0ff"), + "secondary-bg-hover": new Color("#e3e3e3ff"), + "editable-overlay-hover": new Color("#ff594c3d"), + "editable-overlay-active": new Color("#ff594c73"), + "input-bg": new Color("#ebebebff"), + "input-bg-active": new Color("#e0e0e0ff"), + "input-bg-hover": new Color("#ffffffff"), + "input-border": new Color("#9e9e9eff"), + "widget-bg": new Color("#f7f7f7e5"), + "tooltip-bg": new Color("#ffffffff"), + "editor-bg": new Color("#cfcfcfff"), + }, + rust: { + "accent-color": new Color("#b37100ff"), + "text-color": new Color("#ffd7bdf2"), + "text-color-secondary": new Color("#ffd7bd78"), + "text-color-detail": new Color("#ffd7bd45"), + "text-color-disabled": new Color("#ffd7bd87"), + "primary-bg": new Color("#3c2e2aff"), + "primary-border": new Color("#42332eff"), + "primary-bg-active": new Color("#42332eff"), + "primary-bg-hover": new Color("#4e3c37ff"), + "navbar-bg": new Color("#362926ff"), + "navbar-bg-inactive": new Color("#241b19ff"), + "window-bg": new Color("#58413cff"), + "window-border": new Color("#00000000"), + "secondary-bg": new Color("#40302ba1"), + "secondary-border": new Color("#46352fff"), + "secondary-bg-active": new Color("#46352fff"), + "secondary-bg-hover": new Color("#533e38ff"), + "editable-overlay-hover": new Color("#ffffff1a"), + "editable-overlay-active": new Color("#ffffff33"), + "input-bg": new Color("#231515ff"), + "input-bg-active": new Color("#271717ff"), + "input-bg-hover": new Color("#2e1b1bff"), + "input-border": new Color("#5a4c48ff"), + "widget-bg": new Color("#311e1cff"), + "tooltip-bg": new Color("#362926ff"), + "editor-bg": new Color("#181211ff"), + }, + highcontrast: { + "accent-color": new Color("#00ccffff"), + "text-color": new Color("#ffffffff"), + "text-color-secondary": new Color("#ffffff79"), + "text-color-detail": new Color("#ffffff91"), + "text-color-disabled": new Color("#ffffff88"), + "primary-bg": new Color("#000000ff"), + "primary-border": new Color("#00ccffff"), + "primary-bg-active": new Color("#616161ff"), + "primary-bg-hover": new Color("#404040ff"), + "navbar-bg": new Color("#000000ff"), + "navbar-bg-inactive": new Color("#000000ff"), + "window-bg": new Color("#000000ff"), + "window-border": new Color("#00ccffff"), + "secondary-bg": new Color("#000000ff"), + "secondary-border": new Color("#00ccffff"), + "secondary-bg-active": new Color("#616161ff"), + "secondary-bg-hover": new Color("#404040ff"), + "editable-overlay-hover": new Color("#ffffff1a"), + "editable-overlay-active": new Color("#ffffff33"), + "input-bg": new Color("#000000ff"), + "input-bg-active": new Color("#616161ff"), + "input-bg-hover": new Color("#404040ff"), + "input-border": new Color("#00ccffff"), + "widget-bg": new Color("#000000ff"), + "tooltip-bg": new Color("#000000ff"), + "editor-bg": new Color("#000000ff"), }, } diff --git a/app/src/gui/element/NumberSpinner.ts b/app/src/gui/element/NumberSpinner.ts index 449042a8..a6f0e68f 100644 --- a/app/src/gui/element/NumberSpinner.ts +++ b/app/src/gui/element/NumberSpinner.ts @@ -1,6 +1,7 @@ import { clamp, roundDigit } from "../../util/Math" import { Options } from "../../util/Options" import { parseString } from "../../util/Util" +import { Icons } from "../Icons" export class NumberSpinner { view: HTMLDivElement @@ -72,6 +73,7 @@ export class NumberSpinner { const upButton = document.createElement("button") upButton.classList.add("spinner-up") + upButton.appendChild(Icons.getIcon("CHEVRON", 10)) upButton.tabIndex = -1 upButton.onclick = e => { let changeStep = step ?? Options.general.spinnerStep @@ -87,6 +89,7 @@ export class NumberSpinner { const downButton = document.createElement("button") downButton.classList.add("spinner-down") + downButton.appendChild(Icons.getIcon("CHEVRON", 10)) downButton.tabIndex = -1 downButton.onclick = e => { let changeStep = step ?? Options.general.spinnerStep diff --git a/app/src/gui/widget/BaseTimelineWidget.ts b/app/src/gui/widget/BaseTimelineWidget.ts index 2102ed13..29789eea 100644 --- a/app/src/gui/widget/BaseTimelineWidget.ts +++ b/app/src/gui/widget/BaseTimelineWidget.ts @@ -40,7 +40,7 @@ export class BaseTimelineWidget extends Widget { this.addChild(this.container) this.visible = false - assignTint(this.backing, "--bg-widget") + assignTint(this.backing, "--widget-bg") this.overlay.anchor.x = 0.5 this.overlay.anchor.y = 0 diff --git a/app/src/gui/widget/DebugWidget.ts b/app/src/gui/widget/DebugWidget.ts index f5cacee3..d4a1fcf4 100644 --- a/app/src/gui/widget/DebugWidget.ts +++ b/app/src/gui/widget/DebugWidget.ts @@ -87,7 +87,7 @@ export class DebugWidget extends Widget { this.fpsText.x = 5 this.fpsBg.y = -5 - assignTint(this.fpsBg, "--bg-widget") + assignTint(this.fpsBg, "--widget-bg") assignTint(this.fpsText, "--text-color") this.graphs.addChild( diff --git a/app/src/gui/widget/PlayInfoWidget.ts b/app/src/gui/widget/PlayInfoWidget.ts index 666a0e4c..978cfd6c 100644 --- a/app/src/gui/widget/PlayInfoWidget.ts +++ b/app/src/gui/widget/PlayInfoWidget.ts @@ -54,7 +54,7 @@ export class PlayInfoWidget extends Widget { this.visible = false this.background.addChild(this.backgroundRect) - assignTint(this.backgroundRect, "--bg-widget") + assignTint(this.backgroundRect, "--widget-bg") this.addChild(this.background) this.addChild(this.backgroundLines) this.eventMode = "static" diff --git a/app/src/gui/widget/PlaybackOptionsWidget.ts b/app/src/gui/widget/PlaybackOptionsWidget.ts index a5874ec3..31dfd7c9 100644 --- a/app/src/gui/widget/PlaybackOptionsWidget.ts +++ b/app/src/gui/widget/PlaybackOptionsWidget.ts @@ -586,7 +586,7 @@ export class PlaybackOptionsWidget extends Widget { createCheckbox(options: CheckboxOptions) { const item = document.createElement("div") - item.classList.add("po-checkbox") + item.classList.add("ico-checkbox") const update = (trigger = true) => { if (trigger) options.onChange(checkbox.currentValue) diff --git a/app/src/gui/widget/StatusWidget.ts b/app/src/gui/widget/StatusWidget.ts index 646fa0f4..7610ce53 100644 --- a/app/src/gui/widget/StatusWidget.ts +++ b/app/src/gui/widget/StatusWidget.ts @@ -494,7 +494,7 @@ export class StatusWidget extends Widget { }) sprite.scale.set(0.5) const bg = new Sprite(Texture.WHITE) - assignTint(bg, "--bg-widget") + assignTint(bg, "--widget-bg") bg.width = 48 bg.height = 48 bg.anchor.set(0.5) @@ -804,8 +804,8 @@ export class StatusWidget extends Widget { } const noteType = this.manager.chartManager.getEditingNoteType() - const hoverColor = getCSSColor("--bg-editable-overlay") - const activeColor = getCSSColor("--bg-editable-overlay-active") + const hoverColor = getCSSColor("--editable-overlay-hover") + const activeColor = getCSSColor("--editable-overlay-active") const emptyColor = new Color(hoverColor).setAlpha(0) this.noteArrows.forEach(arrow => { let color = diff --git a/app/src/gui/window/NewSongWindow.ts b/app/src/gui/window/NewSongWindow.ts index 4fcb44bd..6c770677 100644 --- a/app/src/gui/window/NewSongWindow.ts +++ b/app/src/gui/window/NewSongWindow.ts @@ -244,8 +244,7 @@ export class NewSongWindow extends Window { input.value = "" deleteButton.disabled = true } - const icon = Icons.getIcon("TRASH") - icon.style.height = "12px" + const icon = Icons.getIcon("TRASH", 12) deleteButton.appendChild(icon) container.appendChild(deleteButton) return container diff --git a/app/src/gui/window/SyncWindow.ts b/app/src/gui/window/SyncWindow.ts index 8760139f..6fe8623b 100644 --- a/app/src/gui/window/SyncWindow.ts +++ b/app/src/gui/window/SyncWindow.ts @@ -651,9 +651,9 @@ export class SyncWindow extends Window { this.lowestFinishedBlock++ } if (this.lowestFinishedBlock < MAX_BLOCKS) { - this.toggleButton.style.background = `linear-gradient(90deg, #265296 0 ${ + this.toggleButton.style.background = `linear-gradient(90deg, var(--accent-color) 0 ${ (this.lowestFinishedBlock / MAX_BLOCKS) * 100 - }%, rgb(83, 82, 82) ${ + }%, var(--input-bg) ${ (this.lowestFinishedBlock / MAX_BLOCKS) * 100 }% 100%)` @@ -1254,9 +1254,9 @@ export class SyncWindow extends Window { processBlock(++blockNum) } else { frameTime = performance.now() - this.toggleButton.style.background = `linear-gradient(90deg, #265296 0 ${ + this.toggleButton.style.background = `linear-gradient(90deg, var(--accent-color) 0 ${ (blockNum / MAX_BLOCKS) * 100 - }%, rgb(83, 82, 82) ${(blockNum / MAX_BLOCKS) * 100}% 100%)` + }%, var(--input-bg) ${(blockNum / MAX_BLOCKS) * 100}% 100%)` this.toggleButton.innerText = `Finding tempo (${roundDigit( (blockNum / MAX_BLOCKS) * 100, 1 @@ -1272,7 +1272,7 @@ export class SyncWindow extends Window { this.toggleButton.innerText = "Finished analyzing" this.resetButton.disabled = false this.doAnalysis = false - this.toggleButton.style.background = `#265296` + this.toggleButton.style.background = `var(--accent-color)` } } processBlock(0) diff --git a/app/src/gui/window/ThemeWindow.ts b/app/src/gui/window/ThemeWindow.ts index 7c5df625..1aea48dd 100644 --- a/app/src/gui/window/ThemeWindow.ts +++ b/app/src/gui/window/ThemeWindow.ts @@ -3,23 +3,23 @@ import tippy from "tippy.js" import { App } from "../../App" import { Theme, + THEME_GENERATOR_LINKS, + THEME_GROUPS, THEME_PROPERTY_DESCRIPTIONS, - THEME_VAR_WHITELIST, + ThemeGroup, ThemeProperty, } from "../../data/ThemeData" import { add, lighten } from "../../util/Color" import { EventHandler } from "../../util/EventHandler" import { Themes } from "../../util/Theme" +import { Icons } from "../Icons" import { Window } from "./Window" export class ThemeWindow extends Window { app: App private handlers: ((...args: any[]) => void)[] = [] - private generatorOptions: Partial = { - "text-color": new Color("white"), - "bg-primary": new Color("#444"), - } + private linkBlacklist = new Set() constructor(app: App) { super({ @@ -38,26 +38,36 @@ export class ThemeWindow extends Window { const padding = document.createElement("div") padding.classList.add("padding") - const generatorGrid = document.createElement("div") - generatorGrid.classList.add("theme-generator-grid") - for (const p of ["bg-primary", "text-color"] as const) { - generatorGrid.appendChild(this.createGenerator(p)) - } - const colorGrid = document.createElement("div") colorGrid.classList.add("theme-color-grid") - for (const p of THEME_VAR_WHITELIST) { - colorGrid.appendChild(this.createPicker(p)) - } - padding.appendChild(generatorGrid) + THEME_GROUPS.forEach(g => { + colorGrid.appendChild(this.createGroup(g)) + }) + padding.appendChild(colorGrid) + this.viewElement.appendChild(padding) } - createGenerator(id: ThemeProperty) { + createGroup(group: ThemeGroup) { + const container = document.createElement("div") + container.classList.add("theme-group") + const title = document.createElement("div") + title.classList.add("theme-group-label") + title.innerText = group.name + const pickerGrid = document.createElement("div") + pickerGrid.classList.add("theme-picker-grid") + group.ids.forEach(i => { + pickerGrid.appendChild(this.createPicker(i)) + }) + container.replaceChildren(title, pickerGrid) + return container + } + + createPicker(opt: { id: ThemeProperty; label: string }) { const updateValue = () => { - const c = new Color(this.generatorOptions[id] ?? "black") + const c = new Color(Themes.getCurrentTheme()[opt.id]) colorLabel.innerText = c.toHex() + " | " + Math.round(c.alpha * 100) + "%" if (document.activeElement == colorInput) return colorInput.value = c.toHex() @@ -65,23 +75,23 @@ export class ThemeWindow extends Window { } const setValue = () => { - const newTheme = this.generatorOptions + const newTheme = Themes.getCurrentTheme() const color = new Color(colorInput.value) color.setAlpha(parseFloat(alphaInput.value)) - newTheme[id] = color - this.generatePalette() + newTheme[opt.id] = color + Themes._applyTheme(this.updateLinks(opt.id, newTheme)) } const container = document.createElement("div") container.classList.add("theme-color-cell") - if (THEME_PROPERTY_DESCRIPTIONS[id] != "") + if (THEME_PROPERTY_DESCRIPTIONS[opt.id] != "") tippy(container, { - content: THEME_PROPERTY_DESCRIPTIONS[id], + content: THEME_PROPERTY_DESCRIPTIONS[opt.id], }) const label = document.createElement("div") - label.innerText = id + label.innerText = opt.label const colorLabel = document.createElement("div") colorLabel.classList.add("theme-color-detail") @@ -99,67 +109,63 @@ export class ThemeWindow extends Window { alphaInput.oninput = setValue alphaInput.onblur = updateValue - updateValue() - container.replaceChildren(label, colorLabel, colorInput, alphaInput) - return container - } - - createPicker(id: ThemeProperty) { - const updateValue = () => { - const c = new Color(Themes.getCurrentTheme()[id]) - colorLabel.innerText = c.toHex() + " | " + Math.round(c.alpha * 100) + "%" - if (document.activeElement == colorInput) return - colorInput.value = c.toHex() - alphaInput.value = c.alpha.toString() - } - - const setValue = () => { - const newTheme = Themes.getCurrentTheme() - const color = new Color(colorInput.value) - color.setAlpha(parseFloat(alphaInput.value)) - newTheme[id] = color - Themes._applyTheme(newTheme) - } + if (this.hasLink(opt.id)) { + const link = document.createElement("div") + link.classList.add("ico-checkbox") + const on = Icons.getIcon("LINK", 12) + const off = Icons.getIcon("LINK_BROKEN", 12) + + let currentValue = true + + const update = () => { + if (currentValue) { + this.linkBlacklist.delete(opt.id) + } else { + this.linkBlacklist.add(opt.id) + } + on.style.display = currentValue ? "" : "none" + off.style.display = currentValue ? "none" : "" + } - const container = document.createElement("div") - container.classList.add("theme-color-cell") + link.onclick = () => { + currentValue = !currentValue + update() + } - if (THEME_PROPERTY_DESCRIPTIONS[id] != "") - tippy(container, { - content: THEME_PROPERTY_DESCRIPTIONS[id], - }) + update() - const label = document.createElement("div") - label.innerText = id + link.replaceChildren(on, off) - const colorLabel = document.createElement("div") - colorLabel.classList.add("theme-color-detail") + container.appendChild(link) - const colorInput = document.createElement("input") - colorInput.type = "color" - colorInput.oninput = setValue - colorInput.onblur = updateValue + const newSetInput = () => { + if (currentValue) { + currentValue = false + update() + } + setValue() + } - const alphaInput = document.createElement("input") - alphaInput.type = "range" - alphaInput.min = "0" - alphaInput.max = "1" - alphaInput.step = "0.001" - alphaInput.oninput = setValue - alphaInput.onblur = updateValue + colorInput.oninput = newSetInput + alphaInput.oninput = newSetInput + } updateValue() - container.replaceChildren(label, colorLabel, colorInput, alphaInput) - EventHandler.on("themeChanged", updateValue) this.handlers.push(updateValue) return container } + hasLink(id: ThemeProperty) { + return Object.values(THEME_GENERATOR_LINKS) + .flatMap(links => Object.keys(links)) + .includes(id) + } + average(c: Color) { return (c.red + c.green + c.blue) / 3 } @@ -172,51 +178,21 @@ export class ThemeWindow extends Window { return new Color(add(new Color(color).toNumber(), gamma)) } - generatePalette() { - const modifiers = { - border: (c: Color) => this.lighten(c, 10).setAlpha(0xbb), - active: (c: Color) => this.lighten(c, 10), - hover: (c: Color) => this.lighten(c, 30), - } - const theme: Partial = { ...this.generatorOptions } - - theme["text-color"] ||= - this.average(theme["bg-primary"]!) > 0.5 - ? new Color("#000") - : new Color("#fff") - theme["bg-input-border"] ||= - this.average(theme["bg-primary"]!) > 0.5 - ? this.add(theme["bg-primary"]!, -30).setAlpha(0x77) - : this.add(theme["bg-primary"]!, +30).setAlpha(0x77) - theme["bg-tooltip"] ||= this.lighten(theme["bg-primary"]!, -10).setAlpha( - 0xee - ) - theme["bg-secondary"] ||= this.lighten(theme["bg-primary"]!, -20) - theme["bg-editor"] = - theme["bg-editor"] ?? this.lighten(theme["bg-primary"]!, -60) - theme["text-color-secondary"] = new Color(theme["text-color"]).setAlpha( - 0x77 / 0xff - ) - theme["text-color-detail"] = new Color(theme["text-color"]).setAlpha( - 0x44 / 0xff - ) - theme["text-color-disabled"] = new Color(theme["text-color"]).setAlpha( - 0x88 / 0xff - ) - for (const type of ["primary", "secondary"] as const) { - for (const [mod, func] of Object.entries(modifiers)) { - theme[`bg-${type}-${mod as "border" | "active" | "hover"}`] = func( - theme[`bg-${type}`]! - ) + updateLinks(updatedId: ThemeProperty, theme: Theme) { + const visited = new Set() + const queue: ThemeProperty[] = [updatedId] + while (queue.length != 0) { + const currentId = queue.shift()! + const links = THEME_GENERATOR_LINKS[currentId] + if (!links) continue + for (const [id, transform] of Object.entries(links)) { + if (this.linkBlacklist.has(id as ThemeProperty)) continue + if (visited.has(id)) continue + theme[id as ThemeProperty] = transform.bind(this)(theme[currentId]) + queue.push(id as ThemeProperty) + visited.add(id) } } - theme["bg-window"] = this.lighten(theme["bg-primary"]!, -10) - theme["bg-window-inactive"] = this.lighten(theme["bg-primary"]!, -40) - theme["bg-widget"] = this.add(theme["bg-primary"]!, -50).setAlpha(0x88) - Themes._applyTheme(theme as Theme) - } - - onClose(): void { - this.handlers.forEach(h => EventHandler.off("themeChanged", h)) + return theme } } diff --git a/public/assets/svg/LINK.svg b/public/assets/svg/LINK.svg new file mode 100644 index 00000000..7d0230b1 --- /dev/null +++ b/public/assets/svg/LINK.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/svg/LINK_BROKEN.svg b/public/assets/svg/LINK_BROKEN.svg new file mode 100644 index 00000000..e6c52cac --- /dev/null +++ b/public/assets/svg/LINK_BROKEN.svg @@ -0,0 +1,8 @@ + + + + + + + +