commit 581e404edfadbe1855feb39eca53277936024bb5 Author: Bruce Leidl Date: Tue Nov 12 17:12:37 2024 -0500 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3490a1e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/subprojects/blueprint-compiler +/node_modules +/build +/install diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..685fbd0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "gi-types"] + path = gi-types + url = https://gitlab.gnome.org/BrainBlasted/gi-typescript-definitions.git diff --git a/data/com.subgraph.citadel.Realms.data.gresource.xml b/data/com.subgraph.citadel.Realms.data.gresource.xml new file mode 100644 index 0000000..1db9946 --- /dev/null +++ b/data/com.subgraph.citadel.Realms.data.gresource.xml @@ -0,0 +1,20 @@ + + + + ui/RealmListItem.ui + ui/RealmRow.ui + ui/RealmsView.ui + ui/RealmInfo.ui + ui/RealmInfoEntry.ui + ui/Window.ui + ui/ConfigureRealm.ui + ui/ConfigureOption.ui + ui/ColorSchemeChooser.ui + ui/ColorSchemeListItem.ui + ui/HelpWindow.ui + css/style.css + dbus-interfaces/com.subgraph.realms.Manager2.xml + dbus-interfaces/com.subgraph.realms.Realm.xml + dbus-interfaces/com.subgraph.realms.RealmFS.xml + + diff --git a/data/com.subgraph.citadel.Realms.desktop b/data/com.subgraph.citadel.Realms.desktop new file mode 100644 index 0000000..fedaa60 --- /dev/null +++ b/data/com.subgraph.citadel.Realms.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Name=Realms +Type=Application +Exec=com.subgraph.citadel.Realms +Terminal=false +Icon=com.subgraph.citadel.Realms diff --git a/data/css/style.css b/data/css/style.css new file mode 100644 index 0000000..3bec583 --- /dev/null +++ b/data/css/style.css @@ -0,0 +1,10 @@ + +welcome { + border-spacing: 18px; + margin: 36px; +} + +welcome.big > label { + font-size: 1.4em; + font-weight: bold; +} diff --git a/data/dbus-interfaces/com.subgraph.realms.Manager2.xml b/data/dbus-interfaces/com.subgraph.realms.Manager2.xml new file mode 100644 index 0000000..bcab568 --- /dev/null +++ b/data/dbus-interfaces/com.subgraph.realms.Manager2.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/data/dbus-interfaces/com.subgraph.realms.Realm.xml b/data/dbus-interfaces/com.subgraph.realms.Realm.xml new file mode 100644 index 0000000..0703b78 --- /dev/null +++ b/data/dbus-interfaces/com.subgraph.realms.Realm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/dbus-interfaces/com.subgraph.realms.RealmFS.xml b/data/dbus-interfaces/com.subgraph.realms.RealmFS.xml new file mode 100644 index 0000000..0822e5f --- /dev/null +++ b/data/dbus-interfaces/com.subgraph.realms.RealmFS.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/data/icons/com.subgraph.Realms.png b/data/icons/com.subgraph.Realms.png new file mode 100644 index 0000000..12c7538 Binary files /dev/null and b/data/icons/com.subgraph.Realms.png differ diff --git a/data/meson.build b/data/meson.build new file mode 100644 index 0000000..3e063a8 --- /dev/null +++ b/data/meson.build @@ -0,0 +1,30 @@ +blueprints = custom_target('blueprints', + input: files( + 'ui/Window.blp', + 'ui/RealmListItem.blp', + 'ui/RealmRow.blp', + 'ui/RealmsView.blp', + 'ui/RealmInfo.blp', + 'ui/RealmInfoEntry.blp', + 'ui/ConfigureOption.blp', + 'ui/ConfigureRealm.blp', + 'ui/ColorSchemeChooser.blp', + 'ui/ColorSchemeListItem.blp', + 'ui/HelpWindow.blp', + ), + output: '.', + command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'], +) + +gnome.compile_resources( + APP_ID + '.data', + APP_ID + '.data.gresource.xml', + gresource_bundle: true, + install: true, + install_dir: get_option('datadir') / APP_ID, + dependencies: blueprints, +) + +install_data('icons/com.subgraph.Realms.png', install_dir: join_paths(get_option('datadir'), 'icons/hicolor/512x512/apps')) + + diff --git a/data/ui/ColorSchemeChooser.blp b/data/ui/ColorSchemeChooser.blp new file mode 100644 index 0000000..dfed4eb --- /dev/null +++ b/data/ui/ColorSchemeChooser.blp @@ -0,0 +1,35 @@ + +using Gtk 4.0; +using Adw 1; + +template $ColorSchemeChooser: Adw.NavigationPage { + title: "Choose Color Scheme"; + tag: "realm-colorscheme"; + Adw.ToolbarView { + [top] + Adw.HeaderBar {} + content : Paned { + + position: 200; + + ScrolledWindow { + styles ["sidebar"] + + child: ListView colorList { + tab-behavior: item; + + styles ["navigation-sidebar"] + factory: Gtk.BuilderListItemFactory { + resource: "/com/subgraph/citadel/Realms/ui/ColorSchemeListItem.ui"; + }; + }; + } + + Label previewLabel { + use-markup: true; + xalign: 0; + yalign: 0; + } + }; + } +} diff --git a/data/ui/ColorSchemeListItem.blp b/data/ui/ColorSchemeListItem.blp new file mode 100644 index 0000000..c063abf --- /dev/null +++ b/data/ui/ColorSchemeListItem.blp @@ -0,0 +1,13 @@ +using Gtk 4.0; + +template Gtk.ListItem { + focusable: false; + child: Gtk.TreeExpander expander { + list-row: bind (template.item) as ; + child: Label { + hexpand: true; + halign: start; + label: bind expander.item as <$ColorSchemeNode>.text; + }; + }; +} diff --git a/data/ui/ConfigureDialog.blp b/data/ui/ConfigureDialog.blp new file mode 100644 index 0000000..3a3e2e5 --- /dev/null +++ b/data/ui/ConfigureDialog.blp @@ -0,0 +1,84 @@ +using Gtk 4.0; +using Adw 1; + +ColorDialog colorDialog { + title: "Choose a window label color"; + modal: true; + with-alpha: false; +} + + +template $ConfigureDialog: Adw.Dialog { + title: "Configure Realm"; + content-width: 640; + styles ["preferences"] + + child: Adw.NavigationView navigationView { + + Adw.NavigationPage { + title: bind template.title; + Adw.ToolbarView { + [top] + Adw.Banner changedBanner { + title: "Realm configuration has changed."; + button-label: "Apply"; + button-clicked => $_onApplyClicked(); + } + + Adw.PreferencesPage { + Adw.PreferencesGroup optionsGroup { + title: "Options"; + } + Adw.PreferencesGroup { + title: "Other"; + + Adw.ComboRow overlayCombo { + title: "Overlay"; + model: StringList { + strings [ + "Storage", + "TmpFS", + "None", + ] + }; + } + + Adw.ComboRow realmfsCombo { + title: "RealmFS"; + model: StringList { + strings [] + }; + } + + Adw.ActionRow { + title: "Color Scheme"; + activatable-widget: colorSchemeButton; + [suffix] + Button colorSchemeButton { + can-focus: false; + label: "Default Dark"; + } + } + + Adw.ActionRow { + title: "Window Label Color"; + activatable-widget: labelColorButton; + + [suffix] + ColorDialogButton labelColorButton { + can-focus: false; + dialog: colorDialog; + rgba: "#ffff00000000"; + } + } + + } // Adw.PreferencesGroup ("Other") + } // Adw.PreferencesPage + } // Adw.ToolbarView + } // Adw.NavigationPage + + + }; // Adw.NavigationView +} // $ConfigureDialog + + diff --git a/data/ui/ConfigureOption.blp b/data/ui/ConfigureOption.blp new file mode 100644 index 0000000..b2ee517 --- /dev/null +++ b/data/ui/ConfigureOption.blp @@ -0,0 +1,23 @@ +using Gtk 4.0; + +/* +template $ConfigureOption: ListBoxRow { + width-request: 100; + activatable: false; + selectable: false; + + child: Box { + margin-bottom: 5; + spacing: 30; + + Label name { + hexpand: true; + halign: start; + } + + Switch switch { + halign: end; + } + }; +} +*/ diff --git a/data/ui/ConfigureRealm.blp b/data/ui/ConfigureRealm.blp new file mode 100644 index 0000000..2ea118d --- /dev/null +++ b/data/ui/ConfigureRealm.blp @@ -0,0 +1,75 @@ +using Gtk 4.0; +using Adw 1; + + +ColorDialog colorDialog { + title: "Choose a window label color"; + modal: true; + with-alpha: false; +} + +template $ConfigureRealm: Adw.NavigationPage { + title: "Realm Config"; + tag: "realm-config"; + + Adw.ToolbarView { + [top] + Adw.HeaderBar {} + [top] + Adw.Banner changedBanner { + title: "Realm configuration has changed."; + button-label: "Apply"; + button-clicked => $_onApplyClicked(); + } + + content: Adw.PreferencesPage { + Adw.PreferencesGroup optionsGroup { + title: "Options"; + } + + Adw.PreferencesGroup { + title: "Other"; + Adw.ComboRow overlayCombo { + title: "Overlay"; + model: StringList { + strings [ + "Storage", + "TmpFS", + "None", + ] + }; + } + + Adw.ComboRow realmfsCombo { + title: "RealmFS"; + model: StringList { + strings [] + }; + } + + Adw.ActionRow { + title: "Color Scheme"; + activatable-widget: colorSchemeButton; + [suffix] + Button colorSchemeButton { + can-focus: false; + label: "Default Dark"; + } + } + + Adw.ActionRow { + title: "Window Label Color"; + activatable-widget: labelColorButton; + + [suffix] + ColorDialogButton labelColorButton { + can-focus: false; + dialog: colorDialog; + rgba: "#ffff00000000"; + } + } + } // Adw.PreferencesGroup ("Other") + + }; // Adw.PreferencesPage + } // Adw.ToolbarView +} // $ConfigureRealm diff --git a/data/ui/HelpWindow.blp b/data/ui/HelpWindow.blp new file mode 100644 index 0000000..32ca1f9 --- /dev/null +++ b/data/ui/HelpWindow.blp @@ -0,0 +1,39 @@ +using Gtk 4.0; + +ShortcutsWindow helpWindow { + modal: true; + can-focus: false; + + ShortcutsSection { + ShortcutsGroup { + title: "General"; + + ShortcutsShortcut { + accelerator: "Up k"; + title: "Previous / Up"; + } + ShortcutsShortcut { + accelerator: "Down j"; + title: "Next / Down"; + } + + ShortcutsShortcut { + accelerator: "h question"; + title: "Display keyboard help"; + } + ShortcutsShortcut { + accelerator: "q"; + title: "Quit"; + } + } + ShortcutsGroup { + title: "Realm"; + + ShortcutsShortcut { + accelerator: "c"; + title: "Configure selected Realm"; + } + } + } + +} diff --git a/data/ui/RealmInfo.blp b/data/ui/RealmInfo.blp new file mode 100644 index 0000000..6aced83 --- /dev/null +++ b/data/ui/RealmInfo.blp @@ -0,0 +1,25 @@ +using Gtk 4.0; + +template $RealmInfo: ScrolledWindow { + Box { + orientation: horizontal; + margin-bottom: 18; + margin-top: 18; + margin-start: 18; + margin-end: 18; + + Box column { + orientation: vertical; + spacing: 12; + hexpand: true; + + Label columnTitle { + label: "Realm"; + halign: start; + + styles [ "title-2" ] + } + + } + } +} diff --git a/data/ui/RealmInfoEntry.blp b/data/ui/RealmInfoEntry.blp new file mode 100644 index 0000000..e7320b4 --- /dev/null +++ b/data/ui/RealmInfoEntry.blp @@ -0,0 +1,19 @@ +using Gtk 4.0; + +template $RealmInfoEntry: Box { + orientation: vertical; + Label nameLabel { + halign: start; + styles [ + "dim-label", + "caption", + ] + } + + Label valueLabel { + halign: start; + wrap: true; + xalign: 0; + use-markup: true; + } +} diff --git a/data/ui/RealmListItem.blp b/data/ui/RealmListItem.blp new file mode 100644 index 0000000..cdcfe3f --- /dev/null +++ b/data/ui/RealmListItem.blp @@ -0,0 +1,7 @@ +using Gtk 4.0; + +template Gtk.ListItem { + child: $RealmRow { + realm: bind template.item; + }; +} diff --git a/data/ui/RealmRow.blp b/data/ui/RealmRow.blp new file mode 100644 index 0000000..6346286 --- /dev/null +++ b/data/ui/RealmRow.blp @@ -0,0 +1,15 @@ +using Gtk 4.0; + +template $RealmRow { + layout-manager: BoxLayout { + orientation: horizontal; + }; + Label nameLabel { + xalign: 0; + label: bind template.realm as <$Realm>.name; + styles [ + "heading", + "dim-label", + ] + } +} diff --git a/data/ui/RealmsView.blp b/data/ui/RealmsView.blp new file mode 100644 index 0000000..8ca608b --- /dev/null +++ b/data/ui/RealmsView.blp @@ -0,0 +1,39 @@ +using Gtk 4.0; + +template $RealmsView { + selected-realm: bind realmsSelection.selected-item; + layout-manager: BinLayout {}; + Frame { + width-request: 200; + [label] + Label { + margin-start: 10; + margin-top: 20; + styles ["title-4"] + label: "Realms"; + } + + ScrolledWindow { + child: ListView { + styles ["navigation-sidebar"] + margin-start: 20; + margin-end: 20; + margin-top: 10; + show-separators: true; + focusable: false; + can-focus: false; + model: SingleSelection realmsSelection { + model: FilterListModel hiddenRealmsFilterModel { + model: SortListModel { + model: $RealmModel{}; + sorter: CustomSorter realmSorter {}; + }; + }; + }; + factory: BuilderListItemFactory { + resource: "/com/subgraph/citadel/Realms/ui/RealmListItem.ui"; + }; + }; + } + } +} diff --git a/data/ui/Window.blp b/data/ui/Window.blp new file mode 100644 index 0000000..8700de5 --- /dev/null +++ b/data/ui/Window.blp @@ -0,0 +1,60 @@ +using Gtk 4.0; +using Adw 1; + +menu menu { + section { + item { + action: "app.about"; + label: "About Realms"; + } + } +} +template $RealmsWindow : Adw.ApplicationWindow { + default-width: 1000; + default-height: 640; + + /* 'width-request and 'height-request' declare minimum window size */ + width-request: 400; + height-request: 300; + + title: "Realms"; + + Adw.NavigationView navView { + + Adw.NavigationPage { + title: "Realms"; + tag: "main"; + Adw.ToolbarView { + [top] + Adw.HeaderBar header { + title-widget: Adw.WindowTitle { + title: "Realms"; + }; + [end] + MenuButton { + can-focus: false; + primary: true; + menu-model: menu; + icon-name: "open-menu-symbolic"; + } + } + content: Paned { + resize-end-child: true; + resize-start-child: false; + shrink-start-child: false; + $RealmsView realmsView {} + $RealmInfo { + realm: bind realmsView.selected-realm; + } + }; + } + } + + $ConfigureRealm configureRealm { + navigation-view: navView; + colorscheme-chooser: colorChooser; + } + + $ColorSchemeChooser colorChooser {} + } +} diff --git a/gi-types b/gi-types new file mode 160000 index 0000000..dbbaa05 --- /dev/null +++ b/gi-types @@ -0,0 +1 @@ +Subproject commit dbbaa0527556cd3ce5434c4a5072cd99348eff7a diff --git a/js/Application.js b/js/Application.js new file mode 100644 index 0000000..4be7253 --- /dev/null +++ b/js/Application.js @@ -0,0 +1,89 @@ +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _Application_instances, _a, _Application_setupAccelerators, _Application_setupActions, _Application_onQuit, _Application_onRealmConfig, _Application_onShowHelp, _Application_onAbout; +import Adw from 'gi://Adw'; +import Gtk from 'gi://Gtk?version=4.0'; +import Gio from 'gi://Gio'; +import GObject from 'gi://GObject'; +import './model/RealmManager.js'; +import './model/Realm.js'; +import './RealmsView.js'; +import './RealmRow.js'; +import './RealmInfo.js'; +import './RealmModel.js'; +import './ConfigureRealm.js'; +import { Window } from './Window.js'; +export class Application extends Adw.Application { + constructor() { + super({ + application_id: 'com.subgraph.citadel.Realms', + flags: Gio.ApplicationFlags.DEFAULT_FLAGS, + }); + _Application_instances.add(this); + } + vfunc_activate() { + let { activeWindow } = this; + if (!activeWindow) { + activeWindow = new Window(this); + activeWindow.set_hide_on_close(true); + } + activeWindow.present(); + } + vfunc_startup() { + super.vfunc_startup(); + __classPrivateFieldGet(this, _Application_instances, "m", _Application_setupActions).call(this); + __classPrivateFieldGet(this, _Application_instances, "m", _Application_setupAccelerators).call(this); + // this.#loadStyleSheet(); + const styleManager = Adw.StyleManager.get_default(); + styleManager.colorScheme = Adw.ColorScheme.FORCE_DARK; + } +} +_a = Application, _Application_instances = new WeakSet(), _Application_setupAccelerators = function _Application_setupAccelerators() { + this.set_accels_for_action('app.quit', ['q']); + this.set_accels_for_action('app.realmConfig', ['c']); + this.set_accels_for_action('app.showHelp', ['h', 'question']); +}, _Application_setupActions = function _Application_setupActions() { + this.add_action_entries([ + // @ts-ignore + { name: 'quit', activate: __classPrivateFieldGet(this, _Application_instances, "m", _Application_onQuit).bind(this) }, + // @ts-ignore + { name: 'realmConfig', activate: __classPrivateFieldGet(this, _Application_instances, "m", _Application_onRealmConfig).bind(this) }, + // @ts-ignore + { name: 'showHelp', activate: __classPrivateFieldGet(this, _Application_instances, "m", _Application_onShowHelp).bind(this) }, + // @ts-ignore + { name: 'about', activate: __classPrivateFieldGet(this, _Application_instances, "m", _Application_onAbout).bind(this) }, + ]); +}, _Application_onQuit = function _Application_onQuit() { + let { activeWindow } = this; + if (activeWindow) { + activeWindow.close(); + } +}, _Application_onRealmConfig = function _Application_onRealmConfig() { + let { activeWindow } = this; + if (activeWindow) { + let window = activeWindow; + const realm = window.realms_view.selectedRealm; + if (realm) { + window.configureRealm(realm); + } + } +}, _Application_onShowHelp = function _Application_onShowHelp() { + const help = Gtk.Builder.new_from_resource('/com/subgraph/citadel/Realms/ui/HelpWindow.ui').get_object('helpWindow'); + help.set_transient_for(this._window); + help.present(); +}, _Application_onAbout = function _Application_onAbout() { + const dialog = new Adw.AboutDialog({ + application_icon: 'face-smile', + application_name: 'Realms', + developer_name: "Subgraph", + }); + dialog.present(this._window); +}; +(() => { + GObject.registerClass({ + GTypeName: 'RealmsApplication' + }, _a); +})(); diff --git a/js/ColorSchemeChooser.js b/js/ColorSchemeChooser.js new file mode 100644 index 0000000..4a86e94 --- /dev/null +++ b/js/ColorSchemeChooser.js @@ -0,0 +1,176 @@ +var _a; +import Adw from 'gi://Adw'; +import GObject from 'gi://GObject'; +import GLib from 'gi://GLib'; +import Gdk from 'gi://Gdk?version=4.0'; +import Gtk from 'gi://Gtk?version=4.0'; +import { ColorSchemeModel } from './ColorSchemeModel.js'; +class PreviewRenderer { + constructor(theme) { + this.theme = theme; + this.buffer = ''; + } + colorAttrib(name, color) { + this.buffer += ` ${name}='${color}'`; + } + colorSpan(fg, bg = null) { + this.buffer += '').nl() + .func('#include ').string('').nl() + .nl() + .vtype('static char').text(' theme[] = ').string(`"${name}"`).text(';').nl() + .nl() + .vtype('int').text(' main(').vtype('int').text(' argc, ').vtype('char').text(' **argv) {').nl() + .text(' printf(').string('"Hello, ').keyword('%s').text('!').keyword('\\n').string('"').text(', theme);').nl() + .text(' exit(').konst('0').text(');').nl() + .text('}') + .nl(); + return this.buffer; + } +} +export class ColorSchemeChooser extends Adw.NavigationPage { + addExpandToggleShortcut(keyval) { + let trigger = Gtk.KeyvalTrigger.new(keyval, Gdk.ModifierType.NO_MODIFIER_MASK); + let action = Gtk.CallbackAction.new((expander) => expander.activate_action('listitem.toggle-expand', null)); + Gtk.TreeExpander.add_shortcut(Gtk.Shortcut.new(trigger, action)); + } + constructor() { + super(); + this.model = new ColorSchemeModel(); + this._previewLabel.add_css_class("preview"); + this.css_provider = new Gtk.CssProvider(); + const display = Gdk.Display.get_default(); + if (display) { + Gtk.StyleContext.add_provider_for_display(display, this.css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + } + this.addExpandToggleShortcut(Gdk.KEY_space); + this.addExpandToggleShortcut(Gdk.KEY_l); + this._colorList.connect('activate', () => { + this.previewSelectedTheme(); + }); + this._colorList.single_click_activate = true; + this._colorList.model = this.model.selection; + const keyController = new Gtk.EventControllerKey(); + keyController.connect('key-pressed', (_, keyval) => { + switch (keyval) { + case Gdk.KEY_j: + case Gdk.KEY_Down: + this.nextScheme(); + break; + case Gdk.KEY_k: + case Gdk.KEY_Up: + this.prevScheme(); + break; + } + }); + this._colorList.add_controller(keyController); + } + nextScheme() { + let pos = this.model.changeSelected(1); + if (pos) { + this._colorList.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, null); + } + } + prevScheme() { + let pos = this.model.changeSelected(-1); + if (pos) { + this._colorList.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, null); + } + } + selectTheme(id) { + const DEFAULT_THEME = '3024'; + let row = this.model.searchId(id !== null && id !== void 0 ? id : DEFAULT_THEME); + if (row) { + let pos = row.get_position(); + this.model.selectPosition(pos); + this._colorList.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, null); + this.previewSelectedTheme(); + } + } + getSelectedTheme() { + return this.model.selectedTheme(); + } + previewSelectedTheme() { + let theme = this.model.selectedTheme(); + if (theme) { + this.setBackgroundColor(theme); + let renderer = new PreviewRenderer(theme); + // @ts-ignore + this._previewLabel.label = renderer.renderPreview(); + } + } + setBackgroundColor(theme) { + let css = ` +label.preview { + background-color: ${theme.terminal_background()}; + font-family: monospace; + font-size: 14pt; +}`; + this.css_provider.load_from_string(css); + } +} +_a = ColorSchemeChooser; +(() => { + GObject.registerClass({ + GTypeName: 'ColorSchemeChooser', + Template: 'resource:///com/subgraph/citadel/Realms/ui/ColorSchemeChooser.ui', + InternalChildren: ['colorList', 'previewLabel'], + }, _a); +})(); diff --git a/js/ColorSchemeModel.js b/js/ColorSchemeModel.js new file mode 100644 index 0000000..7ce3f64 --- /dev/null +++ b/js/ColorSchemeModel.js @@ -0,0 +1,147 @@ +var _a; +import GObject from 'gi://GObject'; +import Gio from 'gi://Gio'; +import Gtk from 'gi://Gtk?version=4.0'; +import { Base16Theme } from './model/Base16Themes.js'; +class ModelBuilder { + constructor() { + this.CATEGORIES = [ + ['atelier', 'Atelier'], + ['black-metal', 'Black Metal'], + ['brushtrees', 'Brush Trees'], + ['classic', 'Classic'], + ['default', 'Default'], + ['google', 'Google'], + ['grayscale', 'Grayscale'], + ['gruvbox', 'Gruvbox'], + ['harmonic', 'Harmonic'], + ['ia', 'iA'], + ['material', 'Material'], + ['papercolor', 'PaperColor'], + ['solarized', 'Solarized'], + ['summerfruit', 'Summerfruit'], + ['tomorrow', 'Tomorrow'], + ['unikitty', 'Unikitty'], + ]; + this.currentCategory = null; + this.storeModel = new Gio.ListStore(ColorSchemeNode); + } + matchesCategory(theme) { + return (this.CATEGORIES.length > 0 && theme.id.startsWith(this.CATEGORIES[0][0])); + } + appendCurrentCategory() { + if (this.currentCategory) { + this.storeModel.append(this.currentCategory); + this.currentCategory = null; + this.CATEGORIES.shift(); + } + } + addToCategory(theme) { + if (!this.currentCategory) { + this.currentCategory = new ColorSchemeNode(this.CATEGORIES[0][1]); + } + this.currentCategory.addChild(new ColorSchemeNode(theme.name, theme)); + } + addTheme(theme) { + if (this.matchesCategory(theme)) { + this.addToCategory(theme); + } + else { + if (this.currentCategory) { + this.appendCurrentCategory(); + } + this.storeModel.append(new ColorSchemeNode(theme.name, theme)); + } + } + static buildTreeModel() { + let builder = new ModelBuilder(); + Base16Theme.THEME_LIST.forEach(theme => builder.addTheme(theme)); + return Gtk.TreeListModel.new(builder.storeModel, false, false, item => item.child_model); + } +} +export class ColorSchemeNode extends GObject.Object { + constructor(text, theme = null) { + super(); + this._text = text; + this.theme = theme; + this.child_model = null; + } + get text() { + return this._text; + } + addChild(child) { + if (this.child_model === null) { + this.child_model = new Gio.ListStore(_a); + } + this.child_model.append(child); + } + matchesId(id) { + return this.theme !== null && this.theme.id === id; + } + searchChildren(id) { + if (this.child_model) { + for (let i = 0; i < this.child_model.n_items; i++) { + let node = this.child_model.get_item(i); + if (node.matchesId(id)) { + return true; + } + } + } + return false; + } +} +_a = ColorSchemeNode; +(() => { + GObject.registerClass({ + GTypeName: 'ColorSchemeNode', + Properties: { + 'text': GObject.ParamSpec.string('text', '', '', GObject.ParamFlags.READWRITE, ''), + } + }, _a); +})(); +export class ColorSchemeModel { + constructor() { + this.treeModel = ModelBuilder.buildTreeModel(); + this.selection = Gtk.SingleSelection.new(this.treeModel); + } + selectedTheme() { + // @ts-ignore + let item = this.selection.selected_item.item; + return item === null || item === void 0 ? void 0 : item.theme; + } + changeSelected(offset) { + const n_items = this.selection.n_items; + if (n_items <= 1) { + return; + } + const pos = this.selection.selected; + if (pos == Gtk.INVALID_LIST_POSITION) { + return; + } + const newPos = pos + offset; + if (newPos < 0 || newPos >= n_items) { + return; + } + this.selection.selected = newPos; + return newPos; + } + selectPosition(pos) { + this.selection.selected = pos; + } + searchId(id, from = 0) { + for (let i = from; i < this.treeModel.n_items; i++) { + let row = this.treeModel.get_row(i); + let item = row === null || row === void 0 ? void 0 : row.item; + if (item && item.matchesId(id)) { + return row; + } + if (item.searchChildren(id)) { + row === null || row === void 0 ? void 0 : row.set_expanded(true); + if (from === 0) { + return this.searchId(id, i); + } + } + } + return null; + } +} diff --git a/js/ConfigureRealm.js b/js/ConfigureRealm.js new file mode 100644 index 0000000..f68ba87 --- /dev/null +++ b/js/ConfigureRealm.js @@ -0,0 +1,151 @@ +var _a; +import GObject from 'gi://GObject'; +import Gdk from 'gi://Gdk?version=4.0'; +import Gtk from 'gi://Gtk?version=4.0'; +import Adw from 'gi://Adw'; +import { BoolOptionData } from './model/RealmConfig.js'; +import { Base16Theme } from './model/Base16Themes.js'; +import { RealmManager } from './model/RealmManager.js'; +import { ColorSchemeChooser } from './ColorSchemeChooser.js'; +class OptionState { + constructor(row) { + this.value = null; + this.row = row; + } + initValue(value) { + this.value = value; + this.originalValue = value; + this.row.active = value; + } + /** @param {any} value */ + setValue(value) { + this.value = value; + } + hasChanged() { + return this.value !== this.originalValue; + } +} +export class ConfigureRealm extends Adw.NavigationPage { + constructor() { + var _b, _c; + super(); + this.realm = null; + this.optionState = new Map(); + this.theme = Base16Theme.lookup('default-dark'); + this._addOptions(); + const keyController = new Gtk.EventControllerKey(); + keyController.connect('key-pressed', (_, keyval) => { + if (keyval === Gdk.KEY_j) { + this.vfunc_move_focus(Gtk.DirectionType.TAB_FORWARD); + } + else if (keyval === Gdk.KEY_k) { + this.vfunc_move_focus(Gtk.DirectionType.TAB_BACKWARD); + } + }); + this.add_controller(keyController); + (_b = this._labelColorButton) === null || _b === void 0 ? void 0 : _b.connect('notify::rgba', () => this._scanChanges()); + (_c = this._colorSchemeButton) === null || _c === void 0 ? void 0 : _c.connect('clicked', () => { + var _b; + (_b = this.navigationView) === null || _b === void 0 ? void 0 : _b.push_by_tag('realm-colorscheme'); + }); + } + get colorschemeChooser() { + return this._colorschemeChooser; + } + set colorschemeChooser(val) { + this._colorschemeChooser = val; + } + set navigationView(val) { + var _b; + this._navigationView = val; + (_b = this._navigationView) === null || _b === void 0 ? void 0 : _b.connect('popped', (_view, page) => { + if (page === this.colorschemeChooser) { + let theme = this.colorschemeChooser.getSelectedTheme(); + if (theme && this._colorSchemeButton) { + this.theme = theme; + this._colorSchemeButton.label = this.theme.name; + } + } + }); + } + get navigationView() { + return this._navigationView; + } + configure(realm) { + this.realm = realm; + this.set_title(`Configure realm-${realm.name}`); + this._setOptions(realm); + } + _setOptions(realm) { + var _b; + let config = realm.config; + this.optionState.forEach((op, name) => { + let v = config.get_bool(name); + op.initValue(v); + }); + let scheme = realm.config.get_colorscheme(); + this.theme = Base16Theme.lookup(scheme); + if (this.theme && this._colorSchemeButton) { + this._colorSchemeButton.label = this.theme.name; + (_b = this.colorschemeChooser) === null || _b === void 0 ? void 0 : _b.selectTheme(this.theme.id); + } + let realmfs_list = RealmManager.instance().realmfsList(); + // @ts-ignore + let model = this._realmfsCombo.model; + if (model.n_items > 0) { + model.splice(0, model.n_items, []); + } + realmfs_list.forEach(realmfs => model.append(realmfs.name)); + let labelColor = realm.getLabelColor(); + this._labelColorButton.rgba = labelColor; + this._scanChanges(); + } + _addOptions() { + BoolOptionData.allOptions().forEach(option => { + let row = new Adw.SwitchRow({ + title: option.description, + }); + if (option.tooltip.length > 0) { + row.tooltipMarkup = option.tooltip; + } + let state = new OptionState(row); + this.optionState.set(option.name, state); + row.connect("notify::active", () => { + state.setValue(row.active); + this._scanChanges(); + }); + this._optionsGroup.add(row); + }); + } + _scanChanges() { + var _b; + let changed = false; + this.optionState.forEach(op => { + if (op.hasChanged()) { + changed = true; + } + }); + let labelColor = (_b = this.realm) === null || _b === void 0 ? void 0 : _b.getLabelColor(); + if (labelColor) { + if (!this._labelColorButton.rgba.equal(labelColor)) { + changed = true; + } + } + this._changedBanner.set_revealed(changed); + } + _onApplyClicked() { + print("clikkk"); + } +} +_a = ConfigureRealm; +(() => { + GObject.registerClass({ + GTypeName: "ConfigureRealm", + Template: 'resource:///com/subgraph/citadel/Realms/ui/ConfigureRealm.ui', + InternalChildren: ['optionsGroup', 'changedBanner', 'overlayCombo', 'realmfsCombo', 'colorSchemeButton', 'labelColorButton'], + Properties: { + 'navigation-view': GObject.ParamSpec.object('navigation-view', '', '', GObject.ParamFlags.READWRITE, Adw.NavigationView), + 'colorscheme-chooser': GObject.ParamSpec.object('colorscheme-chooser', '', '', GObject.ParamFlags.READWRITE, ColorSchemeChooser), + } + }, _a); +})(); diff --git a/js/RealmInfo.js b/js/RealmInfo.js new file mode 100644 index 0000000..54b3e4d --- /dev/null +++ b/js/RealmInfo.js @@ -0,0 +1,131 @@ +var _a; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk?version=4.0'; +import { Realm } from "./model/Realm.js"; +import { RealmInfoEntry } from './RealmInfoEntry.js'; +const Sections = { + STATUS: 'Status', + OPTIONS: 'Options', + REALMFS: 'RealmFS', + MOUNTPOINT: 'RealmFS Mountpoint', +}; +export class RealmInfo extends Gtk.ScrolledWindow { + constructor() { + super(); + this._buffer = ""; + this._changeId = 0; + this._realm = null; + this._entries = new Map(); + this._addEntries({ + left: [ + Sections.STATUS, + Sections.REALMFS, + Sections.MOUNTPOINT, + Sections.OPTIONS, + ], + right: [] + }); + } + _addEntries(labels) { + let addSectionEntries = (section, entries) => { + entries.forEach(name => { + let entry = new RealmInfoEntry(name); + this._entries.set(name, entry); + section.append(entry); + }); + }; + addSectionEntries(this._column, labels['left']); + } + get realm() { + return this._realm; + } + set realm(value) { + if (this.realm === value) { + return; + } + if (this._realm) { + this._realm.disconnect(this._changeId); + } + this._realm = value; + if (this._realm) { + this._changeId = this._realm.connect('changed', () => { + this.displayRealm(); + }); + this.displayRealm(); + } + } + setEntry(name, value) { + let entry = this._entries.get(name); + if (entry) { + entry.setValue(value); + } + } + setEntryVisible(name, isVisible = true) { + let entry = this._entries.get(name); + if (entry) { + entry.set_visible(isVisible); + } + } + displayConfig() { + var _b; + let config = (_b = this._realm) === null || _b === void 0 ? void 0 : _b.config; + if (config) { + let enabled_default = config.enabled_bool_option_labels(true); + let enabled = config.enabled_bool_option_labels(false); + let buffer = enabled_default.join(' '); + buffer += '\n'; + buffer += enabled.map(s => `${s}`) + .join(' '); + this.setEntry(Sections.OPTIONS, buffer); + } + else { + this.setEntry(Sections.OPTIONS, ''); + } + } + displayRealmFS() { + var _b; + let realmfs = (_b = this._realm) === null || _b === void 0 ? void 0 : _b.realmfs; + if (realmfs) { + this.setEntryVisible(Sections.REALMFS); + this.setEntry(Sections.REALMFS, `${realmfs.name}-realmfs.img`); + if (realmfs.activated) { + this.setEntryVisible(Sections.MOUNTPOINT); + this.setEntry(Sections.MOUNTPOINT, realmfs.mountpoint); + } + else { + this.setEntryVisible(Sections.MOUNTPOINT, false); + } + } + else { + this.setEntryVisible(Sections.REALMFS, false); + this.setEntryVisible(Sections.MOUNTPOINT, false); + } + } + displayRealm() { + if (this._realm) { + this._columnTitle.label = `Realm ${this._realm.name}`; + if (this._realm.is_running()) { + this.setEntry("Status", "Running"); + } + else { + this.setEntry("Status", "Stopped"); + } + this.displayConfig(); + this.displayRealmFS(); + } + } +} +_a = RealmInfo; +(() => { + GObject.registerClass({ + GTypeName: "RealmInfo", + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmInfo.ui', + Properties: { + 'realm': GObject.ParamSpec.object('realm', '', '', GObject.ParamFlags.READWRITE, Realm), + }, + InternalChildren: [ + 'column', + 'columnTitle', + ] + }, _a); +})(); diff --git a/js/RealmInfoEntry.js b/js/RealmInfoEntry.js new file mode 100644 index 0000000..73cc434 --- /dev/null +++ b/js/RealmInfoEntry.js @@ -0,0 +1,20 @@ +var _a; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk?version=4.0'; +export class RealmInfoEntry extends Gtk.Box { + constructor(name) { + super(); + this._nameLabel.label = name; + } + setValue(value) { + this._valueLabel.label = value; + } +} +_a = RealmInfoEntry; +(() => { + GObject.registerClass({ + GTypeName: "RealmInfoEntry", + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmInfoEntry.ui', + InternalChildren: ['nameLabel', 'valueLabel'] + }, _a); +})(); diff --git a/js/RealmModel.js b/js/RealmModel.js new file mode 100644 index 0000000..66bc469 --- /dev/null +++ b/js/RealmModel.js @@ -0,0 +1,42 @@ +var _a; +import Gio from 'gi://Gio'; +import GObject from 'gi://GObject'; +import { Realm } from './model/Realm.js'; +import { RealmManager } from "./model/RealmManager.js"; +export class RealmModel extends GObject.Object { + constructor() { + super(); + this._realms = []; + this._realmManager = RealmManager.instance(); + this._realmManager.connect('realm-added', (_manager, realm) => { + let pos = this._realms.length; + this._realms.push(realm); + // @ts-ignore + this.items_changed(pos, 0, 1); + }); + this._realmManager.connect('realm-removed', (_manager, realm) => { + let pos = this._realms.findIndex(r => r === realm); + if (pos >= 0) { + this._realms.splice(pos, 1); + // @ts-ignore + this.items_changed(pos, 1, 0); + } + }); + } + vfunc_get_item_type() { + return Realm; + } + vfunc_get_item(position) { + return this._realms[position] || null; + } + vfunc_get_n_items() { + return this._realms.length; + } +} +_a = RealmModel; +(() => { + GObject.registerClass({ + GTypeName: 'RealmModel', + Implements: [Gio.ListModel], + }, _a); +})(); diff --git a/js/RealmRow.js b/js/RealmRow.js new file mode 100644 index 0000000..cf47cef --- /dev/null +++ b/js/RealmRow.js @@ -0,0 +1,51 @@ +var _a; +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk?version=4.0'; +import { Realm } from './model/Realm.js'; +export class RealmRow extends Gtk.Widget { + constructor() { + super(...arguments); + this._notifyId = 0; + } + get realm() { + if (this._realm === undefined) { + this._realm = null; + } + return this._realm; + } + set realm(value) { + if (this.realm === value) { + return; + } + if (this.realm && this._notifyId) { + this.realm.disconnect(this._notifyId); + this._notifyId = 0; + } + this._realm = value; + if (this.realm) { + this._notifyId = this.realm.connect('notify', this.syncRealm.bind(this)); + this.syncRealm(); + } + this.notify('realm'); + } + syncRealm() { + if (this.realm && this.realm.is_running()) { + this._nameLabel.remove_css_class('dim-label'); + } + else { + // @ts-ignore + this._nameLabel.add_css_class('dim-label'); + } + } +} +_a = RealmRow; +(() => { + GObject.registerClass({ + GTypeName: 'RealmRow', + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmRow.ui', + Properties: { + 'realm': GObject.ParamSpec.object('realm', '', '', GObject.ParamFlags.READWRITE, Realm), + }, + InternalChildren: ['nameLabel'], + }, _a); +})(); diff --git a/js/RealmsView.js b/js/RealmsView.js new file mode 100644 index 0000000..a6fbabd --- /dev/null +++ b/js/RealmsView.js @@ -0,0 +1,91 @@ +var _a; +import GObject from 'gi://GObject'; +import Gdk from 'gi://Gdk?version=4.0'; +import Gtk from 'gi://Gtk?version=4.0'; +import { Realm } from "./model/Realm.js"; +export class RealmsView extends Gtk.Widget { + constructor() { + super(); + this._selectedRealm = null; + this._setupHiddenRealmsFilter(); + this._setupRealmSorter(); + const keyController = new Gtk.EventControllerKey(); + keyController.connect('key-pressed', (_, keyval) => { + switch (keyval) { + case Gdk.KEY_j: + case Gdk.KEY_Down: + this.nextRealm(); + break; + case Gdk.KEY_k: + case Gdk.KEY_Up: + this.prevRealm(); + break; + case Gdk.KEY_Escape: + this.activate_action('app.quit', null); + print("escaped"); + break; + } + }); + this.add_controller(keyController); + } + _changeSelected(offset) { + const n_items = this._realmsSelection.n_items; + if (n_items <= 1) { + return; + } + const pos = this._realmsSelection.selected; + if (pos == Gtk.INVALID_LIST_POSITION) { + return; + } + const newPos = pos + offset; + if (newPos < 0 || newPos >= n_items) { + return; + } + this._realmsSelection.selected = newPos; + } + nextRealm() { + this._changeSelected(1); + } + prevRealm() { + this._changeSelected(-1); + } + get selectedRealm() { + return this._selectedRealm; + } + set selectedRealm(value) { + if (this.selectedRealm === value) { + return; + } + this._selectedRealm = value; + } + _setupHiddenRealmsFilter() { + this._hiddenRealmsFilterModel.filter = Gtk.CustomFilter.new(item => !item.is_system_realm); + } + _setupRealmSorter() { + // 1) Sort 'Current' the lowest (top of list). + // 2) Then sort 'Running' lower than not 'Running' + // 3) Realms in the same run state sorted by lowest timestamp + this._realmSorter.set_sort_func((a, b) => { + if (a.is_current || (a.is_running && !b.is_running)) { + return Gtk.Ordering.SMALLER; + } + else if (b.is_current || (b.is_running && !a.is_running)) { + return Gtk.Ordering.LARGER; + } + else { + return b.timestamp - a.timestamp; + } + }); + } +} +_a = RealmsView; +(() => { + GObject.registerClass({ + GTypeName: 'RealmsView', + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmsView.ui', + Properties: { + 'selected-realm': GObject.ParamSpec.object('selected-realm', '', '', GObject.ParamFlags.READWRITE, Realm), + }, + InternalChildren: ['realmsSelection', 'hiddenRealmsFilterModel', 'realmSorter'], + }, _a); +})(); diff --git a/js/Window.js b/js/Window.js new file mode 100644 index 0000000..1d91634 --- /dev/null +++ b/js/Window.js @@ -0,0 +1,28 @@ +var _a; +import GObject from 'gi://GObject'; +import Adw from 'gi://Adw'; +export class Window extends Adw.ApplicationWindow { + constructor(application) { + super({ application: application }); + } + configureRealm(realm) { + this._configureRealm.configure(realm); + this._navView.push(this._configureRealm); + } + get realms_view() { + return this._realmsView; + } + vfunc_close_request() { + super.vfunc_close_request(); + this.run_dispose(); + return true; + } +} +_a = Window; +(() => { + GObject.registerClass({ + GTypeName: 'RealmsWindow', + Template: 'resource:///com/subgraph/citadel/Realms/ui/Window.ui', + InternalChildren: ['realmsView', 'configureRealm', 'navView'], + }, _a); +})(); diff --git a/js/colors/Base16Theme.js b/js/colors/Base16Theme.js new file mode 100644 index 0000000..a16dcbc --- /dev/null +++ b/js/colors/Base16Theme.js @@ -0,0 +1,822 @@ +export class Base16Theme { + static add(id, name, colors) { + const theme = new Base16Theme(id, name, colors); + Base16Theme.THEMES.push(theme); + } + constructor(id, name, colors) { + this.id = id; + this.name = name; + this.colors = colors; + } + color(idx) { + let hex = this.colors[idx].toString(16).padStart(6, '0'); + return `#${hex}`; + } + terminal_background() { + return this.color(0); + } + terminal_foreground() { + return this.color(5); + } + terminal_palette_color(idx) { + return this.color(Base16Theme.TERM_MAP[idx]); + } +} +Base16Theme.CATEGORIES = [ + ['atelier', 'Atelier'], + ['black-metal', 'Black Metal'], + ['brushtrees', 'Brush Trees'], + ['classic', 'Classic'], + ['default', 'Default'], + ['google', 'Google'], + ['grayscale', 'Grayscale'], + ['gruvbox', 'Gruvbox'], + ['harmonic', 'Harmonic'], + ['ia', 'iA'], + ['material', 'Material'], + ['papercolor', 'PaperColor'], + ['solarized', 'Solarized'], + ['summerfruit', 'Summerfruit'], + ['tomorrow', 'Tomorrow'], + ['unikitty', 'Unikitty'], +]; +Base16Theme.TERM_MAP = [ + 0x00, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x05, + 0x03, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x07, + 0x09, 0x0F, 0x01, 0x02, 0x04, 0x06, +]; +Base16Theme.THEMES = []; +Base16Theme.add("3024", "3024", [ + 0x090300, 0x3a3432, 0x4a4543, 0x5c5855, + 0x807d7c, 0xa5a2a2, 0xd6d5d4, 0xf7f7f7, + 0xdb2d20, 0xe8bbd0, 0xfded02, 0x01a252, + 0xb5e4f4, 0x01a0e4, 0xa16a94, 0xcdab53, +]); +Base16Theme.add("apathy", 'Apathy', [ + 0x031A16, 0x0B342D, 0x184E45, 0x2B685E, + 0x5F9C92, 0x81B5AC, 0xA7CEC8, 0xD2E7E4, + 0x3E9688, 0x3E7996, 0x3E4C96, 0x883E96, + 0x963E4C, 0x96883E, 0x4C963E, 0x3E965B, +]); +Base16Theme.add("ashes", "Ashes", [ + 0x1C2023, 0x393F45, 0x565E65, 0x747C84, + 0xADB3BA, 0xC7CCD1, 0xDFE2E5, 0xF3F4F5, + 0xC7AE95, 0xC7C795, 0xAEC795, 0x95C7AE, + 0x95AEC7, 0xAE95C7, 0xC795AE, 0xC79595, +]); +Base16Theme.add("atelier-cave-light", "Atelier Cave Light", [ + 0xefecf4, 0xe2dfe7, 0x8b8792, 0x7e7887, + 0x655f6d, 0x585260, 0x26232a, 0x19171c, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, +]); +Base16Theme.add("atelier-cave", "Atelier Cave", [ + 0x19171c, 0x26232a, 0x585260, 0x655f6d, + 0x7e7887, 0x8b8792, 0xe2dfe7, 0xefecf4, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, +]); +Base16Theme.add("atelier-dune-light", "Atelier Dune Light", [ + 0xfefbec, 0xe8e4cf, 0xa6a28c, 0x999580, + 0x7d7a68, 0x6e6b5e, 0x292824, 0x20201d, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, +]); +Base16Theme.add("atelier-dune", "Atelier Dune", [ + 0x20201d, 0x292824, 0x6e6b5e, 0x7d7a68, + 0x999580, 0xa6a28c, 0xe8e4cf, 0xfefbec, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, +]); +Base16Theme.add("atelier-estuary-light", "Atelier Estuary Light", [ + 0xf4f3ec, 0xe7e6df, 0x929181, 0x878573, + 0x6c6b5a, 0x5f5e4e, 0x302f27, 0x22221b, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, +]); +Base16Theme.add("atelier-estuary", "Atelier Estuary", [ + 0x22221b, 0x302f27, 0x5f5e4e, 0x6c6b5a, + 0x878573, 0x929181, 0xe7e6df, 0xf4f3ec, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, +]); +Base16Theme.add("atelier-forest-light", "Atelier Forest Light", [ + 0xf1efee, 0xe6e2e0, 0xa8a19f, 0x9c9491, + 0x766e6b, 0x68615e, 0x2c2421, 0x1b1918, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, +]); +Base16Theme.add("atelier-forest", "Atelier Forest", [ + 0x1b1918, 0x2c2421, 0x68615e, 0x766e6b, + 0x9c9491, 0xa8a19f, 0xe6e2e0, 0xf1efee, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, +]); +Base16Theme.add("atelier-heath-light", "Atelier Heath Light", [ + 0xf7f3f7, 0xd8cad8, 0xab9bab, 0x9e8f9e, + 0x776977, 0x695d69, 0x292329, 0x1b181b, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, +]); +Base16Theme.add("atelier-heath", "Atelier Heath", [ + 0x1b181b, 0x292329, 0x695d69, 0x776977, + 0x9e8f9e, 0xab9bab, 0xd8cad8, 0xf7f3f7, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, +]); +Base16Theme.add("atelier-lakeside-light", "Atelier Lakeside Light", [ + 0xebf8ff, 0xc1e4f6, 0x7ea2b4, 0x7195a8, + 0x5a7b8c, 0x516d7b, 0x1f292e, 0x161b1d, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, +]); +Base16Theme.add("atelier-lakeside", "Atelier Lakeside", [ + 0x161b1d, 0x1f292e, 0x516d7b, 0x5a7b8c, + 0x7195a8, 0x7ea2b4, 0xc1e4f6, 0xebf8ff, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, +]); +Base16Theme.add("atelier-plateau-light", "Atelier Plateau Light", [ + 0xf4ecec, 0xe7dfdf, 0x8a8585, 0x7e7777, + 0x655d5d, 0x585050, 0x292424, 0x1b1818, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, +]); +Base16Theme.add("atelier-plateau", "Atelier Plateau", [ + 0x1b1818, 0x292424, 0x585050, 0x655d5d, + 0x7e7777, 0x8a8585, 0xe7dfdf, 0xf4ecec, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, +]); +Base16Theme.add("atelier-savanna-light", "Atelier Savanna Light", [ + 0xecf4ee, 0xdfe7e2, 0x87928a, 0x78877d, + 0x5f6d64, 0x526057, 0x232a25, 0x171c19, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, +]); +Base16Theme.add("atelier-savanna", "Atelier Savanna", [ + 0x171c19, 0x232a25, 0x526057, 0x5f6d64, + 0x78877d, 0x87928a, 0xdfe7e2, 0xecf4ee, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, +]); +Base16Theme.add("atelier-seaside-light", "Atelier Seaside Light", [ + 0xf4fbf4, 0xcfe8cf, 0x8ca68c, 0x809980, + 0x687d68, 0x5e6e5e, 0x242924, 0x131513, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, +]); +Base16Theme.add("atelier-seaside", "Atelier Seaside", [ + 0x131513, 0x242924, 0x5e6e5e, 0x687d68, + 0x809980, 0x8ca68c, 0xcfe8cf, 0xf4fbf4, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, +]); +Base16Theme.add("atelier-sulphurpool-light", "Atelier Sulphurpool Light", [ + 0xf5f7ff, 0xdfe2f1, 0x979db4, 0x898ea4, + 0x6b7394, 0x5e6687, 0x293256, 0x202746, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, +]); +Base16Theme.add("atelier-sulphurpool", "Atelier Sulphurpool", [ + 0x202746, 0x293256, 0x5e6687, 0x6b7394, + 0x898ea4, 0x979db4, 0xdfe2f1, 0xf5f7ff, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, +]); +Base16Theme.add("atlas", "Atlas", [ + 0x002635, 0x00384d, 0x517F8D, 0x6C8B91, + 0x869696, 0xa1a19a, 0xe6e6dc, 0xfafaf8, + 0xff5a67, 0xf08e48, 0xffcc1b, 0x7fc06e, + 0x14747e, 0x5dd7b9, 0x9a70a4, 0xc43060, +]); +Base16Theme.add("bespin", "Bespin", [ + 0x28211c, 0x36312e, 0x5e5d5c, 0x666666, + 0x797977, 0x8a8986, 0x9d9b97, 0xbaae9e, + 0xcf6a4c, 0xcf7d34, 0xf9ee98, 0x54be0d, + 0xafc4db, 0x5ea6ea, 0x9b859d, 0x937121, +]); +Base16Theme.add("black-metal-bathory", "Black Metal (Bathory)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xe78a53, 0xfbcb97, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-burzum", "Black Metal (Burzum)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x99bbaa, 0xddeecc, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-dark-funeral", "Black Metal (Dark Funeral)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x5f81a5, 0xd0dfee, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-gorgoroth", "Black Metal (Gorgoroth)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x8c7f70, 0x9b8d7f, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-immortal", "Black Metal (Immortal)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x556677, 0x7799bb, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-khold", "Black Metal (Khold)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x974b46, 0xeceee3, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-marduk", "Black Metal (Marduk)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x626b67, 0xa5aaa7, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-mayhem", "Black Metal (Mayhem)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xeecc6c, 0xf3ecd4, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-nile", "Black Metal (Nile)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x777755, 0xaa9988, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-venom", "Black Metal (Venom)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x79241f, 0xf8f7f2, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal", "Black Metal", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xa06666, 0xdd9999, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("brewer", "Brewer", [ + 0x0c0d0e, 0x2e2f30, 0x515253, 0x737475, + 0x959697, 0xb7b8b9, 0xdadbdc, 0xfcfdfe, + 0xe31a1c, 0xe6550d, 0xdca060, 0x31a354, + 0x80b1d3, 0x3182bd, 0x756bb1, 0xb15928, +]); +Base16Theme.add("bright", "Bright", [ + 0x000000, 0x303030, 0x505050, 0xb0b0b0, + 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, 0xffffff, + 0xfb0120, 0xfc6d24, 0xfda331, 0xa1c659, + 0x76c7b7, 0x6fb3d2, 0xd381c3, 0xbe643c, +]); +Base16Theme.add("brogrammer", "Brogrammer", [ + 0x1f1f1f, 0xf81118, 0x2dc55e, 0xecba0f, + 0x2a84d2, 0x4e5ab7, 0x1081d6, 0xd6dbe5, + 0xd6dbe5, 0xde352e, 0x1dd361, 0xf3bd09, + 0x1081d6, 0x5350b9, 0x0f7ddb, 0xffffff, +]); +Base16Theme.add("brushtrees-dark", "Brush Trees Dark", [ + 0x485867, 0x5A6D7A, 0x6D828E, 0x8299A1, + 0x98AFB5, 0xB0C5C8, 0xC9DBDC, 0xE3EFEF, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, +]); +Base16Theme.add("brushtrees", "Brush Trees", [ + 0xE3EFEF, 0xC9DBDC, 0xB0C5C8, 0x98AFB5, + 0x8299A1, 0x6D828E, 0x5A6D7A, 0x485867, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, +]); +Base16Theme.add("chalk", "Chalk", [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, + 0xfb9fb1, 0xeda987, 0xddb26f, 0xacc267, + 0x12cfc0, 0x6fc2ef, 0xe1a3ee, 0xdeaf8f, +]); +Base16Theme.add("circus", "Circus", [ + 0x191919, 0x202020, 0x303030, 0x5f5a60, + 0x505050, 0xa7a7a7, 0x808080, 0xffffff, + 0xdc657d, 0x4bb1a7, 0xc3ba63, 0x84b97c, + 0x4bb1a7, 0x639ee4, 0xb888e2, 0xb888e2, +]); +Base16Theme.add("classic-dark", "Classic Dark", [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xF5F5F5, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, +]); +Base16Theme.add("classic-light", "Classic Light", [ + 0xF5F5F5, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x505050, 0x303030, 0x202020, 0x151515, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, +]); +Base16Theme.add("codeschool", "Codeschool", [ + 0x232c31, 0x1c3657, 0x2a343a, 0x3f4944, + 0x84898c, 0x9ea7a6, 0xa7cfa3, 0xb5d8f6, + 0x2a5491, 0x43820d, 0xa03b1e, 0x237986, + 0xb02f30, 0x484d79, 0xc59820, 0xc98344, +]); +Base16Theme.add("cupcake", "Cupcake", [ + 0xfbf1f2, 0xf2f1f4, 0xd8d5dd, 0xbfb9c6, + 0xa59daf, 0x8b8198, 0x72677E, 0x585062, + 0xD57E85, 0xEBB790, 0xDCB16C, 0xA3B367, + 0x69A9A7, 0x7297B9, 0xBB99B4, 0xBAA58C, +]); +Base16Theme.add("cupertino", "Cupertino", [ + 0xffffff, 0xc0c0c0, 0xc0c0c0, 0x808080, + 0x808080, 0x404040, 0x404040, 0x5e5e5e, + 0xc41a15, 0xeb8500, 0x826b28, 0x007400, + 0x318495, 0x0000ff, 0xa90d91, 0x826b28, +]); +Base16Theme.add("darktooth", "Darktooth", [ + 0x1D2021, 0x32302F, 0x504945, 0x665C54, + 0x928374, 0xA89984, 0xD5C4A1, 0xFDF4C1, + 0xFB543F, 0xFE8625, 0xFAC03B, 0x95C085, + 0x8BA59B, 0x0D6678, 0x8F4673, 0xA87322, +]); +Base16Theme.add("default-dark", "Default Dark", [ + 0x181818, 0x282828, 0x383838, 0x585858, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, +]); +Base16Theme.add("default-light", "Default Light", [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, +]); +Base16Theme.add("dracula", "Dracula", [ + 0x282936, 0x3a3c4e, 0x4d4f68, 0x626483, + 0x62d6e8, 0xe9e9f4, 0xf1f2f8, 0xf7f7fb, + 0xea51b2, 0xb45bcf, 0x00f769, 0xebff87, + 0xa1efe4, 0x62d6e8, 0xb45bcf, 0x00f769, +]); +Base16Theme.add("eighties", "Eighties", [ + 0x2d2d2d, 0x393939, 0x515151, 0x747369, + 0xa09f93, 0xd3d0c8, 0xe8e6df, 0xf2f0ec, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xd27b53, +]); +Base16Theme.add("embers", "Embers", [ + 0x16130F, 0x2C2620, 0x433B32, 0x5A5047, + 0x8A8075, 0xA39A90, 0xBEB6AE, 0xDBD6D1, + 0x826D57, 0x828257, 0x6D8257, 0x57826D, + 0x576D82, 0x6D5782, 0x82576D, 0x825757, +]); +Base16Theme.add("flat", "Flat", [ + 0x2C3E50, 0x34495E, 0x7F8C8D, 0x95A5A6, + 0xBDC3C7, 0xe0e0e0, 0xf5f5f5, 0xECF0F1, + 0xE74C3C, 0xE67E22, 0xF1C40F, 0x2ECC71, + 0x1ABC9C, 0x3498DB, 0x9B59B6, 0xbe643c, +]); +Base16Theme.add("fruit-soda", "Fruit Soda", [ + 0xf1ecf1, 0xe0dee0, 0xd8d5d5, 0xb5b4b6, + 0x979598, 0x515151, 0x474545, 0x2d2c2c, + 0xfe3e31, 0xfe6d08, 0xf7e203, 0x47f74c, + 0x0f9cfd, 0x2931df, 0x611fce, 0xb16f40, +]); +Base16Theme.add("github", "Github", [ + 0xffffff, 0xf5f5f5, 0xc8c8fa, 0x969896, + 0xe8e8e8, 0x333333, 0xffffff, 0xffffff, + 0xed6a43, 0x0086b3, 0x795da3, 0x183691, + 0x183691, 0x795da3, 0xa71d5d, 0x333333, +]); +Base16Theme.add("google-dark", "Google Dark", [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, +]); +Base16Theme.add("google-light", "Google Light", [ + 0xffffff, 0xe0e0e0, 0xc5c8c6, 0xb4b7b4, + 0x969896, 0x373b41, 0x282a2e, 0x1d1f21, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, +]); +Base16Theme.add("grayscale-dark", "Grayscale Dark", [ + 0x101010, 0x252525, 0x464646, 0x525252, + 0xababab, 0xb9b9b9, 0xe3e3e3, 0xf7f7f7, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, +]); +Base16Theme.add("grayscale-light", "Grayscale Light", [ + 0xf7f7f7, 0xe3e3e3, 0xb9b9b9, 0xababab, + 0x525252, 0x464646, 0x252525, 0x101010, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, +]); +Base16Theme.add("greenscreen", "Green Screen", [ + 0x001100, 0x003300, 0x005500, 0x007700, + 0x009900, 0x00bb00, 0x00dd00, 0x00ff00, + 0x007700, 0x009900, 0x007700, 0x00bb00, + 0x005500, 0x009900, 0x00bb00, 0x005500, +]); +Base16Theme.add("gruvbox-dark-hard", "Gruvbox dark, hard", [ + 0x1d2021, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, +]); +Base16Theme.add("gruvbox-dark-medium", "Gruvbox dark, medium", [ + 0x282828, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, +]); +Base16Theme.add("gruvbox-dark-pale", "Gruvbox dark, pale", [ + 0x262626, 0x3a3a3a, 0x4e4e4e, 0x8a8a8a, + 0x949494, 0xdab997, 0xd5c4a1, 0xebdbb2, + 0xd75f5f, 0xff8700, 0xffaf00, 0xafaf00, + 0x85ad85, 0x83adad, 0xd485ad, 0xd65d0e, +]); +Base16Theme.add("gruvbox-dark-soft", "Gruvbox dark, soft", [ + 0x32302f, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, +]); +Base16Theme.add("gruvbox-light-hard", "Gruvbox light, hard", [ + 0xf9f5d7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, +]); +Base16Theme.add("gruvbox-light-medium", "Gruvbox light, medium", [ + 0xfbf1c7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, +]); +Base16Theme.add("gruvbox-light-soft", "Gruvbox light, soft", [ + 0xf2e5bc, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, +]); +Base16Theme.add("harmonic-dark", "Harmonic16 Dark", [ + 0x0b1c2c, 0x223b54, 0x405c79, 0x627e99, + 0xaabcce, 0xcbd6e2, 0xe5ebf1, 0xf7f9fb, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, +]); +Base16Theme.add("harmonic-light", "Harmonic16 Light", [ + 0xf7f9fb, 0xe5ebf1, 0xcbd6e2, 0xaabcce, + 0x627e99, 0x405c79, 0x223b54, 0x0b1c2c, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, +]); +Base16Theme.add("heetch-light", "Heetch Light", [ + 0xfeffff, 0x392551, 0x7b6d8b, 0x9c92a8, + 0xddd6e5, 0x5a496e, 0x470546, 0x190134, + 0x27d9d5, 0xbdb6c5, 0x5ba2b6, 0xf80059, + 0xc33678, 0x47f9f5, 0xbd0152, 0xdedae2, +]); +Base16Theme.add("heetch", "Heetch Dark", [ + 0x190134, 0x392551, 0x5A496E, 0x7B6D8B, + 0x9C92A8, 0xBDB6C5, 0xDEDAE2, 0xFEFFFF, + 0x27D9D5, 0x5BA2B6, 0x8F6C97, 0xC33678, + 0xF80059, 0xBD0152, 0x82034C, 0x470546, +]); +Base16Theme.add("helios", "Helios", [ + 0x1d2021, 0x383c3e, 0x53585b, 0x6f7579, + 0xcdcdcd, 0xd5d5d5, 0xdddddd, 0xe5e5e5, + 0xd72638, 0xeb8413, 0xf19d1a, 0x88b92d, + 0x1ba595, 0x1e8bac, 0xbe4264, 0xc85e0d, +]); +Base16Theme.add("hopscotch", "Hopscotch", [ + 0x322931, 0x433b42, 0x5c545b, 0x797379, + 0x989498, 0xb9b5b8, 0xd5d3d5, 0xffffff, + 0xdd464c, 0xfd8b19, 0xfdcc59, 0x8fc13e, + 0x149b93, 0x1290bf, 0xc85e7c, 0xb33508, +]); +Base16Theme.add("horizon-dark", "Horizon Dark", [ + 0x1c1e26, 0x232530, 0x2e303e, 0x676a8d, + 0xced1d0, 0xcbced0, 0xdcdfe4, 0xe3e6ee, + 0xe93c58, 0xe58d7d, 0xefb993, 0xefaf8e, + 0x24a8b4, 0xdf5273, 0xb072d1, 0xe4a382, +]); +Base16Theme.add("ia-dark", "iA Dark", [ + 0x1a1a1a, 0x222222, 0x1d414d, 0x767676, + 0xb8b8b8, 0xcccccc, 0xe8e8e8, 0xf8f8f8, + 0xd88568, 0xd86868, 0xb99353, 0x83a471, + 0x7c9cae, 0x8eccdd, 0xb98eb2, 0x8b6c37, +]); +Base16Theme.add("ia-light", "iA Light", [ + 0xf6f6f6, 0xdedede, 0xbde5f2, 0x898989, + 0x767676, 0x181818, 0xe8e8e8, 0xf8f8f8, + 0x9c5a02, 0xc43e18, 0xc48218, 0x38781c, + 0x2d6bb1, 0x48bac2, 0xa94598, 0x8b6c37, +]); +Base16Theme.add("icy", "Icy Dark", [ + 0x021012, 0x031619, 0x041f23, 0x052e34, + 0x064048, 0x095b67, 0x0c7c8c, 0x109cb0, + 0x16c1d9, 0xb3ebf2, 0x80deea, 0x4dd0e1, + 0x26c6da, 0x00bcd4, 0x00acc1, 0x0097a7, +]); +Base16Theme.add("irblack", "IR Black", [ + 0x000000, 0x242422, 0x484844, 0x6c6c66, + 0x918f88, 0xb5b3aa, 0xd9d7cc, 0xfdfbee, + 0xff6c60, 0xe9c062, 0xffffb6, 0xa8ff60, + 0xc6c5fe, 0x96cbfe, 0xff73fd, 0xb18a3d, +]); +Base16Theme.add("isotope", "Isotope", [ + 0x000000, 0x404040, 0x606060, 0x808080, + 0xc0c0c0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xff0000, 0xff9900, 0xff0099, 0x33ff00, + 0x00ffff, 0x0066ff, 0xcc00ff, 0x3300ff, +]); +Base16Theme.add("macintosh", "Macintosh", [ + 0x000000, 0x404040, 0x404040, 0x808080, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0xffffff, + 0xdd0907, 0xff6403, 0xfbf305, 0x1fb714, + 0x02abea, 0x0000d3, 0x4700a5, 0x90713a, +]); +Base16Theme.add("marrakesh", "Marrakesh", [ + 0x201602, 0x302e00, 0x5f5b17, 0x6c6823, + 0x86813b, 0x948e48, 0xccc37a, 0xfaf0a5, + 0xc35359, 0xb36144, 0xa88339, 0x18974e, + 0x75a738, 0x477ca1, 0x8868b3, 0xb3588e, +]); +Base16Theme.add("materia", "Materia", [ + 0x263238, 0x2C393F, 0x37474F, 0x707880, + 0xC9CCD3, 0xCDD3DE, 0xD5DBE5, 0xFFFFFF, + 0xEC5F67, 0xEA9560, 0xFFCC00, 0x8BD649, + 0x80CBC4, 0x89DDFF, 0x82AAFF, 0xEC5F67, +]); +Base16Theme.add("material-darker", "Material Darker", [ + 0x212121, 0x303030, 0x353535, 0x4A4A4A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, +]); +Base16Theme.add("material-lighter", "Material Lighter", [ + 0xFAFAFA, 0xE7EAEC, 0xCCEAE7, 0xCCD7DA, + 0x8796B0, 0x80CBC4, 0x80CBC4, 0xFFFFFF, + 0xFF5370, 0xF76D47, 0xFFB62C, 0x91B859, + 0x39ADB5, 0x6182B8, 0x7C4DFF, 0xE53935, +]); +Base16Theme.add("material-palenight", "Material Palenight", [ + 0x292D3E, 0x444267, 0x32374D, 0x676E95, + 0x8796B0, 0x959DCB, 0x959DCB, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, +]); +Base16Theme.add("material-vivid", "Material Vivid", [ + 0x202124, 0x27292c, 0x323639, 0x44464d, + 0x676c71, 0x80868b, 0x9e9e9e, 0xffffff, + 0xf44336, 0xff9800, 0xffeb3b, 0x00e676, + 0x00bcd4, 0x2196f3, 0x673ab7, 0x8d6e63, +]); +Base16Theme.add("material", "Material", [ + 0x263238, 0x2E3C43, 0x314549, 0x546E7A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, +]); +Base16Theme.add("mellow-purple", "Mellow Purple", [ + 0x1e0528, 0x1A092D, 0x331354, 0x320f55, + 0x873582, 0xffeeff, 0xffeeff, 0xf8c0ff, + 0x00d9e9, 0xaa00a3, 0x955ae7, 0x05cb0d, + 0xb900b1, 0x550068, 0x8991bb, 0x4d6fff, +]); +Base16Theme.add("mexico-light", "Mexico Light", [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf79a0e, 0x538947, + 0x4b8093, 0x7cafc2, 0x96609e, 0xa16946, +]); +Base16Theme.add("mocha", "Mocha", [ + 0x3B3228, 0x534636, 0x645240, 0x7e705a, + 0xb8afad, 0xd0c8c6, 0xe9e1dd, 0xf5eeeb, + 0xcb6077, 0xd28b71, 0xf4bc87, 0xbeb55b, + 0x7bbda4, 0x8ab3b5, 0xa89bb9, 0xbb9584, +]); +Base16Theme.add("monokai", "Monokai", [ + 0x272822, 0x383830, 0x49483e, 0x75715e, + 0xa59f85, 0xf8f8f2, 0xf5f4f1, 0xf9f8f5, + 0xf92672, 0xfd971f, 0xf4bf75, 0xa6e22e, + 0xa1efe4, 0x66d9ef, 0xae81ff, 0xcc6633, +]); +Base16Theme.add("nord", "Nord", [ + 0x2E3440, 0x3B4252, 0x434C5E, 0x4C566A, + 0xD8DEE9, 0xE5E9F0, 0xECEFF4, 0x8FBCBB, + 0x88C0D0, 0x81A1C1, 0x5E81AC, 0xBF616A, + 0xD08770, 0xEBCB8B, 0xA3BE8C, 0xB48EAD, +]); +Base16Theme.add("ocean", "Ocean", [ + 0x2b303b, 0x343d46, 0x4f5b66, 0x65737e, + 0xa7adba, 0xc0c5ce, 0xdfe1e8, 0xeff1f5, + 0xbf616a, 0xd08770, 0xebcb8b, 0xa3be8c, + 0x96b5b4, 0x8fa1b3, 0xb48ead, 0xab7967, +]); +Base16Theme.add("oceanicnext", "OceanicNext", [ + 0x1B2B34, 0x343D46, 0x4F5B66, 0x65737E, + 0xA7ADBA, 0xC0C5CE, 0xCDD3DE, 0xD8DEE9, + 0xEC5F67, 0xF99157, 0xFAC863, 0x99C794, + 0x5FB3B3, 0x6699CC, 0xC594C5, 0xAB7967, +]); +Base16Theme.add("one-light", "One Light", [ + 0xfafafa, 0xf0f0f1, 0xe5e5e6, 0xa0a1a7, + 0x696c77, 0x383a42, 0x202227, 0x090a0b, + 0xca1243, 0xd75f00, 0xc18401, 0x50a14f, + 0x0184bc, 0x4078f2, 0xa626a4, 0x986801, +]); +Base16Theme.add("onedark", "OneDark", [ + 0x282c34, 0x353b45, 0x3e4451, 0x545862, + 0x565c64, 0xabb2bf, 0xb6bdca, 0xc8ccd4, + 0xe06c75, 0xd19a66, 0xe5c07b, 0x98c379, + 0x56b6c2, 0x61afef, 0xc678dd, 0xbe5046, +]); +Base16Theme.add("outrun-dark", "Outrun Dark", [ + 0x00002A, 0x20204A, 0x30305A, 0x50507A, + 0xB0B0DA, 0xD0D0FA, 0xE0E0FF, 0xF5F5FF, + 0xFF4242, 0xFC8D28, 0xF3E877, 0x59F176, + 0x0EF0F0, 0x66B0FF, 0xF10596, 0xF003EF, +]); +Base16Theme.add("papercolor-dark", "PaperColor Dark", [ + 0x1c1c1c, 0xaf005f, 0x5faf00, 0xd7af5f, + 0x5fafd7, 0x808080, 0xd7875f, 0xd0d0d0, + 0x585858, 0x5faf5f, 0xafd700, 0xaf87d7, + 0xffaf00, 0xff5faf, 0x00afaf, 0x5f8787, +]); +Base16Theme.add("papercolor-light", "PaperColor Light", [ + 0xeeeeee, 0xaf0000, 0x008700, 0x5f8700, + 0x0087af, 0x878787, 0x005f87, 0x444444, + 0xbcbcbc, 0xd70000, 0xd70087, 0x8700af, + 0xd75f00, 0xd75f00, 0x005faf, 0x005f87, +]); +Base16Theme.add("paraiso", "Paraiso", [ + 0x2f1e2e, 0x41323f, 0x4f424c, 0x776e71, + 0x8d8687, 0xa39e9b, 0xb9b6b0, 0xe7e9db, + 0xef6155, 0xf99b15, 0xfec418, 0x48b685, + 0x5bc4bf, 0x06b6ef, 0x815ba4, 0xe96ba8, +]); +Base16Theme.add("phd", "PhD", [ + 0x061229, 0x2a3448, 0x4d5666, 0x717885, + 0x9a99a3, 0xb8bbc2, 0xdbdde0, 0xffffff, + 0xd07346, 0xf0a000, 0xfbd461, 0x99bf52, + 0x72b9bf, 0x5299bf, 0x9989cc, 0xb08060, +]); +Base16Theme.add("pico", "Pico", [ + 0x000000, 0x1d2b53, 0x7e2553, 0x008751, + 0xab5236, 0x5f574f, 0xc2c3c7, 0xfff1e8, + 0xff004d, 0xffa300, 0xfff024, 0x00e756, + 0x29adff, 0x83769c, 0xff77a8, 0xffccaa, +]); +Base16Theme.add("pop", "Pop", [ + 0x000000, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xeb008a, 0xf29333, 0xf8ca12, 0x37b349, + 0x00aabb, 0x0e5a94, 0xb31e8d, 0x7a2d00, +]); +Base16Theme.add("porple", "Porple", [ + 0x292c36, 0x333344, 0x474160, 0x65568a, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xf84547, 0xd28e5d, 0xefa16b, 0x95c76f, + 0x64878f, 0x8485ce, 0xb74989, 0x986841, +]); +Base16Theme.add("qualia", "Qualia", [ + 0x101010, 0x454545, 0x454545, 0x454545, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0x454545, + 0xefa6a2, 0xa3b8ef, 0xe6a3dc, 0x80c990, + 0xc8c874, 0x50cacd, 0xe0af85, 0x808080, +]); +Base16Theme.add("railscasts", "Railscasts", [ + 0x2b2b2b, 0x272935, 0x3a4055, 0x5a647e, + 0xd4cfc9, 0xe6e1dc, 0xf4f1ed, 0xf9f7f3, + 0xda4939, 0xcc7833, 0xffc66d, 0xa5c261, + 0x519f50, 0x6d9cbe, 0xb6b3eb, 0xbc9458, +]); +Base16Theme.add("rebecca", "Rebecca", [ + 0x292a44, 0x663399, 0x383a62, 0x666699, + 0xa0a0c5, 0xf1eff8, 0xccccff, 0x53495d, + 0xa0a0c5, 0xefe4a1, 0xae81ff, 0x6dfedf, + 0x8eaee0, 0x2de0a7, 0x7aa5ff, 0xff79c6, +]); +Base16Theme.add("seti", "Seti UI", [ + 0x151718, 0x282a2b, 0x3B758C, 0x41535B, + 0x43a5d5, 0xd6d6d6, 0xeeeeee, 0xffffff, + 0xcd3f45, 0xdb7b55, 0xe6cd69, 0x9fca56, + 0x55dbbe, 0x55b5db, 0xa074c4, 0x8a553f, +]); +Base16Theme.add("shapeshifter", "Shapeshifter", [ + 0xf9f9f9, 0xe0e0e0, 0xababab, 0x555555, + 0x343434, 0x102015, 0x040404, 0x000000, + 0xe92f2f, 0xe09448, 0xdddd13, 0x0ed839, + 0x23edda, 0x3b48e3, 0xf996e2, 0x69542d, +]); +Base16Theme.add("snazzy", "Snazzy", [ + 0x282a36, 0x34353e, 0x43454f, 0x78787e, + 0xa5a5a9, 0xe2e4e5, 0xeff0eb, 0xf1f1f0, + 0xff5c57, 0xff9f43, 0xf3f99d, 0x5af78e, + 0x9aedfe, 0x57c7ff, 0xff6ac1, 0xb2643c, +]); +Base16Theme.add("solarflare", "Solar Flare", [ + 0x18262F, 0x222E38, 0x586875, 0x667581, + 0x85939E, 0xA6AFB8, 0xE8E9ED, 0xF5F7FA, + 0xEF5253, 0xE66B2B, 0xE4B51C, 0x7CC844, + 0x52CBB0, 0x33B5E1, 0xA363D5, 0xD73C9A, +]); +Base16Theme.add("solarized-dark", "Solarized Dark", [ + 0x002b36, 0x073642, 0x586e75, 0x657b83, + 0x839496, 0x93a1a1, 0xeee8d5, 0xfdf6e3, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, +]); +Base16Theme.add("solarized-light", "Solarized Light", [ + 0xfdf6e3, 0xeee8d5, 0x93a1a1, 0x839496, + 0x657b83, 0x586e75, 0x073642, 0x002b36, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, +]); +Base16Theme.add("spacemacs", "Spacemacs", [ + 0x1f2022, 0x282828, 0x444155, 0x585858, + 0xb8b8b8, 0xa3a3a3, 0xe8e8e8, 0xf8f8f8, + 0xf2241f, 0xffa500, 0xb1951d, 0x67b11d, + 0x2d9574, 0x4f97d7, 0xa31db1, 0xb03060, +]); +Base16Theme.add("summerfruit-dark", "Summerfruit Dark", [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xFFFFFF, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, +]); +Base16Theme.add("summerfruit-light", "Summerfruit Light", [ + 0xFFFFFF, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x000000, 0x101010, 0x151515, 0x202020, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, +]); +Base16Theme.add("synth-midnight-dark", "Synth Midnight", [ + 0x040404, 0x141414, 0x242424, 0x61507A, + 0xBFBBBF, 0xDFDBDF, 0xEFEBEF, 0xFFFBFF, + 0xB53B50, 0xE4600E, 0xDAE84D, 0x06EA61, + 0x7CEDE9, 0x03AEFF, 0xEA5CE2, 0x9D4D0E, +]); +Base16Theme.add("tomorrow-night-eighties", "Tomorrow Night Eighties", [ + 0x2d2d2d, 0x393939, 0x515151, 0x999999, + 0xb4b7b4, 0xcccccc, 0xe0e0e0, 0xffffff, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xa3685a, +]); +Base16Theme.add("tomorrow-night", "Tomorrow Night", [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xcc6666, 0xde935f, 0xf0c674, 0xb5bd68, + 0x8abeb7, 0x81a2be, 0xb294bb, 0xa3685a, +]); +Base16Theme.add("tomorrow", "Tomorrow", [ + 0xffffff, 0xe0e0e0, 0xd6d6d6, 0x8e908c, + 0x969896, 0x4d4d4c, 0x282a2e, 0x1d1f21, + 0xc82829, 0xf5871f, 0xeab700, 0x718c00, + 0x3e999f, 0x4271ae, 0x8959a8, 0xa3685a, +]); +Base16Theme.add("tube", "London Tube", [ + 0x231f20, 0x1c3f95, 0x5a5758, 0x737171, + 0x959ca1, 0xd9d8d8, 0xe7e7e8, 0xffffff, + 0xee2e24, 0xf386a1, 0xffd204, 0x00853e, + 0x85cebc, 0x009ddc, 0x98005d, 0xb06110, +]); +Base16Theme.add("twilight", "Twilight", [ + 0x1e1e1e, 0x323537, 0x464b50, 0x5f5a60, + 0x838184, 0xa7a7a7, 0xc3c3c3, 0xffffff, + 0xcf6a4c, 0xcda869, 0xf9ee98, 0x8f9d6a, + 0xafc4db, 0x7587a6, 0x9b859d, 0x9b703f, +]); +Base16Theme.add("unikitty-dark", "Unikitty Dark", [ + 0x2e2a31, 0x4a464d, 0x666369, 0x838085, + 0x9f9da2, 0xbcbabe, 0xd8d7da, 0xf5f4f7, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x796af5, 0xbb60ea, 0xc720ca, +]); +Base16Theme.add("unikitty-light", "Unikitty Light", [ + 0xffffff, 0xe1e1e2, 0xc4c3c5, 0xa7a5a8, + 0x89878b, 0x6c696e, 0x4f4b51, 0x322d34, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x775dff, 0xaa17e6, 0xe013d0, +]); +Base16Theme.add("woodland", "Woodland", [ + 0x231e18, 0x302b25, 0x48413a, 0x9d8b70, + 0xb4a490, 0xcabcb1, 0xd7c8bc, 0xe4d4c8, + 0xd35c5c, 0xca7f32, 0xe0ac16, 0xb7ba53, + 0x6eb958, 0x88a4d3, 0xbb90e2, 0xb49368, +]); +Base16Theme.add("xcode-dusk", "XCode Dusk", [ + 0x282B35, 0x3D4048, 0x53555D, 0x686A71, + 0x7E8086, 0x939599, 0xA9AAAE, 0xBEBFC2, + 0xB21889, 0x786DC5, 0x438288, 0xDF0002, + 0x00A0BE, 0x790EAD, 0xB21889, 0xC77C48, +]); +Base16Theme.add("zenburn", "Zenburn", [ + 0x383838, 0x404040, 0x606060, 0x6f6f6f, + 0x808080, 0xdcdccc, 0xc0c0c0, 0xffffff, + 0xdca3a3, 0xdfaf8f, 0xe0cf9f, 0x5f7f5f, + 0x93e0e3, 0x7cb8bb, 0xdc8cc3, 0x000000, +]); diff --git a/js/colors/ColorSchemeModel.js b/js/colors/ColorSchemeModel.js new file mode 100644 index 0000000..3aba664 --- /dev/null +++ b/js/colors/ColorSchemeModel.js @@ -0,0 +1,111 @@ +var _a; +import GObject from 'gi://GObject'; +import Gio from 'gi://Gio'; +import Gtk from 'gi://Gtk?version=4.0'; +import { Base16Theme } from './Base16Theme.js'; +export class ColorSchemeModel { + constructor() { + let builder = new TreeModelBuilder(); + this.treeModel = builder.buildTreeModel(); + this.selection = Gtk.SingleSelection.new(this.treeModel); + } +} +class ColorModelNode extends GObject.Object { + constructor(data) { + super(); + this.data = data; + } + get text() { + return this.data.name; + } + child_model() { + if (this.data instanceof ColorThemeCategory) { + return this.data.children; + } + else { + return null; + } + } + isThemeWithId(id) { + return (this.data instanceof Base16Theme) && + (this.data.id === id); + } + hasChildThemeWithId(id) { + const child_model = this.child_model(); + if (child_model) { + for (let i = 0; i < child_model.n_items; i++) { + let node = child_model.get_item(i); + if (node.isThemeWithId(id)) { + return true; + } + } + } + return false; + } + static newScheme(color) { + return new _a(color); + } + static newCategory(category) { + return new _a(category); + } +} +_a = ColorModelNode; +(() => { + GObject.registerClass({ + GTypeName: 'ColorModelNode', + Properties: { + 'text': GObject.ParamSpec.string('text', '', '', GObject.ParamFlags.READWRITE, ''), + } + }, _a); +})(); +class ColorThemeCategory { + constructor(name) { + this.name = name; + this.children = new Gio.ListStore(ColorModelNode); + } + append(color) { + this.children.append(ColorModelNode.newScheme(color)); + } +} +class TreeModelBuilder { + constructor() { + this.categories = Base16Theme.CATEGORIES; + this.currentCategory = null; + this.storeModel = new Gio.ListStore(ColorModelNode); + } + buildTreeModel() { + Base16Theme.THEMES.forEach(theme => this.addTheme(theme)); + return Gtk.TreeListModel.new(this.storeModel, false, false, item => item.child_model()); + } + appendCurrentCategory() { + if (this.currentCategory) { + this.storeModel.append(ColorModelNode.newCategory(this.currentCategory)); + this.currentCategory = null; + this.categories.shift(); + } + } + matchesNextCategory(theme) { + if (this.categories.length === 0) { + return false; + } + let [id, _name] = this.categories[0]; + return theme.id === id; + } + addTheme(theme) { + if (this.matchesNextCategory(theme)) { + this.addToCategory(theme); + return; + } + if (this.currentCategory) { + this.appendCurrentCategory(); + } + this.storeModel.append(ColorModelNode.newScheme(theme)); + } + addToCategory(theme) { + if (!this.currentCategory) { + let [_id, name] = this.categories[0]; + this.currentCategory = new ColorThemeCategory(name); + } + this.currentCategory.append(theme); + } +} diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..f284c98 --- /dev/null +++ b/js/main.js @@ -0,0 +1,6 @@ +import 'gi://Gdk?version=4.0'; +import 'gi://Gtk?version=4.0'; +import { Application } from './Application.js'; +export function main(argv) { + return new Application().run(argv); +} diff --git a/js/model/Base16Themes.js b/js/model/Base16Themes.js new file mode 100644 index 0000000..3b5c469 --- /dev/null +++ b/js/model/Base16Themes.js @@ -0,0 +1,809 @@ +const TERM_MAP = [ + 0x00, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x05, + 0x03, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x07, + 0x09, 0x0F, 0x01, 0x02, 0x04, 0x06, +]; +export class Base16Theme { + constructor(id, name, colors) { + this.id = id; + this.name = name; + this.colors = colors; + } + static add(id, name, colors) { + const theme = new Base16Theme(id, name, colors); + Base16Theme.THEME_LIST.push(theme); + Base16Theme.THEMES.set(id, theme); + } + static lookup(id) { + return Base16Theme.THEMES.get(id); + } + color(idx) { + let hex = this.colors[idx].toString(16).padStart(6, '0'); + return `#${hex}`; + } + terminal_background() { + return this.color(0); + } + terminal_foreground() { + return this.color(5); + } + terminal_palette_color(idx) { + return this.color(TERM_MAP[idx]); + } +} +Base16Theme.THEMES = new Map(); +Base16Theme.THEME_LIST = []; +Base16Theme.add("3024", "3024", [ + 0x090300, 0x3a3432, 0x4a4543, 0x5c5855, + 0x807d7c, 0xa5a2a2, 0xd6d5d4, 0xf7f7f7, + 0xdb2d20, 0xe8bbd0, 0xfded02, 0x01a252, + 0xb5e4f4, 0x01a0e4, 0xa16a94, 0xcdab53, +]); +Base16Theme.add("apathy", 'Apathy', [ + 0x031A16, 0x0B342D, 0x184E45, 0x2B685E, + 0x5F9C92, 0x81B5AC, 0xA7CEC8, 0xD2E7E4, + 0x3E9688, 0x3E7996, 0x3E4C96, 0x883E96, + 0x963E4C, 0x96883E, 0x4C963E, 0x3E965B, +]); +Base16Theme.add("ashes", "Ashes", [ + 0x1C2023, 0x393F45, 0x565E65, 0x747C84, + 0xADB3BA, 0xC7CCD1, 0xDFE2E5, 0xF3F4F5, + 0xC7AE95, 0xC7C795, 0xAEC795, 0x95C7AE, + 0x95AEC7, 0xAE95C7, 0xC795AE, 0xC79595, +]); +Base16Theme.add("atelier-cave-light", "Atelier Cave Light", [ + 0xefecf4, 0xe2dfe7, 0x8b8792, 0x7e7887, + 0x655f6d, 0x585260, 0x26232a, 0x19171c, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, +]); +Base16Theme.add("atelier-cave", "Atelier Cave", [ + 0x19171c, 0x26232a, 0x585260, 0x655f6d, + 0x7e7887, 0x8b8792, 0xe2dfe7, 0xefecf4, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, +]); +Base16Theme.add("atelier-dune-light", "Atelier Dune Light", [ + 0xfefbec, 0xe8e4cf, 0xa6a28c, 0x999580, + 0x7d7a68, 0x6e6b5e, 0x292824, 0x20201d, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, +]); +Base16Theme.add("atelier-dune", "Atelier Dune", [ + 0x20201d, 0x292824, 0x6e6b5e, 0x7d7a68, + 0x999580, 0xa6a28c, 0xe8e4cf, 0xfefbec, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, +]); +Base16Theme.add("atelier-estuary-light", "Atelier Estuary Light", [ + 0xf4f3ec, 0xe7e6df, 0x929181, 0x878573, + 0x6c6b5a, 0x5f5e4e, 0x302f27, 0x22221b, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, +]); +Base16Theme.add("atelier-estuary", "Atelier Estuary", [ + 0x22221b, 0x302f27, 0x5f5e4e, 0x6c6b5a, + 0x878573, 0x929181, 0xe7e6df, 0xf4f3ec, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, +]); +Base16Theme.add("atelier-forest-light", "Atelier Forest Light", [ + 0xf1efee, 0xe6e2e0, 0xa8a19f, 0x9c9491, + 0x766e6b, 0x68615e, 0x2c2421, 0x1b1918, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, +]); +Base16Theme.add("atelier-forest", "Atelier Forest", [ + 0x1b1918, 0x2c2421, 0x68615e, 0x766e6b, + 0x9c9491, 0xa8a19f, 0xe6e2e0, 0xf1efee, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, +]); +Base16Theme.add("atelier-heath-light", "Atelier Heath Light", [ + 0xf7f3f7, 0xd8cad8, 0xab9bab, 0x9e8f9e, + 0x776977, 0x695d69, 0x292329, 0x1b181b, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, +]); +Base16Theme.add("atelier-heath", "Atelier Heath", [ + 0x1b181b, 0x292329, 0x695d69, 0x776977, + 0x9e8f9e, 0xab9bab, 0xd8cad8, 0xf7f3f7, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, +]); +Base16Theme.add("atelier-lakeside-light", "Atelier Lakeside Light", [ + 0xebf8ff, 0xc1e4f6, 0x7ea2b4, 0x7195a8, + 0x5a7b8c, 0x516d7b, 0x1f292e, 0x161b1d, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, +]); +Base16Theme.add("atelier-lakeside", "Atelier Lakeside", [ + 0x161b1d, 0x1f292e, 0x516d7b, 0x5a7b8c, + 0x7195a8, 0x7ea2b4, 0xc1e4f6, 0xebf8ff, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, +]); +Base16Theme.add("atelier-plateau-light", "Atelier Plateau Light", [ + 0xf4ecec, 0xe7dfdf, 0x8a8585, 0x7e7777, + 0x655d5d, 0x585050, 0x292424, 0x1b1818, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, +]); +Base16Theme.add("atelier-plateau", "Atelier Plateau", [ + 0x1b1818, 0x292424, 0x585050, 0x655d5d, + 0x7e7777, 0x8a8585, 0xe7dfdf, 0xf4ecec, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, +]); +Base16Theme.add("atelier-savanna-light", "Atelier Savanna Light", [ + 0xecf4ee, 0xdfe7e2, 0x87928a, 0x78877d, + 0x5f6d64, 0x526057, 0x232a25, 0x171c19, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, +]); +Base16Theme.add("atelier-savanna", "Atelier Savanna", [ + 0x171c19, 0x232a25, 0x526057, 0x5f6d64, + 0x78877d, 0x87928a, 0xdfe7e2, 0xecf4ee, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, +]); +Base16Theme.add("atelier-seaside-light", "Atelier Seaside Light", [ + 0xf4fbf4, 0xcfe8cf, 0x8ca68c, 0x809980, + 0x687d68, 0x5e6e5e, 0x242924, 0x131513, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, +]); +Base16Theme.add("atelier-seaside", "Atelier Seaside", [ + 0x131513, 0x242924, 0x5e6e5e, 0x687d68, + 0x809980, 0x8ca68c, 0xcfe8cf, 0xf4fbf4, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, +]); +Base16Theme.add("atelier-sulphurpool-light", "Atelier Sulphurpool Light", [ + 0xf5f7ff, 0xdfe2f1, 0x979db4, 0x898ea4, + 0x6b7394, 0x5e6687, 0x293256, 0x202746, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, +]); +Base16Theme.add("atelier-sulphurpool", "Atelier Sulphurpool", [ + 0x202746, 0x293256, 0x5e6687, 0x6b7394, + 0x898ea4, 0x979db4, 0xdfe2f1, 0xf5f7ff, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, +]); +Base16Theme.add("atlas", "Atlas", [ + 0x002635, 0x00384d, 0x517F8D, 0x6C8B91, + 0x869696, 0xa1a19a, 0xe6e6dc, 0xfafaf8, + 0xff5a67, 0xf08e48, 0xffcc1b, 0x7fc06e, + 0x14747e, 0x5dd7b9, 0x9a70a4, 0xc43060, +]); +Base16Theme.add("bespin", "Bespin", [ + 0x28211c, 0x36312e, 0x5e5d5c, 0x666666, + 0x797977, 0x8a8986, 0x9d9b97, 0xbaae9e, + 0xcf6a4c, 0xcf7d34, 0xf9ee98, 0x54be0d, + 0xafc4db, 0x5ea6ea, 0x9b859d, 0x937121, +]); +Base16Theme.add("black-metal-bathory", "Black Metal (Bathory)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xe78a53, 0xfbcb97, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-burzum", "Black Metal (Burzum)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x99bbaa, 0xddeecc, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-dark-funeral", "Black Metal (Dark Funeral)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x5f81a5, 0xd0dfee, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-gorgoroth", "Black Metal (Gorgoroth)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x8c7f70, 0x9b8d7f, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-immortal", "Black Metal (Immortal)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x556677, 0x7799bb, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-khold", "Black Metal (Khold)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x974b46, 0xeceee3, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-marduk", "Black Metal (Marduk)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x626b67, 0xa5aaa7, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-mayhem", "Black Metal (Mayhem)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xeecc6c, 0xf3ecd4, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-nile", "Black Metal (Nile)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x777755, 0xaa9988, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal-venom", "Black Metal (Venom)", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x79241f, 0xf8f7f2, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("black-metal", "Black Metal", [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xa06666, 0xdd9999, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, +]); +Base16Theme.add("brewer", "Brewer", [ + 0x0c0d0e, 0x2e2f30, 0x515253, 0x737475, + 0x959697, 0xb7b8b9, 0xdadbdc, 0xfcfdfe, + 0xe31a1c, 0xe6550d, 0xdca060, 0x31a354, + 0x80b1d3, 0x3182bd, 0x756bb1, 0xb15928, +]); +Base16Theme.add("bright", "Bright", [ + 0x000000, 0x303030, 0x505050, 0xb0b0b0, + 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, 0xffffff, + 0xfb0120, 0xfc6d24, 0xfda331, 0xa1c659, + 0x76c7b7, 0x6fb3d2, 0xd381c3, 0xbe643c, +]); +Base16Theme.add("brogrammer", "Brogrammer", [ + 0x1f1f1f, 0xf81118, 0x2dc55e, 0xecba0f, + 0x2a84d2, 0x4e5ab7, 0x1081d6, 0xd6dbe5, + 0xd6dbe5, 0xde352e, 0x1dd361, 0xf3bd09, + 0x1081d6, 0x5350b9, 0x0f7ddb, 0xffffff, +]); +Base16Theme.add("brushtrees-dark", "Brush Trees Dark", [ + 0x485867, 0x5A6D7A, 0x6D828E, 0x8299A1, + 0x98AFB5, 0xB0C5C8, 0xC9DBDC, 0xE3EFEF, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, +]); +Base16Theme.add("brushtrees", "Brush Trees", [ + 0xE3EFEF, 0xC9DBDC, 0xB0C5C8, 0x98AFB5, + 0x8299A1, 0x6D828E, 0x5A6D7A, 0x485867, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, +]); +Base16Theme.add("chalk", "Chalk", [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, + 0xfb9fb1, 0xeda987, 0xddb26f, 0xacc267, + 0x12cfc0, 0x6fc2ef, 0xe1a3ee, 0xdeaf8f, +]); +Base16Theme.add("circus", "Circus", [ + 0x191919, 0x202020, 0x303030, 0x5f5a60, + 0x505050, 0xa7a7a7, 0x808080, 0xffffff, + 0xdc657d, 0x4bb1a7, 0xc3ba63, 0x84b97c, + 0x4bb1a7, 0x639ee4, 0xb888e2, 0xb888e2, +]); +Base16Theme.add("classic-dark", "Classic Dark", [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xF5F5F5, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, +]); +Base16Theme.add("classic-light", "Classic Light", [ + 0xF5F5F5, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x505050, 0x303030, 0x202020, 0x151515, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, +]); +Base16Theme.add("codeschool", "Codeschool", [ + 0x232c31, 0x1c3657, 0x2a343a, 0x3f4944, + 0x84898c, 0x9ea7a6, 0xa7cfa3, 0xb5d8f6, + 0x2a5491, 0x43820d, 0xa03b1e, 0x237986, + 0xb02f30, 0x484d79, 0xc59820, 0xc98344, +]); +Base16Theme.add("cupcake", "Cupcake", [ + 0xfbf1f2, 0xf2f1f4, 0xd8d5dd, 0xbfb9c6, + 0xa59daf, 0x8b8198, 0x72677E, 0x585062, + 0xD57E85, 0xEBB790, 0xDCB16C, 0xA3B367, + 0x69A9A7, 0x7297B9, 0xBB99B4, 0xBAA58C, +]); +Base16Theme.add("cupertino", "Cupertino", [ + 0xffffff, 0xc0c0c0, 0xc0c0c0, 0x808080, + 0x808080, 0x404040, 0x404040, 0x5e5e5e, + 0xc41a15, 0xeb8500, 0x826b28, 0x007400, + 0x318495, 0x0000ff, 0xa90d91, 0x826b28, +]); +Base16Theme.add("darktooth", "Darktooth", [ + 0x1D2021, 0x32302F, 0x504945, 0x665C54, + 0x928374, 0xA89984, 0xD5C4A1, 0xFDF4C1, + 0xFB543F, 0xFE8625, 0xFAC03B, 0x95C085, + 0x8BA59B, 0x0D6678, 0x8F4673, 0xA87322, +]); +Base16Theme.add("default-dark", "Default Dark", [ + 0x181818, 0x282828, 0x383838, 0x585858, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, +]); +Base16Theme.add("default-light", "Default Light", [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, +]); +Base16Theme.add("dracula", "Dracula", [ + 0x282936, 0x3a3c4e, 0x4d4f68, 0x626483, + 0x62d6e8, 0xe9e9f4, 0xf1f2f8, 0xf7f7fb, + 0xea51b2, 0xb45bcf, 0x00f769, 0xebff87, + 0xa1efe4, 0x62d6e8, 0xb45bcf, 0x00f769, +]); +Base16Theme.add("eighties", "Eighties", [ + 0x2d2d2d, 0x393939, 0x515151, 0x747369, + 0xa09f93, 0xd3d0c8, 0xe8e6df, 0xf2f0ec, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xd27b53, +]); +Base16Theme.add("embers", "Embers", [ + 0x16130F, 0x2C2620, 0x433B32, 0x5A5047, + 0x8A8075, 0xA39A90, 0xBEB6AE, 0xDBD6D1, + 0x826D57, 0x828257, 0x6D8257, 0x57826D, + 0x576D82, 0x6D5782, 0x82576D, 0x825757, +]); +Base16Theme.add("flat", "Flat", [ + 0x2C3E50, 0x34495E, 0x7F8C8D, 0x95A5A6, + 0xBDC3C7, 0xe0e0e0, 0xf5f5f5, 0xECF0F1, + 0xE74C3C, 0xE67E22, 0xF1C40F, 0x2ECC71, + 0x1ABC9C, 0x3498DB, 0x9B59B6, 0xbe643c, +]); +Base16Theme.add("fruit-soda", "Fruit Soda", [ + 0xf1ecf1, 0xe0dee0, 0xd8d5d5, 0xb5b4b6, + 0x979598, 0x515151, 0x474545, 0x2d2c2c, + 0xfe3e31, 0xfe6d08, 0xf7e203, 0x47f74c, + 0x0f9cfd, 0x2931df, 0x611fce, 0xb16f40, +]); +Base16Theme.add("github", "Github", [ + 0xffffff, 0xf5f5f5, 0xc8c8fa, 0x969896, + 0xe8e8e8, 0x333333, 0xffffff, 0xffffff, + 0xed6a43, 0x0086b3, 0x795da3, 0x183691, + 0x183691, 0x795da3, 0xa71d5d, 0x333333, +]); +Base16Theme.add("google-dark", "Google Dark", [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, +]); +Base16Theme.add("google-light", "Google Light", [ + 0xffffff, 0xe0e0e0, 0xc5c8c6, 0xb4b7b4, + 0x969896, 0x373b41, 0x282a2e, 0x1d1f21, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, +]); +Base16Theme.add("grayscale-dark", "Grayscale Dark", [ + 0x101010, 0x252525, 0x464646, 0x525252, + 0xababab, 0xb9b9b9, 0xe3e3e3, 0xf7f7f7, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, +]); +Base16Theme.add("grayscale-light", "Grayscale Light", [ + 0xf7f7f7, 0xe3e3e3, 0xb9b9b9, 0xababab, + 0x525252, 0x464646, 0x252525, 0x101010, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, +]); +Base16Theme.add("greenscreen", "Green Screen", [ + 0x001100, 0x003300, 0x005500, 0x007700, + 0x009900, 0x00bb00, 0x00dd00, 0x00ff00, + 0x007700, 0x009900, 0x007700, 0x00bb00, + 0x005500, 0x009900, 0x00bb00, 0x005500, +]); +Base16Theme.add("gruvbox-dark-hard", "Gruvbox dark, hard", [ + 0x1d2021, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, +]); +Base16Theme.add("gruvbox-dark-medium", "Gruvbox dark, medium", [ + 0x282828, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, +]); +Base16Theme.add("gruvbox-dark-pale", "Gruvbox dark, pale", [ + 0x262626, 0x3a3a3a, 0x4e4e4e, 0x8a8a8a, + 0x949494, 0xdab997, 0xd5c4a1, 0xebdbb2, + 0xd75f5f, 0xff8700, 0xffaf00, 0xafaf00, + 0x85ad85, 0x83adad, 0xd485ad, 0xd65d0e, +]); +Base16Theme.add("gruvbox-dark-soft", "Gruvbox dark, soft", [ + 0x32302f, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, +]); +Base16Theme.add("gruvbox-light-hard", "Gruvbox light, hard", [ + 0xf9f5d7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, +]); +Base16Theme.add("gruvbox-light-medium", "Gruvbox light, medium", [ + 0xfbf1c7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, +]); +Base16Theme.add("gruvbox-light-soft", "Gruvbox light, soft", [ + 0xf2e5bc, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, +]); +Base16Theme.add("harmonic-dark", "Harmonic16 Dark", [ + 0x0b1c2c, 0x223b54, 0x405c79, 0x627e99, + 0xaabcce, 0xcbd6e2, 0xe5ebf1, 0xf7f9fb, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, +]); +Base16Theme.add("harmonic-light", "Harmonic16 Light", [ + 0xf7f9fb, 0xe5ebf1, 0xcbd6e2, 0xaabcce, + 0x627e99, 0x405c79, 0x223b54, 0x0b1c2c, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, +]); +Base16Theme.add("heetch-light", "Heetch Light", [ + 0xfeffff, 0x392551, 0x7b6d8b, 0x9c92a8, + 0xddd6e5, 0x5a496e, 0x470546, 0x190134, + 0x27d9d5, 0xbdb6c5, 0x5ba2b6, 0xf80059, + 0xc33678, 0x47f9f5, 0xbd0152, 0xdedae2, +]); +Base16Theme.add("heetch", "Heetch Dark", [ + 0x190134, 0x392551, 0x5A496E, 0x7B6D8B, + 0x9C92A8, 0xBDB6C5, 0xDEDAE2, 0xFEFFFF, + 0x27D9D5, 0x5BA2B6, 0x8F6C97, 0xC33678, + 0xF80059, 0xBD0152, 0x82034C, 0x470546, +]); +Base16Theme.add("helios", "Helios", [ + 0x1d2021, 0x383c3e, 0x53585b, 0x6f7579, + 0xcdcdcd, 0xd5d5d5, 0xdddddd, 0xe5e5e5, + 0xd72638, 0xeb8413, 0xf19d1a, 0x88b92d, + 0x1ba595, 0x1e8bac, 0xbe4264, 0xc85e0d, +]); +Base16Theme.add("hopscotch", "Hopscotch", [ + 0x322931, 0x433b42, 0x5c545b, 0x797379, + 0x989498, 0xb9b5b8, 0xd5d3d5, 0xffffff, + 0xdd464c, 0xfd8b19, 0xfdcc59, 0x8fc13e, + 0x149b93, 0x1290bf, 0xc85e7c, 0xb33508, +]); +Base16Theme.add("horizon-dark", "Horizon Dark", [ + 0x1c1e26, 0x232530, 0x2e303e, 0x676a8d, + 0xced1d0, 0xcbced0, 0xdcdfe4, 0xe3e6ee, + 0xe93c58, 0xe58d7d, 0xefb993, 0xefaf8e, + 0x24a8b4, 0xdf5273, 0xb072d1, 0xe4a382, +]); +Base16Theme.add("ia-dark", "iA Dark", [ + 0x1a1a1a, 0x222222, 0x1d414d, 0x767676, + 0xb8b8b8, 0xcccccc, 0xe8e8e8, 0xf8f8f8, + 0xd88568, 0xd86868, 0xb99353, 0x83a471, + 0x7c9cae, 0x8eccdd, 0xb98eb2, 0x8b6c37, +]); +Base16Theme.add("ia-light", "iA Light", [ + 0xf6f6f6, 0xdedede, 0xbde5f2, 0x898989, + 0x767676, 0x181818, 0xe8e8e8, 0xf8f8f8, + 0x9c5a02, 0xc43e18, 0xc48218, 0x38781c, + 0x2d6bb1, 0x48bac2, 0xa94598, 0x8b6c37, +]); +Base16Theme.add("icy", "Icy Dark", [ + 0x021012, 0x031619, 0x041f23, 0x052e34, + 0x064048, 0x095b67, 0x0c7c8c, 0x109cb0, + 0x16c1d9, 0xb3ebf2, 0x80deea, 0x4dd0e1, + 0x26c6da, 0x00bcd4, 0x00acc1, 0x0097a7, +]); +Base16Theme.add("irblack", "IR Black", [ + 0x000000, 0x242422, 0x484844, 0x6c6c66, + 0x918f88, 0xb5b3aa, 0xd9d7cc, 0xfdfbee, + 0xff6c60, 0xe9c062, 0xffffb6, 0xa8ff60, + 0xc6c5fe, 0x96cbfe, 0xff73fd, 0xb18a3d, +]); +Base16Theme.add("isotope", "Isotope", [ + 0x000000, 0x404040, 0x606060, 0x808080, + 0xc0c0c0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xff0000, 0xff9900, 0xff0099, 0x33ff00, + 0x00ffff, 0x0066ff, 0xcc00ff, 0x3300ff, +]); +Base16Theme.add("macintosh", "Macintosh", [ + 0x000000, 0x404040, 0x404040, 0x808080, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0xffffff, + 0xdd0907, 0xff6403, 0xfbf305, 0x1fb714, + 0x02abea, 0x0000d3, 0x4700a5, 0x90713a, +]); +Base16Theme.add("marrakesh", "Marrakesh", [ + 0x201602, 0x302e00, 0x5f5b17, 0x6c6823, + 0x86813b, 0x948e48, 0xccc37a, 0xfaf0a5, + 0xc35359, 0xb36144, 0xa88339, 0x18974e, + 0x75a738, 0x477ca1, 0x8868b3, 0xb3588e, +]); +Base16Theme.add("materia", "Materia", [ + 0x263238, 0x2C393F, 0x37474F, 0x707880, + 0xC9CCD3, 0xCDD3DE, 0xD5DBE5, 0xFFFFFF, + 0xEC5F67, 0xEA9560, 0xFFCC00, 0x8BD649, + 0x80CBC4, 0x89DDFF, 0x82AAFF, 0xEC5F67, +]); +Base16Theme.add("material-darker", "Material Darker", [ + 0x212121, 0x303030, 0x353535, 0x4A4A4A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, +]); +Base16Theme.add("material-lighter", "Material Lighter", [ + 0xFAFAFA, 0xE7EAEC, 0xCCEAE7, 0xCCD7DA, + 0x8796B0, 0x80CBC4, 0x80CBC4, 0xFFFFFF, + 0xFF5370, 0xF76D47, 0xFFB62C, 0x91B859, + 0x39ADB5, 0x6182B8, 0x7C4DFF, 0xE53935, +]); +Base16Theme.add("material-palenight", "Material Palenight", [ + 0x292D3E, 0x444267, 0x32374D, 0x676E95, + 0x8796B0, 0x959DCB, 0x959DCB, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, +]); +Base16Theme.add("material-vivid", "Material Vivid", [ + 0x202124, 0x27292c, 0x323639, 0x44464d, + 0x676c71, 0x80868b, 0x9e9e9e, 0xffffff, + 0xf44336, 0xff9800, 0xffeb3b, 0x00e676, + 0x00bcd4, 0x2196f3, 0x673ab7, 0x8d6e63, +]); +Base16Theme.add("material", "Material", [ + 0x263238, 0x2E3C43, 0x314549, 0x546E7A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, +]); +Base16Theme.add("mellow-purple", "Mellow Purple", [ + 0x1e0528, 0x1A092D, 0x331354, 0x320f55, + 0x873582, 0xffeeff, 0xffeeff, 0xf8c0ff, + 0x00d9e9, 0xaa00a3, 0x955ae7, 0x05cb0d, + 0xb900b1, 0x550068, 0x8991bb, 0x4d6fff, +]); +Base16Theme.add("mexico-light", "Mexico Light", [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf79a0e, 0x538947, + 0x4b8093, 0x7cafc2, 0x96609e, 0xa16946, +]); +Base16Theme.add("mocha", "Mocha", [ + 0x3B3228, 0x534636, 0x645240, 0x7e705a, + 0xb8afad, 0xd0c8c6, 0xe9e1dd, 0xf5eeeb, + 0xcb6077, 0xd28b71, 0xf4bc87, 0xbeb55b, + 0x7bbda4, 0x8ab3b5, 0xa89bb9, 0xbb9584, +]); +Base16Theme.add("monokai", "Monokai", [ + 0x272822, 0x383830, 0x49483e, 0x75715e, + 0xa59f85, 0xf8f8f2, 0xf5f4f1, 0xf9f8f5, + 0xf92672, 0xfd971f, 0xf4bf75, 0xa6e22e, + 0xa1efe4, 0x66d9ef, 0xae81ff, 0xcc6633, +]); +Base16Theme.add("nord", "Nord", [ + 0x2E3440, 0x3B4252, 0x434C5E, 0x4C566A, + 0xD8DEE9, 0xE5E9F0, 0xECEFF4, 0x8FBCBB, + 0x88C0D0, 0x81A1C1, 0x5E81AC, 0xBF616A, + 0xD08770, 0xEBCB8B, 0xA3BE8C, 0xB48EAD, +]); +Base16Theme.add("ocean", "Ocean", [ + 0x2b303b, 0x343d46, 0x4f5b66, 0x65737e, + 0xa7adba, 0xc0c5ce, 0xdfe1e8, 0xeff1f5, + 0xbf616a, 0xd08770, 0xebcb8b, 0xa3be8c, + 0x96b5b4, 0x8fa1b3, 0xb48ead, 0xab7967, +]); +Base16Theme.add("oceanicnext", "OceanicNext", [ + 0x1B2B34, 0x343D46, 0x4F5B66, 0x65737E, + 0xA7ADBA, 0xC0C5CE, 0xCDD3DE, 0xD8DEE9, + 0xEC5F67, 0xF99157, 0xFAC863, 0x99C794, + 0x5FB3B3, 0x6699CC, 0xC594C5, 0xAB7967, +]); +Base16Theme.add("one-light", "One Light", [ + 0xfafafa, 0xf0f0f1, 0xe5e5e6, 0xa0a1a7, + 0x696c77, 0x383a42, 0x202227, 0x090a0b, + 0xca1243, 0xd75f00, 0xc18401, 0x50a14f, + 0x0184bc, 0x4078f2, 0xa626a4, 0x986801, +]); +Base16Theme.add("onedark", "OneDark", [ + 0x282c34, 0x353b45, 0x3e4451, 0x545862, + 0x565c64, 0xabb2bf, 0xb6bdca, 0xc8ccd4, + 0xe06c75, 0xd19a66, 0xe5c07b, 0x98c379, + 0x56b6c2, 0x61afef, 0xc678dd, 0xbe5046, +]); +Base16Theme.add("outrun-dark", "Outrun Dark", [ + 0x00002A, 0x20204A, 0x30305A, 0x50507A, + 0xB0B0DA, 0xD0D0FA, 0xE0E0FF, 0xF5F5FF, + 0xFF4242, 0xFC8D28, 0xF3E877, 0x59F176, + 0x0EF0F0, 0x66B0FF, 0xF10596, 0xF003EF, +]); +Base16Theme.add("papercolor-dark", "PaperColor Dark", [ + 0x1c1c1c, 0xaf005f, 0x5faf00, 0xd7af5f, + 0x5fafd7, 0x808080, 0xd7875f, 0xd0d0d0, + 0x585858, 0x5faf5f, 0xafd700, 0xaf87d7, + 0xffaf00, 0xff5faf, 0x00afaf, 0x5f8787, +]); +Base16Theme.add("papercolor-light", "PaperColor Light", [ + 0xeeeeee, 0xaf0000, 0x008700, 0x5f8700, + 0x0087af, 0x878787, 0x005f87, 0x444444, + 0xbcbcbc, 0xd70000, 0xd70087, 0x8700af, + 0xd75f00, 0xd75f00, 0x005faf, 0x005f87, +]); +Base16Theme.add("paraiso", "Paraiso", [ + 0x2f1e2e, 0x41323f, 0x4f424c, 0x776e71, + 0x8d8687, 0xa39e9b, 0xb9b6b0, 0xe7e9db, + 0xef6155, 0xf99b15, 0xfec418, 0x48b685, + 0x5bc4bf, 0x06b6ef, 0x815ba4, 0xe96ba8, +]); +Base16Theme.add("phd", "PhD", [ + 0x061229, 0x2a3448, 0x4d5666, 0x717885, + 0x9a99a3, 0xb8bbc2, 0xdbdde0, 0xffffff, + 0xd07346, 0xf0a000, 0xfbd461, 0x99bf52, + 0x72b9bf, 0x5299bf, 0x9989cc, 0xb08060, +]); +Base16Theme.add("pico", "Pico", [ + 0x000000, 0x1d2b53, 0x7e2553, 0x008751, + 0xab5236, 0x5f574f, 0xc2c3c7, 0xfff1e8, + 0xff004d, 0xffa300, 0xfff024, 0x00e756, + 0x29adff, 0x83769c, 0xff77a8, 0xffccaa, +]); +Base16Theme.add("pop", "Pop", [ + 0x000000, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xeb008a, 0xf29333, 0xf8ca12, 0x37b349, + 0x00aabb, 0x0e5a94, 0xb31e8d, 0x7a2d00, +]); +Base16Theme.add("porple", "Porple", [ + 0x292c36, 0x333344, 0x474160, 0x65568a, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xf84547, 0xd28e5d, 0xefa16b, 0x95c76f, + 0x64878f, 0x8485ce, 0xb74989, 0x986841, +]); +Base16Theme.add("qualia", "Qualia", [ + 0x101010, 0x454545, 0x454545, 0x454545, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0x454545, + 0xefa6a2, 0xa3b8ef, 0xe6a3dc, 0x80c990, + 0xc8c874, 0x50cacd, 0xe0af85, 0x808080, +]); +Base16Theme.add("railscasts", "Railscasts", [ + 0x2b2b2b, 0x272935, 0x3a4055, 0x5a647e, + 0xd4cfc9, 0xe6e1dc, 0xf4f1ed, 0xf9f7f3, + 0xda4939, 0xcc7833, 0xffc66d, 0xa5c261, + 0x519f50, 0x6d9cbe, 0xb6b3eb, 0xbc9458, +]); +Base16Theme.add("rebecca", "Rebecca", [ + 0x292a44, 0x663399, 0x383a62, 0x666699, + 0xa0a0c5, 0xf1eff8, 0xccccff, 0x53495d, + 0xa0a0c5, 0xefe4a1, 0xae81ff, 0x6dfedf, + 0x8eaee0, 0x2de0a7, 0x7aa5ff, 0xff79c6, +]); +Base16Theme.add("seti", "Seti UI", [ + 0x151718, 0x282a2b, 0x3B758C, 0x41535B, + 0x43a5d5, 0xd6d6d6, 0xeeeeee, 0xffffff, + 0xcd3f45, 0xdb7b55, 0xe6cd69, 0x9fca56, + 0x55dbbe, 0x55b5db, 0xa074c4, 0x8a553f, +]); +Base16Theme.add("shapeshifter", "Shapeshifter", [ + 0xf9f9f9, 0xe0e0e0, 0xababab, 0x555555, + 0x343434, 0x102015, 0x040404, 0x000000, + 0xe92f2f, 0xe09448, 0xdddd13, 0x0ed839, + 0x23edda, 0x3b48e3, 0xf996e2, 0x69542d, +]); +Base16Theme.add("snazzy", "Snazzy", [ + 0x282a36, 0x34353e, 0x43454f, 0x78787e, + 0xa5a5a9, 0xe2e4e5, 0xeff0eb, 0xf1f1f0, + 0xff5c57, 0xff9f43, 0xf3f99d, 0x5af78e, + 0x9aedfe, 0x57c7ff, 0xff6ac1, 0xb2643c, +]); +Base16Theme.add("solarflare", "Solar Flare", [ + 0x18262F, 0x222E38, 0x586875, 0x667581, + 0x85939E, 0xA6AFB8, 0xE8E9ED, 0xF5F7FA, + 0xEF5253, 0xE66B2B, 0xE4B51C, 0x7CC844, + 0x52CBB0, 0x33B5E1, 0xA363D5, 0xD73C9A, +]); +Base16Theme.add("solarized-dark", "Solarized Dark", [ + 0x002b36, 0x073642, 0x586e75, 0x657b83, + 0x839496, 0x93a1a1, 0xeee8d5, 0xfdf6e3, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, +]); +Base16Theme.add("solarized-light", "Solarized Light", [ + 0xfdf6e3, 0xeee8d5, 0x93a1a1, 0x839496, + 0x657b83, 0x586e75, 0x073642, 0x002b36, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, +]); +Base16Theme.add("spacemacs", "Spacemacs", [ + 0x1f2022, 0x282828, 0x444155, 0x585858, + 0xb8b8b8, 0xa3a3a3, 0xe8e8e8, 0xf8f8f8, + 0xf2241f, 0xffa500, 0xb1951d, 0x67b11d, + 0x2d9574, 0x4f97d7, 0xa31db1, 0xb03060, +]); +Base16Theme.add("summerfruit-dark", "Summerfruit Dark", [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xFFFFFF, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, +]); +Base16Theme.add("summerfruit-light", "Summerfruit Light", [ + 0xFFFFFF, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x000000, 0x101010, 0x151515, 0x202020, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, +]); +Base16Theme.add("synth-midnight-dark", "Synth Midnight", [ + 0x040404, 0x141414, 0x242424, 0x61507A, + 0xBFBBBF, 0xDFDBDF, 0xEFEBEF, 0xFFFBFF, + 0xB53B50, 0xE4600E, 0xDAE84D, 0x06EA61, + 0x7CEDE9, 0x03AEFF, 0xEA5CE2, 0x9D4D0E, +]); +Base16Theme.add("tomorrow-night-eighties", "Tomorrow Night Eighties", [ + 0x2d2d2d, 0x393939, 0x515151, 0x999999, + 0xb4b7b4, 0xcccccc, 0xe0e0e0, 0xffffff, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xa3685a, +]); +Base16Theme.add("tomorrow-night", "Tomorrow Night", [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xcc6666, 0xde935f, 0xf0c674, 0xb5bd68, + 0x8abeb7, 0x81a2be, 0xb294bb, 0xa3685a, +]); +Base16Theme.add("tomorrow", "Tomorrow", [ + 0xffffff, 0xe0e0e0, 0xd6d6d6, 0x8e908c, + 0x969896, 0x4d4d4c, 0x282a2e, 0x1d1f21, + 0xc82829, 0xf5871f, 0xeab700, 0x718c00, + 0x3e999f, 0x4271ae, 0x8959a8, 0xa3685a, +]); +Base16Theme.add("tube", "London Tube", [ + 0x231f20, 0x1c3f95, 0x5a5758, 0x737171, + 0x959ca1, 0xd9d8d8, 0xe7e7e8, 0xffffff, + 0xee2e24, 0xf386a1, 0xffd204, 0x00853e, + 0x85cebc, 0x009ddc, 0x98005d, 0xb06110, +]); +Base16Theme.add("twilight", "Twilight", [ + 0x1e1e1e, 0x323537, 0x464b50, 0x5f5a60, + 0x838184, 0xa7a7a7, 0xc3c3c3, 0xffffff, + 0xcf6a4c, 0xcda869, 0xf9ee98, 0x8f9d6a, + 0xafc4db, 0x7587a6, 0x9b859d, 0x9b703f, +]); +Base16Theme.add("unikitty-dark", "Unikitty Dark", [ + 0x2e2a31, 0x4a464d, 0x666369, 0x838085, + 0x9f9da2, 0xbcbabe, 0xd8d7da, 0xf5f4f7, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x796af5, 0xbb60ea, 0xc720ca, +]); +Base16Theme.add("unikitty-light", "Unikitty Light", [ + 0xffffff, 0xe1e1e2, 0xc4c3c5, 0xa7a5a8, + 0x89878b, 0x6c696e, 0x4f4b51, 0x322d34, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x775dff, 0xaa17e6, 0xe013d0, +]); +Base16Theme.add("woodland", "Woodland", [ + 0x231e18, 0x302b25, 0x48413a, 0x9d8b70, + 0xb4a490, 0xcabcb1, 0xd7c8bc, 0xe4d4c8, + 0xd35c5c, 0xca7f32, 0xe0ac16, 0xb7ba53, + 0x6eb958, 0x88a4d3, 0xbb90e2, 0xb49368, +]); +Base16Theme.add("xcode-dusk", "XCode Dusk", [ + 0x282B35, 0x3D4048, 0x53555D, 0x686A71, + 0x7E8086, 0x939599, 0xA9AAAE, 0xBEBFC2, + 0xB21889, 0x786DC5, 0x438288, 0xDF0002, + 0x00A0BE, 0x790EAD, 0xB21889, 0xC77C48, +]); +Base16Theme.add("zenburn", "Zenburn", [ + 0x383838, 0x404040, 0x606060, 0x6f6f6f, + 0x808080, 0xdcdccc, 0xc0c0c0, 0xffffff, + 0xdca3a3, 0xdfaf8f, 0xe0cf9f, 0x5f7f5f, + 0x93e0e3, 0x7cb8bb, 0xdc8cc3, 0x000000, +]); diff --git a/js/model/LabelColors.js b/js/model/LabelColors.js new file mode 100644 index 0000000..c51b8a3 --- /dev/null +++ b/js/model/LabelColors.js @@ -0,0 +1,69 @@ +import Gdk from 'gi://Gdk?version=4.0'; +import Gio from 'gi://Gio'; +const CITADEL_SETTINGS_SCHEMA = 'com.subgraph.citadel'; +const LABEL_COLOR_LIST_KEY = 'label-color-list'; +const REALM_LABEL_COLORS_KEY = 'realm-label-colors'; +const DEFAULT_LABEL_COLOR = new Gdk.RGBA({ red: 153, green: 193, blue: 241, }); +export class LabelColorManager { + constructor() { + this._citadelSettings = new Gio.Settings({ schema_id: CITADEL_SETTINGS_SCHEMA }); + this._defaultColors = []; + this._realmLabelColors = new Map(); + this._loadColors(); + } + _loadColors() { + let entries = this._citadelSettings.get_strv(LABEL_COLOR_LIST_KEY); + entries.forEach(entry => { + let c = new Gdk.RGBA(); + if (c.parse(entry)) { + this._defaultColors.push(c); + } + }); + entries = this._citadelSettings.get_strv(REALM_LABEL_COLORS_KEY); + entries.forEach(entry => { + let parts = entry.split(":"); + if (parts.length === 2) { + let c = new Gdk.RGBA(); + if (c.parse(parts[1])) { + this._realmLabelColors.set(parts[0], c); + } + } + }); + } + updateRealmColor(realm, color) { + this._realmLabelColors.set(realm.name, color); + this._storeRealmColors(); + } + lookupRealmColor(realm) { + let c = this._realmLabelColors.get(realm.name); + if (c) { + return c; + } + let newColor = this._allocateColor(); + this.updateRealmColor(realm, newColor); + return newColor; + } + _storeRealmColors() { + let entries = []; + this._realmLabelColors.forEach((v, k) => { + entries.push(`${k}:${v.to_string()}`); + }); + entries.sort(); + this._citadelSettings.set_strv(REALM_LABEL_COLORS_KEY, entries); + } + _allocateColor() { + // 1) No default colors? return a built in color + if (this._defaultColors.length === 0) { + return DEFAULT_LABEL_COLOR; + } + // 2) Find first color on default color list that isn't used already + let usedColors = Array.from(this._realmLabelColors.values()); + let defaultColor = this._defaultColors.find(color => !usedColors.some(c => c.equal(color))); + if (defaultColor) { + return defaultColor; + } + // 3) Choose a random element of the default list + let index = Math.floor(Math.random() * this._defaultColors.length); + return this._defaultColors[index]; + } +} diff --git a/js/model/ObjectManager.js b/js/model/ObjectManager.js new file mode 100644 index 0000000..ab3feb4 --- /dev/null +++ b/js/model/ObjectManager.js @@ -0,0 +1,183 @@ +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +const Signals = imports.signals; +Gio._promisify(Gio.DBusProxy.prototype, 'init_async', 'init_finish'); +// Specified in the D-Bus specification here: +// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager +const ObjectManagerIface = ` + + + + + + + + + + + + + + +`; +const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface); +; +export class ObjectManager { + constructor(params) { + var _a; + this._connection = params.connection; + this._serviceName = params.name; + this._managerPath = params.objectPath; + this._cancellable = (_a = params.cancellable) !== null && _a !== void 0 ? _a : null; + this._managerProxy = new Gio.DBusProxy({ + g_connection: this._connection, + g_interface_name: ObjectManagerInfo.name, + g_interface_info: ObjectManagerInfo, + g_name: this._serviceName, + g_object_path: this._managerPath, + g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START, + }); + this._interfaceInfos = {}; + this._objects = {}; + this._interfaces = {}; + this._onLoaded = params.onLoaded; + if (params.knownInterfaces) + this._registerInterfaces(params.knownInterfaces); + this._initManagerProxy(); + } + _completeLoad() { + if (this._onLoaded) + this._onLoaded(); + } + async _addInterface(objectPath, interfaceName) { + let info = this._interfaceInfos[interfaceName]; + if (!info) + return; + const proxy = new Gio.DBusProxy({ + g_connection: this._connection, + g_name: this._serviceName, + g_object_path: objectPath, + g_interface_name: interfaceName, + g_interface_info: info, + g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START, + }); + try { + await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable); + } + catch (e) { + logError(e, `could not initialize proxy for interface ${interfaceName}`); + return; + } + let isNewObject; + if (!this._objects[objectPath]) { + this._objects[objectPath] = {}; + isNewObject = true; + } + else { + isNewObject = false; + } + this._objects[objectPath][interfaceName] = proxy; + if (!this._interfaces[interfaceName]) + this._interfaces[interfaceName] = []; + this._interfaces[interfaceName].push(proxy); + if (isNewObject) + this.emit('object-added', objectPath); + this.emit('interface-added', interfaceName, proxy); + } + _removeInterface(objectPath, interfaceName) { + if (!this._objects[objectPath]) + return; + let proxy = this._objects[objectPath][interfaceName]; + if (this._interfaces[interfaceName]) { + let index = this._interfaces[interfaceName].indexOf(proxy); + if (index >= 0) + this._interfaces[interfaceName].splice(index, 1); + if (this._interfaces[interfaceName].length === 0) + delete this._interfaces[interfaceName]; + } + this.emit('interface-removed', interfaceName, proxy); + delete this._objects[objectPath][interfaceName]; + if (Object.keys(this._objects[objectPath]).length === 0) { + delete this._objects[objectPath]; + this.emit('object-removed', objectPath); + } + } + async _initManagerProxy() { + try { + await this._managerProxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable); + } + catch (e) { + logError(e, `could not initialize object manager for object ${this._serviceName}`); + this._completeLoad(); + return; + } + this._managerProxy.connectSignal('InterfacesAdded', (_objectManager, _sender, [objectPath, interfaces]) => { + let interfaceNames = Object.keys(interfaces); + for (let i = 0; i < interfaceNames.length; i++) + this._addInterface(objectPath, interfaceNames[i]); + }); + this._managerProxy.connectSignal('InterfacesRemoved', (_objectManager, _sender, [objectPath, interfaceNames]) => { + for (let i = 0; i < interfaceNames.length; i++) + this._removeInterface(objectPath, interfaceNames[i]); + }); + if (Object.keys(this._interfaceInfos).length === 0) { + this._completeLoad(); + return; + } + this._managerProxy.connect('notify::g-name-owner', () => { + if (this._managerProxy.g_name_owner) + this._onNameAppeared(); + else + this._onNameVanished(); + }); + if (this._managerProxy.g_name_owner) + this._onNameAppeared().catch(logError); + } + async _onNameAppeared() { + try { + const [objects] = await this._managerProxy.GetManagedObjectsAsync(); + if (!objects) { + this._completeLoad(); + return; + } + const objectPaths = Object.keys(objects); + await Promise.allSettled(objectPaths.flatMap(objectPath => { + const object = objects[objectPath]; + const interfaceNames = Object.getOwnPropertyNames(object); + return interfaceNames.map(ifaceName => this._addInterface(objectPath, ifaceName)); + })); + } + catch (error) { + logError(error, `could not get remote objects for service ${this._serviceName} path ${this._managerPath}`); + } + finally { + this._completeLoad(); + } + } + _onNameVanished() { + let objectPaths = Object.keys(this._objects); + for (let i = 0; i < objectPaths.length; i++) { + let objectPath = objectPaths[i]; + let object = this._objects[objectPath]; + let interfaceNames = Object.keys(object); + for (let j = 0; j < interfaceNames.length; j++) { + let interfaceName = interfaceNames[j]; + if (object[interfaceName]) + this._removeInterface(objectPath, interfaceName); + } + } + } + _registerInterfaces(interfaces) { + for (let i = 0; i < interfaces.length; i++) { + let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]); + this._interfaceInfos[info.name] = info; + } + } + getProxiesForInterface(interfaceName) { + let proxyList = this._interfaces[interfaceName]; + if (!proxyList) + return []; + return proxyList; + } +} +Signals.addSignalMethods(ObjectManager.prototype); diff --git a/js/model/OptionData.js b/js/model/OptionData.js new file mode 100644 index 0000000..99737b6 --- /dev/null +++ b/js/model/OptionData.js @@ -0,0 +1,73 @@ +export class OptionData { + constructor(description, tooltip) { + this.tooltip = tooltip; + this.description = description; + } + static add(name, description, tooltip) { + OptionData.map.set(name, new OptionData(description, tooltip)); + } + static description(name) { + var _a; + return (_a = OptionData.map.get(name)) === null || _a === void 0 ? void 0 : _a.description; + } + static tooltip(name) { + var _a; + return (_a = OptionData.map.get(name)) === null || _a === void 0 ? void 0 : _a.tooltip; + } +} +OptionData.map = new Map(); +OptionData.add('use-gpu', 'Use GPU in Realm', `If enabled the render node device /dev/dri/renderD128 will be mounted into the realm container. + +If privileged device /dev/dri/card0 is also needed set +additional variable in realm configuration file: + + use-gpu-card0 = true +`); +OptionData.add('use-wayland', 'Use Wayland in Realm', `If enabled access to Wayland display will be permitted in realm by adding wayland socket to realm. + + /run/user/1000/wayland-0 + +`); +OptionData.add('use-x11', 'Use X11 in Realm', `If enabled access to X11 server will be added by mounting directory X11 directory into realm. + + /tmp/.X11-unix + +`); +OptionData.add('use-sound', 'Use sound in Realm', `If enabled allows use of sound inside of realm. The following items will be added: + + /dev/snd + /dev/shm + /run/user/1000/pulse + +`); +OptionData.add('use-shared-dir', 'Mount /Shared directory in Realm', `If enabled the shared directory will be mounted as /Shared in home directory of realm. + +This directory is shared between all realms with this option enabled and is an easy way to move files between realms. + +`); +OptionData.add('use-network', 'Realm has network access', `If enabled the realm will have access to the network.`); +OptionData.add('use-kvm', 'Use KVM (/dev/kvm) in Realm', `If enabled device /dev/kvm will be added to realm`); +OptionData.add('use-ephemeral-home', 'Use ephemeral tmpfs mount for home directory', `If enabled the home directory of realm will be set up in ephemeral mode. + +The ephemeral home directory is set up with the following steps: + + 1. Home directory is mounted as tmpfs filesystem + 2. Any files in /realms/skel are copied into home directory + 3. Any files in /realms/realm-$name/skel are copied into home directory. + 4. Any directories listed in config file variable ephemeral_persistent_dirs + are bind mounted from /realms/realm-$name/home into ephemeral + home directory. + +`); +OptionData.add('overlay', 'Type of rootfs overlay Realm is configured to use.', `Overlay +Type of rootfs overlay realm is configured to use. + None Don't use a rootfs overlay + TmpFS Use a rootfs overlay stored on tmpfs + Storage Use a rootfs overlay stored on disk in storage partition +`); +OptionData.add('realmfs', 'Root filesystem image to use for Realm.', `RealmFS +Root filesystem image to use for realm.`); +OptionData.add('colorscheme', 'Terminal Color Scheme', `Terminal Color Scheme +Choose a color scheme to use in the terminals in this realm.`); +OptionData.add('window-label-color', 'Window Label Color', `Window Label Color +Set a color to be used when a label is drawn on the window titlebar indicating which realm the application is running in.`); diff --git a/js/model/Realm.js b/js/model/Realm.js new file mode 100644 index 0000000..b2b8c6f --- /dev/null +++ b/js/model/Realm.js @@ -0,0 +1,94 @@ +var _a; +import GObject from 'gi://GObject'; +import { RealmFS } from './RealmFS.js'; +import { RealmConfig } from './RealmConfig.js'; +export const RunStatus = { + STOPPED: 0, + STARTING: 1, + RUNNING: 2, + CURRENT: 3, + STOPPING: 4, +}; +export class Realm extends GObject.Object { + constructor(proxy, labelColors) { + super(); + this.config = new RealmConfig(); + this._proxy = proxy; + this._labelColors = labelColors; + this._proxy.connect('g-properties-changed', (_proxy, _changed, _invalidated) => { + this._sync(); + }); + this._sync(); + } + get realmfs() { + return this._realmfs; + } + set realmfs(value) { + if (this.realmfs === value) { + return; + } + this._realmfs = value; + this.emit('changed'); + } + _sync() { + this._name = this._proxy.Name; + this._description = this._proxy.Description; + this._pidns = this._proxy.PidNS; + this._run_status = this._proxy.RunStatus; + this._is_system_realm = this._proxy.IsSystemRealm; + this.emit('changed'); + } + get name() { + return this._name; + } + get description() { + return this._description; + } + get pidns() { + return this._pidns; + } + get run_status() { + return this._run_status; + } + get is_system_realm() { + return this._is_system_realm; + } + is_running() { + return this.run_status === RunStatus.RUNNING || this.run_status === RunStatus.CURRENT; + } + is_current() { + return this.run_status === RunStatus.CURRENT; + } + getLabelColor() { + return this._labelColors.lookupRealmColor(this); + } + setLabelColor(color) { + this._labelColors.updateRealmColor(this, color); + } + realmfs_index() { + return this._proxy.RealmFS; + } + set_global_config(config) { + this.config.set_global_config(config); + } + async load_config() { + const result = await this._proxy.GetConfigAsync(); + this.config.set_config(result[0]); + this.emit('changed'); + } +} +_a = Realm; +(() => { + GObject.registerClass({ + GTypeName: 'Realm', + Properties: { + 'name': GObject.ParamSpec.string('name', '', '', GObject.ParamFlags.READWRITE, ''), + 'description': GObject.ParamSpec.string('description', '', '', GObject.ParamFlags.READWRITE, ''), + 'pidns': GObject.ParamSpec.uint64('pidns', '', '', GObject.ParamFlags.READWRITE, 0, Number.MAX_SAFE_INTEGER, 0), + 'run-status': GObject.ParamSpec.uint('run-status', '', '', GObject.ParamFlags.READWRITE, 0, 4, 0), + 'is-system-realm': GObject.ParamSpec.boolean('is-system-realm', '', '', GObject.ParamFlags.READWRITE, false), + 'realmfs': GObject.ParamSpec.object('realmfs', '', '', GObject.ParamFlags.READWRITE, RealmFS), + }, + Signals: { 'changed': {} }, + }, _a); +})(); diff --git a/js/model/RealmConfig.js b/js/model/RealmConfig.js new file mode 100644 index 0000000..5c04802 --- /dev/null +++ b/js/model/RealmConfig.js @@ -0,0 +1,94 @@ +import { OptionData } from './OptionData.js'; +export class BoolOptionData { + constructor(name) { + var _a, _b; + this.name = name; + this.description = (_a = OptionData.description(name)) !== null && _a !== void 0 ? _a : name; + this.tooltip = (_b = OptionData.tooltip(name)) !== null && _b !== void 0 ? _b : ""; + } + static allOptions() { + let options = []; + BoolOptionData.ALL_OPTIONS.forEach(name => { + options.push(new BoolOptionData(name)); + }); + return options; + } +} +BoolOptionData.ALL_OPTIONS = [ + 'use-gpu', + 'use-wayland', + 'use-x11', + 'use-sound', + 'use-network', + 'use-kvm', + 'use-shared-dir', + 'use-ephemeral-home', +]; +export class ConfigOption { + constructor(name, value, defaultValue, description, tooltip) { + this.name = name; + this.value = value; + this.defaultValue = defaultValue; + this.description = description; + this.tooltip = tooltip; + } +} +export class RealmConfig { + constructor() { + this._configVars = {}; + this._globalConfig = {}; + } + set_config(config) { + this._configVars = config; + } + set_global_config(globalConfig) { + this._globalConfig = globalConfig; + } + get_var(name) { + let value = this._configVars[name]; + if (value && value.length > 0) { + return value; + } + value = this._globalConfig[name]; + if (value && value.length > 0) { + return value; + } + return null; + } + get_bool(name) { + return this.get_var(name) === 'true'; + } + get_colorscheme() { + var _a; + return (_a = this.get_var('terminal-scheme')) !== null && _a !== void 0 ? _a : 'default-dark'; + } + get_realmfs() { + var _a; + return (_a = this.get_var('realmfs')) !== null && _a !== void 0 ? _a : 'base'; + } + static capitalize(term) { + const acronyms = ["gpu", "kvm"]; + if (acronyms.find(s => term === s)) { + return term.toUpperCase(); + } + else { + return term.charAt(0).toUpperCase() + term.slice(1); + } + } + static option_label(key) { + return key.substring(4) + .split('-') + .map(RealmConfig.capitalize) + .join(''); + } + is_enabled_bool_option(name, value, isDefault) { + const default_val = this._globalConfig[name]; + return name.startsWith("use-") && value === "true" && (value === default_val) === isDefault; + } + enabled_bool_option_labels(isDefault) { + return Object.entries(this._configVars) + .filter(([k, v]) => this.is_enabled_bool_option(k, v, isDefault)) + .map(([k,]) => RealmConfig.option_label(k)) + .sort(); + } +} diff --git a/js/model/RealmFS.js b/js/model/RealmFS.js new file mode 100644 index 0000000..e0f60a7 --- /dev/null +++ b/js/model/RealmFS.js @@ -0,0 +1,69 @@ +var _a; +import GObject from 'gi://GObject'; +const OBJECT_PREFIX = "/com/subgraph/Realms2/RealmFS"; +export class RealmFS extends GObject.Object { + constructor(proxy) { + super(); + this._proxy = proxy; + this._proxy.connect('g-properties-changed', (_proxy, _changed, _invalidated) => { + this._sync(); + }); + this._sync(); + } + index() { + let path = this._proxy.get_object_path(); + if (path.startsWith(OBJECT_PREFIX)) { + const tail = path.substring(OBJECT_PREFIX.length); + let index = Number.parseInt(tail); + if (!Number.isNaN(index)) { + return index; + } + } + return -1; + } + get name() { + return this._name; + } + get in_use() { + return this._in_use; + } + get activated() { + return this._activated; + } + get mountpoint() { + return this._mountpoint; + } + get path() { + return this._path; + } + get free_space() { + return this._free_space; + } + get allocated_space() { + return this._allocated_space; + } + _sync() { + this._name = this._proxy.Name; + this._in_use = this._proxy.InUse; + this._activated = this._proxy.Activated; + this._mountpoint = this._proxy.Mountpoint; + this._path = this._proxy.Path; + this._free_space = this._proxy.FreeSpace; + this._allocated_space = this._proxy.AllocatedSpace; + } +} +_a = RealmFS; +(() => { + GObject.registerClass({ + GTypeName: 'RealmFS', + Properties: { + 'name': GObject.ParamSpec.string('name', '', '', GObject.ParamFlags.READWRITE, ''), + 'in-use': GObject.ParamSpec.boolean('in-use', '', '', GObject.ParamFlags.READWRITE, false), + 'activated': GObject.ParamSpec.boolean('activated', '', '', GObject.ParamFlags.READWRITE, false), + 'mountpoint': GObject.ParamSpec.string('mountpoint', '', '', GObject.ParamFlags.READWRITE, ''), + 'path': GObject.ParamSpec.string('path', '', '', GObject.ParamFlags.READWRITE, ''), + 'free-space': GObject.ParamSpec.uint64('free-space', '', '', GObject.ParamFlags.READWRITE, 0, Number.MAX_SAFE_INTEGER, 0), + 'allocated-space': GObject.ParamSpec.uint64('allocated-space', '', '', GObject.ParamFlags.READWRITE, 0, Number.MAX_SAFE_INTEGER, 0), + }, + }, _a); +})(); diff --git a/js/model/RealmManager.js b/js/model/RealmManager.js new file mode 100644 index 0000000..51969d8 --- /dev/null +++ b/js/model/RealmManager.js @@ -0,0 +1,140 @@ +import Gio from 'gi://Gio'; +import { ObjectManager } from './ObjectManager.js'; +import { loadInterfaceXML } from './Utils.js'; +import { Realm } from './Realm.js'; +import { RealmFS } from './RealmFS.js'; +import { LabelColorManager } from './LabelColors.js'; +const Signals = imports.signals; +const RealmIface = loadInterfaceXML("com.subgraph.realms.Realm"); +const RealmFSIface = loadInterfaceXML("com.subgraph.realms.RealmFS"); +const BUS_NAME = 'com.subgraph.Realms2'; +const OBJECT_PATH = '/com/subgraph/Realms2'; +const ManagerInterface = loadInterfaceXML("com.subgraph.realms.Manager2"); +const ManagerProxy = Gio.DBusProxy.makeProxyWrapper(ManagerInterface); +; +export class RealmManager { + static instance() { + return RealmManager.INSTANCE; + } + constructor() { + this._globalConfig = {}; + this._realms = {}; + this._realmfs = {}; + this._realmfs = {}; + this._objectManager = new ObjectManager({ + connection: Gio.DBus.system, + name: 'com.subgraph.Realms2', + objectPath: '/com/subgraph/Realms2', + knownInterfaces: [RealmIface, RealmFSIface], + onLoaded: this._onLoaded.bind(this), + }); + this._proxy = new ManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH, (_proxy, error) => { + if (error) { + logError(error); + } + else { + this._setGlobalConfig().catch(logError); + } + }); + this._labelColors = new LabelColorManager(); + } + async _setGlobalConfig() { + let result = await this._proxy.GetGlobalConfigAsync(); + this._globalConfig = result[0]; + this._assignGlobalConfigToRealms(); + } + async _onLoaded() { + let realms = this._objectManager.getProxiesForInterface('com.subgraph.realms.Realm'); + for (let i = 0; i < realms.length; i++) { + this._addRealm(realms[i]); + } + let realmfs = this._objectManager.getProxiesForInterface('com.subgraph.realms.RealmFS'); + for (let i = 0; i < realmfs.length; i++) { + this._addRealmFS(realmfs[i]); + } + this._objectManager.connect('interface-added', (_objectManager, interfaceName, proxy) => { + if (interfaceName === 'com.subgraph.Realm') { + this._addRealm(proxy); + } + else if (interfaceName === 'com.subgraph.RealmFS') { + this._addRealmFS(proxy); + } + }); + this._objectManager.connect('interface-removed', (_objectManager, interfaceName, proxy) => { + if (interfaceName === 'com.subgraph.Realm') { + this._removeRealm(proxy); + } + else if (interfaceName === 'com.subgraph.RealmFS') { + this._removeRealmFS(proxy); + } + }); + } + async _addRealm(proxy) { + let objectPath = proxy.get_object_path(); + let realm = new Realm(proxy, this._labelColors); + this._realms[objectPath] = realm; + this._findRealmFSForRealm(realm); + if (this._globalConfig) { + realm.set_global_config(this._globalConfig); + } + await realm.load_config(); + this.emit('realm-added', realm); + } + _removeRealm(proxy) { + var _a; + let objectPath = proxy.get_object_path(); + if (((_a = this._realms[objectPath]) === null || _a === void 0 ? void 0 : _a._proxy) === proxy) { + let realm = this._realms[objectPath]; + delete this._realms[objectPath]; + this.emit('realm-removed', realm); + } + proxy.disconnectAll(); + } + _addRealmFS(proxy) { + let objectPath = proxy.get_object_path(); + let realmfs = new RealmFS(proxy); + this._realmfs[objectPath] = realmfs; + this._assignRealmFSToRealms(realmfs); + this.emit('realmfs-added', realmfs); + } + _findRealmFSForRealm(realm) { + var _a; + if (realm.realmfs_index() > 0) { + realm.realmfs = (_a = Object.values(this._realmfs) + .find(realmfs => realmfs.index() === realm.realmfs_index())) !== null && _a !== void 0 ? _a : null; + } + } + realmfsList() { + return Object.values(this._realmfs); + } + _assignRealmFSToRealms(realmfs) { + Object.values(this._realms).forEach(r => { + if (r.realmfs_index() > 0 && r.realmfs_index() === realmfs.index() && r.realmfs != realmfs) { + r.realmfs = realmfs; + } + }); + } + _assignGlobalConfigToRealms() { + Object.values(this._realms).forEach(r => r.set_global_config(this._globalConfig)); + } + _removeRealmFSFromRealms(realmfs) { + Object.values(this._realms).forEach(r => { + if (r.realmfs === realmfs) { + r.realmfs = null; + } + }); + } + _removeRealmFS(proxy) { + var _a; + let objectPath = proxy.get_object_path(); + if (((_a = this._realmfs[objectPath]) === null || _a === void 0 ? void 0 : _a._proxy) === proxy) { + let realmfs = this._realmfs[objectPath]; + delete this._realmfs[objectPath]; + this._removeRealmFSFromRealms(realmfs); + this.emit('realmfs-removed', realmfs); + } + proxy.disconnectAll(); + } +} +RealmManager.INSTANCE = new RealmManager(); +Signals.addSignalMethods(RealmManager.prototype); diff --git a/js/model/Utils.js b/js/model/Utils.js new file mode 100644 index 0000000..d256968 --- /dev/null +++ b/js/model/Utils.js @@ -0,0 +1,14 @@ +import Gio from 'gi://Gio'; +export function loadInterfaceXML(iface) { + let uri = `resource:///com/subgraph/citadel/Realms/dbus-interfaces/${iface}.xml`; + let f = Gio.File.new_for_uri(uri); + try { + let [_ok, bytes] = f.load_contents(null); + // @ts-ignore + return new TextDecoder().decode(bytes); + } + catch (e) { + log(`Failed to load D-Bus interface ${iface}`); + } + return null; +} diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..3abee6f --- /dev/null +++ b/meson.build @@ -0,0 +1,16 @@ +project( + 'Realms', + version: '0.0.1', + license: ['GLP-Stallmans-Razor'], + meson_version: '>= 0.59.0' +) + +APP_ID = 'com.subgraph.citadel.Realms' + +gnome = import('gnome') + +#tsc = find_program('tsc', required: true) + +subdir('data') +subdir('src') + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1681cca --- /dev/null +++ b/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "Realms", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "Realms", + "version": "1.0.0", + "dependencies": { + "typescript": "^5.3.3" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5446e5b --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "Realms", + "version": "1.0.0", + "main": "src/main.ts", + "dependencies": { + "typescript": "^5.3.3" + }, + "scripts": { + "build": "tsc --strict", + "typecheck": "tsc --strict --noEmit" + } +} diff --git a/src/Application.ts b/src/Application.ts new file mode 100644 index 0000000..8bbc585 --- /dev/null +++ b/src/Application.ts @@ -0,0 +1,120 @@ +import Adw from 'gi://Adw'; +import Gtk from 'gi://Gtk?version=4.0'; +import Gio from 'gi://Gio'; +import GObject from 'gi://GObject'; + +import './model/RealmManager.js'; +import './model/Realm.js'; +import './RealmsView.js'; +import './RealmRow.js'; +import './RealmInfo.js'; +import './RealmModel.js'; +import './ConfigureRealm.js'; + + +import { Window } from './Window.js'; + + +export class Application extends Adw.Application { + static { + GObject.registerClass({ + GTypeName: 'RealmsApplication' + }, this); + } + + _window?: Window; + + constructor() { + super({ + application_id: 'com.subgraph.citadel.Realms', + flags: Gio.ApplicationFlags.DEFAULT_FLAGS, + }) + } + + vfunc_activate() { + let {activeWindow} = this; + if (!activeWindow) { + activeWindow = new Window(this); + activeWindow.set_hide_on_close(true); + } + activeWindow.present(); + } + + vfunc_startup() { + super.vfunc_startup(); + this.#setupActions(); + this.#setupAccelerators(); +// this.#loadStyleSheet(); + const styleManager = Adw.StyleManager.get_default(); + styleManager.colorScheme = Adw.ColorScheme.FORCE_DARK; + } + + /* + #loadStyleSheet() { + const provider = new Gtk.CssProvider(); + provider.load_from_resource('/com/subgraph/citadel/Realms/css/style.css'); + + const display = Gdk.Display.get_default(); + if (display) { + Gtk.StyleContext.add_provider_for_display( + display, + provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); + } + } + */ + + #setupAccelerators() { + this.set_accels_for_action('app.quit', ['q']); + this.set_accels_for_action('app.realmConfig', ['c']); + this.set_accels_for_action('app.showHelp', ['h','question']); + } + + #setupActions() { + this.add_action_entries([ + // @ts-ignore + { name: 'quit', activate: this.#onQuit.bind(this) }, + // @ts-ignore + { name: 'realmConfig', activate: this.#onRealmConfig.bind(this) }, + // @ts-ignore + { name: 'showHelp', activate: this.#onShowHelp.bind(this) }, + // @ts-ignore + { name: 'about', activate: this.#onAbout.bind(this) }, + ]); + } + + #onQuit() { + let {activeWindow} = this; + if (activeWindow) { + activeWindow.close(); + } + } + + #onRealmConfig() { + let {activeWindow} = this; + if (activeWindow) { + let window = activeWindow as Window; + + const realm = window.realms_view.selectedRealm; + if (realm) { + window.configureRealm(realm); + } + } + } + + #onShowHelp() { + const help: Gtk.ShortcutsWindow = Gtk.Builder.new_from_resource('/com/subgraph/citadel/Realms/ui/HelpWindow.ui').get_object('helpWindow'); + help.set_transient_for(this._window); + help.present(); + } + + #onAbout() { + const dialog = new Adw.AboutDialog({ + application_icon: 'face-smile', + application_name: 'Realms', + developer_name: "Subgraph", + }) + dialog.present(this._window); + } +} diff --git a/src/ColorSchemeChooser.ts b/src/ColorSchemeChooser.ts new file mode 100644 index 0000000..84c0ab8 --- /dev/null +++ b/src/ColorSchemeChooser.ts @@ -0,0 +1,225 @@ +import Adw from 'gi://Adw'; +import GObject from 'gi://GObject'; +import GLib from 'gi://GLib'; +import Gdk from 'gi://Gdk?version=4.0'; +import Gtk from 'gi://Gtk?version=4.0'; + +import {Base16Theme} from './model/Base16Themes.js'; +import {ColorSchemeModel} from './ColorSchemeModel.js'; + + +class PreviewRenderer { + + private theme: Base16Theme; + private buffer: string; + + constructor(theme: Base16Theme) { + this.theme = theme; + this.buffer = ''; + + } + + colorAttrib(name: string, color: string) { + this.buffer += ` ${name}='${color}'`; + } + + colorSpan(fg: string, bg = null) { + this.buffer += '').nl() + .func('#include ').string('').nl() + .nl() + .vtype('static char').text(' theme[] = ').string(`"${name}"`).text(';').nl() + .nl() + .vtype('int').text(' main(').vtype('int').text(' argc, ').vtype('char').text(' **argv) {').nl() + .text(' printf(').string('"Hello, ').keyword('%s').text('!').keyword('\\n').string('"').text(', theme);').nl() + .text(' exit(').konst('0').text(');').nl() + .text('}') + .nl(); + + return this.buffer; + } + +} + +export class ColorSchemeChooser extends Adw.NavigationPage{ + + private _colorList!: Gtk.ListView; + private _previewLabel!: Gtk.Label; + css_provider: Gtk.CssProvider; + model: ColorSchemeModel; + + static { + GObject.registerClass({ + GTypeName: 'ColorSchemeChooser', + Template: 'resource:///com/subgraph/citadel/Realms/ui/ColorSchemeChooser.ui', + InternalChildren: ['colorList', 'previewLabel'], + }, this); + } + + addExpandToggleShortcut(keyval: number) { + let trigger = Gtk.KeyvalTrigger.new(keyval, Gdk.ModifierType.NO_MODIFIER_MASK); + let action = Gtk.CallbackAction.new((expander) => expander.activate_action('listitem.toggle-expand', null)); + Gtk.TreeExpander.add_shortcut(Gtk.Shortcut.new(trigger, action)); + } + + constructor() { + super(); + + this.model = new ColorSchemeModel(); + + this._previewLabel.add_css_class("preview"); + this.css_provider = new Gtk.CssProvider(); + + const display = Gdk.Display.get_default(); + if (display) { + Gtk.StyleContext.add_provider_for_display( + display, + this.css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); + } + + this.addExpandToggleShortcut(Gdk.KEY_space); + this.addExpandToggleShortcut(Gdk.KEY_l); + + + this._colorList.connect('activate', () => { + this.previewSelectedTheme(); + }) + this._colorList.single_click_activate = true; + this._colorList.model = this.model.selection; + + const keyController = new Gtk.EventControllerKey(); + keyController.connect('key-pressed', (_, keyval) => { + switch (keyval) { + case Gdk.KEY_j: + case Gdk.KEY_Down: + this.nextScheme(); + break; + case Gdk.KEY_k: + case Gdk.KEY_Up: + this.prevScheme(); + break; + } + }); + this._colorList.add_controller(keyController); + + } + + nextScheme() { + let pos = this.model.changeSelected(1); + if (pos) { + this._colorList.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, null); + } + } + prevScheme() { + let pos = this.model.changeSelected(-1); + if(pos) { + this._colorList.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, null); + } + } + + selectTheme(id?: string) { + const DEFAULT_THEME = '3024'; + let row = this.model.searchId(id ?? DEFAULT_THEME); + if (row) { + let pos = row.get_position(); + this.model.selectPosition(pos); + this._colorList.scroll_to(pos, Gtk.ListScrollFlags.SELECT | Gtk.ListScrollFlags.FOCUS, null); + this.previewSelectedTheme(); + } + } + + getSelectedTheme() { + return this.model.selectedTheme(); + } + + previewSelectedTheme() { + let theme = this.model.selectedTheme(); + if (theme) { + this.setBackgroundColor(theme); + let renderer = new PreviewRenderer(theme); + // @ts-ignore + this._previewLabel.label = renderer.renderPreview(); + } + } + + setBackgroundColor(theme: Base16Theme) { + let css = ` +label.preview { + background-color: ${theme.terminal_background()}; + font-family: monospace; + font-size: 14pt; +}`; + this.css_provider.load_from_string(css); + } + +} diff --git a/src/ColorSchemeModel.ts b/src/ColorSchemeModel.ts new file mode 100644 index 0000000..40b8cba --- /dev/null +++ b/src/ColorSchemeModel.ts @@ -0,0 +1,176 @@ +import GObject from 'gi://GObject'; +import Gio from 'gi://Gio'; +import Gtk from 'gi://Gtk?version=4.0'; + +import {Base16Theme} from './model/Base16Themes.js'; + +class ModelBuilder { + CATEGORIES = [ + ['atelier', 'Atelier'], + ['black-metal', 'Black Metal'], + ['brushtrees', 'Brush Trees'], + ['classic', 'Classic'], + ['default', 'Default'], + ['google', 'Google'], + ['grayscale', 'Grayscale'], + ['gruvbox', 'Gruvbox'], + ['harmonic', 'Harmonic'], + ['ia', 'iA'], + ['material', 'Material'], + ['papercolor', 'PaperColor'], + ['solarized', 'Solarized'], + ['summerfruit', 'Summerfruit'], + ['tomorrow', 'Tomorrow'], + ['unikitty', 'Unikitty'], + ]; + + currentCategory: null | ColorSchemeNode = null; + storeModel = new Gio.ListStore(ColorSchemeNode); + + + matchesCategory(theme: Base16Theme): boolean { + return (this.CATEGORIES.length > 0 && theme.id.startsWith(this.CATEGORIES[0][0])) + } + + appendCurrentCategory() { + if (this.currentCategory) { + this.storeModel.append(this.currentCategory); + this.currentCategory = null; + this.CATEGORIES.shift(); + } + } + + addToCategory(theme: Base16Theme) { + if (!this.currentCategory) { + this.currentCategory = new ColorSchemeNode(this.CATEGORIES[0][1]); + } + this.currentCategory.addChild(new ColorSchemeNode(theme.name, theme)); + } + + addTheme(theme: Base16Theme) { + if (this.matchesCategory(theme)) { + this.addToCategory(theme); + } else { + if (this.currentCategory) { + this.appendCurrentCategory(); + } + this.storeModel.append(new ColorSchemeNode(theme.name, theme)); + } + } + + static buildTreeModel(): Gtk.TreeListModel { + let builder = new ModelBuilder(); + Base16Theme.THEME_LIST.forEach(theme => builder.addTheme(theme)); + return Gtk.TreeListModel.new( + builder.storeModel, + false, + false, + item => (item as ColorSchemeNode).child_model, + ); + } + +} + +export class ColorSchemeNode extends GObject.Object { + private _text: string; + + theme: Base16Theme | null; + child_model: Gio.ListStore | null; + static { + GObject.registerClass({ + GTypeName: 'ColorSchemeNode', + Properties: { + 'text': GObject.ParamSpec.string('text', '', '', GObject.ParamFlags.READWRITE, ''), + } + + }, this); + } + + constructor(text: string, theme: Base16Theme | null = null) { + super(); + this._text = text; + this.theme = theme; + this.child_model = null; + } + + get text(): string { + return this._text; + } + + addChild(child: ColorSchemeNode) { + if(this.child_model === null) { + this.child_model = new Gio.ListStore(ColorSchemeNode); + } + this.child_model.append(child); + } + + matchesId(id: string): boolean { + return this.theme !== null && this.theme.id === id; + } + + searchChildren(id: string): boolean { + if (this.child_model) { + for(let i = 0; i < this.child_model.n_items; i++) { + let node = this.child_model.get_item(i) as ColorSchemeNode; + if (node.matchesId(id)) { + return true; + } + } + } + return false; + + } +} + +export class ColorSchemeModel { + selection: Gtk.SingleSelection; + treeModel: Gtk.TreeListModel; + constructor() { + this.treeModel = ModelBuilder.buildTreeModel(); + this.selection = Gtk.SingleSelection.new(this.treeModel); + } + + selectedTheme() { + // @ts-ignore + let item = this.selection.selected_item.item; + return item?.theme; + } + + changeSelected(offset: number) { + const n_items = this.selection.n_items; + if (n_items <= 1) { + return; + } + const pos = this.selection.selected; + if (pos == Gtk.INVALID_LIST_POSITION) { + return; + } + const newPos = pos + offset; + if (newPos < 0 || newPos >= n_items) { + return; + } + this.selection.selected = newPos; + return newPos; + } + + selectPosition(pos: number) { + this.selection.selected = pos; + } + + searchId(id: string, from = 0): Gtk.TreeListRow | null { + for(let i = from; i < this.treeModel.n_items; i++) { + let row = this.treeModel.get_row(i); + let item = row?.item as ColorSchemeNode; + if (item && item.matchesId(id)) { + return row; + } + if (item.searchChildren(id)) { + row?.set_expanded(true); + if(from === 0) { + return this.searchId(id, i); + } + } + } + return null; + } +} diff --git a/src/ConfigureRealm.ts b/src/ConfigureRealm.ts new file mode 100644 index 0000000..75e2412 --- /dev/null +++ b/src/ConfigureRealm.ts @@ -0,0 +1,189 @@ +import GObject from 'gi://GObject' +import Gdk from 'gi://Gdk?version=4.0' +import Gtk from 'gi://Gtk?version=4.0' +import Adw from 'gi://Adw'; + +import {Realm} from './model/Realm.js'; +import {BoolOptionData} from './model/RealmConfig.js'; +import {Base16Theme} from './model/Base16Themes.js'; +import { RealmManager } from './model/RealmManager.js'; +import {ColorSchemeChooser} from './ColorSchemeChooser.js'; + +class OptionState { + value: any = null; + originalValue: any; + + row: Adw.SwitchRow; + + constructor(row: Adw.SwitchRow) { + this.row = row; + } + + initValue(value: any) { + this.value = value; + this.originalValue = value; + this.row.active = value; + } + + /** @param {any} value */ + setValue(value: any) { + this.value = value; + } + + hasChanged() { + return this.value !== this.originalValue; + } + +} + +export class ConfigureRealm extends Adw.NavigationPage { + + static { + GObject.registerClass({ + GTypeName: "ConfigureRealm", + Template: 'resource:///com/subgraph/citadel/Realms/ui/ConfigureRealm.ui', + InternalChildren: ['optionsGroup', 'changedBanner', 'overlayCombo', 'realmfsCombo', 'colorSchemeButton', 'labelColorButton'], + Properties: { + 'navigation-view': GObject.ParamSpec.object('navigation-view', '', '', GObject.ParamFlags.READWRITE, Adw.NavigationView), + 'colorscheme-chooser': GObject.ParamSpec.object('colorscheme-chooser', '', '', GObject.ParamFlags.READWRITE, ColorSchemeChooser), + } + }, this); + } + + realm: Realm | null = null; + + private _colorSchemeButton!: Gtk.Button ; + + private _labelColorButton!: Gtk.ColorDialogButton; + + private _optionsGroup!: Adw.PreferencesGroup; + private _changedBanner!: Adw.Banner; + + private _navigationView!: Adw.NavigationView; + + private _colorschemeChooser!: ColorSchemeChooser; + + optionState: Map = new Map(); + + theme = Base16Theme.lookup('default-dark'); + + constructor() { + super(); + this._addOptions(); + const keyController = new Gtk.EventControllerKey(); + keyController.connect('key-pressed', (_, keyval) => { + if (keyval === Gdk.KEY_j) { + this.vfunc_move_focus(Gtk.DirectionType.TAB_FORWARD); + } else if (keyval === Gdk.KEY_k) { + this.vfunc_move_focus(Gtk.DirectionType.TAB_BACKWARD); + } + }); + + this.add_controller(keyController); + this._labelColorButton?.connect('notify::rgba', () => this._scanChanges()); + this._colorSchemeButton?.connect('clicked', () => { + this.navigationView?.push_by_tag('realm-colorscheme'); + }); + + } + + get colorschemeChooser() { + return this._colorschemeChooser; + } + + set colorschemeChooser(val) { + this._colorschemeChooser = val; + } + + set navigationView(val) { + this._navigationView = val; + this._navigationView?.connect('popped', (_view, page) => { + if (page === this.colorschemeChooser) { + let theme = this.colorschemeChooser.getSelectedTheme(); + if (theme && this._colorSchemeButton) { + this.theme = theme; + this._colorSchemeButton.label = this.theme.name; + } + } + }); + } + + get navigationView() { + return this._navigationView; + + } + + configure(realm: Realm) { + this.realm = realm; + this.set_title(`Configure realm-${realm.name}`); + this._setOptions(realm); + } + + _setOptions(realm: Realm) { + let config = realm.config; + this.optionState.forEach((op,name) => { + let v = config.get_bool(name); + op.initValue(v); + }) + + let scheme = realm.config.get_colorscheme(); + this.theme = Base16Theme.lookup(scheme); + if (this.theme && this._colorSchemeButton) { + this._colorSchemeButton.label = this.theme.name; + this.colorschemeChooser?.selectTheme(this.theme.id); + } + + let realmfs_list = RealmManager.instance().realmfsList(); + // @ts-ignore + let model = this._realmfsCombo.model; + if(model.n_items > 0) { + model.splice(0, model.n_items, []); + } + realmfs_list.forEach(realmfs => model.append(realmfs.name)); + + let labelColor = realm.getLabelColor(); + this._labelColorButton.rgba = labelColor; + + this._scanChanges(); + } + + _addOptions() { + BoolOptionData.allOptions().forEach(option => { + let row = new Adw.SwitchRow({ + title: option.description, + }); + if (option.tooltip.length > 0) { + row.tooltipMarkup = option.tooltip; + } + let state = new OptionState(row); + this.optionState.set(option.name, state); + + row.connect("notify::active", () => { + state.setValue(row.active); + this._scanChanges(); + }); + + this._optionsGroup.add(row); + }) + } + + _scanChanges() { + let changed = false; + this.optionState.forEach(op => { + if (op.hasChanged()) { + changed = true; + } + }); + let labelColor = this.realm?.getLabelColor(); + if (labelColor) { + if (!this._labelColorButton.rgba.equal(labelColor)) { + changed = true; + } + } + this._changedBanner.set_revealed(changed); + } + + _onApplyClicked() { + print("clikkk"); + } +} diff --git a/src/RealmInfo.ts b/src/RealmInfo.ts new file mode 100644 index 0000000..78109c5 --- /dev/null +++ b/src/RealmInfo.ts @@ -0,0 +1,147 @@ +import GObject from 'gi://GObject' +import Gtk from 'gi://Gtk?version=4.0'; +import {Realm} from "./model/Realm.js"; + +import {RealmInfoEntry} from './RealmInfoEntry.js'; + +const Sections = { + STATUS: 'Status', + OPTIONS: 'Options', + REALMFS: 'RealmFS', + MOUNTPOINT: 'RealmFS Mountpoint', +}; + +export class RealmInfo extends Gtk.ScrolledWindow { + private _column!: Gtk.Box; + private _columnTitle!: Gtk.Label; + + static { + GObject.registerClass({ + GTypeName: "RealmInfo", + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmInfo.ui', + Properties: { + 'realm': GObject.ParamSpec.object('realm', '', '', GObject.ParamFlags.READWRITE, Realm), + }, + InternalChildren: [ + 'column', + 'columnTitle', + ] + }, this); + } + + + _buffer = ""; + _changeId: number = 0; + _realm: Realm | null = null; + + _entries: Map = new Map(); + + constructor() { + super(); + this._addEntries({ + left: [ + Sections.STATUS, + Sections.REALMFS, + Sections.MOUNTPOINT, + Sections.OPTIONS, + ], + right: [] + }); + } + + + _addEntries(labels: { left: string[]; right: string[]; }) { + let addSectionEntries = (section: Gtk.Box, entries: string[]) => { + entries.forEach(name => { + let entry = new RealmInfoEntry(name); + this._entries.set(name, entry); + section.append(entry); + }) + }; + + addSectionEntries(this._column, labels['left']); + } + + get realm(): Realm | null { + return this._realm; + } + + set realm(value) { + if (this.realm === value) { + return; + } + if (this._realm) { + this._realm.disconnect(this._changeId); + } + this._realm = value; + if (this._realm) { + this._changeId = this._realm.connect('changed', () => { + this.displayRealm(); + }); + this.displayRealm(); + } + } + + + setEntry(name: string, value: string) { + let entry = this._entries.get(name); + if (entry) { + entry.setValue(value); + } + } + + setEntryVisible(name: string, isVisible: boolean = true) { + let entry = this._entries.get(name); + if (entry) { + entry.set_visible(isVisible); + } + + } + + displayConfig() { + let config = this._realm?.config; + if (config) { + let enabled_default = config.enabled_bool_option_labels(true); + let enabled = config.enabled_bool_option_labels(false); + let buffer = enabled_default.join(' '); + buffer += '\n'; + buffer += enabled.map(s => `${s}`) + .join(' '); + this.setEntry(Sections.OPTIONS, buffer); + } else { + this.setEntry(Sections.OPTIONS, ''); + } + } + + displayRealmFS() { + let realmfs = this._realm?.realmfs; + if (realmfs) { + this.setEntryVisible(Sections.REALMFS); + this.setEntry(Sections.REALMFS, `${realmfs.name}-realmfs.img`); + if(realmfs.activated) { + this.setEntryVisible(Sections.MOUNTPOINT); + this.setEntry(Sections.MOUNTPOINT, realmfs.mountpoint); + + } else { + this.setEntryVisible(Sections.MOUNTPOINT, false); + } + + } else { + this.setEntryVisible(Sections.REALMFS, false); + this.setEntryVisible(Sections.MOUNTPOINT, false); + } + } + + displayRealm() { + if (this._realm) { + this._columnTitle.label = `Realm ${this._realm.name}`; + if (this._realm.is_running()) { + this.setEntry("Status", "Running"); + } else { + this.setEntry("Status", "Stopped"); + } + this.displayConfig(); + this.displayRealmFS(); + } + } +} diff --git a/src/RealmInfoEntry.ts b/src/RealmInfoEntry.ts new file mode 100644 index 0000000..8620fdf --- /dev/null +++ b/src/RealmInfoEntry.ts @@ -0,0 +1,24 @@ +import GObject from 'gi://GObject' +import Gtk from 'gi://Gtk?version=4.0'; + +export class RealmInfoEntry extends Gtk.Box { + private _nameLabel!: Gtk.Label; + private _valueLabel!: Gtk.Label; + static { + GObject.registerClass({ + GTypeName: "RealmInfoEntry", + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmInfoEntry.ui', + InternalChildren: ['nameLabel', 'valueLabel'] + }, this); + } + + constructor(name: string) { + super(); + this._nameLabel.label = name; + } + + setValue(value: string) { + this._valueLabel.label = value; + } +} + diff --git a/src/RealmModel.ts b/src/RealmModel.ts new file mode 100644 index 0000000..d2c2085 --- /dev/null +++ b/src/RealmModel.ts @@ -0,0 +1,49 @@ +import Gio from 'gi://Gio'; +import GObject from 'gi://GObject'; +import { Realm } from './model/Realm.js'; +import {RealmManager} from "./model/RealmManager.js"; + +export class RealmModel extends GObject.Object { + static { + GObject.registerClass({ + GTypeName: 'RealmModel', + Implements: [Gio.ListModel], + }, this); + } + + _realms: Realm[] = []; + _realmManager: RealmManager; + + constructor() { + super(); + this._realmManager = RealmManager.instance(); + + this._realmManager.connect('realm-added', (_manager, realm: Realm) => { + let pos = this._realms.length; + this._realms.push(realm); + // @ts-ignore + this.items_changed(pos, 0, 1); + }); + + this._realmManager.connect('realm-removed', (_manager, realm) => { + let pos = this._realms.findIndex(r => r === realm); + if (pos >= 0) { + this._realms.splice(pos, 1); + // @ts-ignore + this.items_changed(pos, 1, 0); + } + }); + } + + vfunc_get_item_type() { + return Realm; + } + + vfunc_get_item(position: number) { + return this._realms[position] || null; + } + + vfunc_get_n_items() { + return this._realms.length; + } +} diff --git a/src/RealmRow.ts b/src/RealmRow.ts new file mode 100644 index 0000000..4a99e85 --- /dev/null +++ b/src/RealmRow.ts @@ -0,0 +1,59 @@ +import GObject from 'gi://GObject'; +import Gtk from 'gi://Gtk?version=4.0'; + +import { Realm } from './model/Realm.js'; + +export class RealmRow extends Gtk.Widget { + private _nameLabel!: Gtk.Label; + + static { + GObject.registerClass({ + GTypeName: 'RealmRow', + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmRow.ui', + Properties: { + 'realm': GObject.ParamSpec.object('realm', '','',GObject.ParamFlags.READWRITE, Realm), + }, + InternalChildren: ['nameLabel'], + }, this); + } + + _realm!: Realm | null; + + _notifyId = 0; + + + get realm() { + if (this._realm === undefined) { + this._realm = null; + } + return this._realm; + } + set realm(value) { + if(this.realm === value) { + return; + } + + if(this.realm && this._notifyId) { + this.realm.disconnect(this._notifyId); + this._notifyId = 0; + } + this._realm = value; + + if(this.realm) { + this._notifyId = this.realm.connect('notify', this.syncRealm.bind(this)); + this.syncRealm(); + } + + this.notify('realm'); + } + + syncRealm() { + if (this.realm && this.realm.is_running()) { + this._nameLabel.remove_css_class('dim-label'); + } else { + // @ts-ignore + this._nameLabel.add_css_class('dim-label'); + } + } +} + diff --git a/src/RealmsView.ts b/src/RealmsView.ts new file mode 100644 index 0000000..ae72b38 --- /dev/null +++ b/src/RealmsView.ts @@ -0,0 +1,106 @@ +import GObject from 'gi://GObject'; +import Gdk from 'gi://Gdk?version=4.0'; +import Gtk from 'gi://Gtk?version=4.0'; + +import {Realm} from "./model/Realm.js"; + +export class RealmsView extends Gtk.Widget { + private _realmsSelection!: Gtk.SingleSelection; + private _hiddenRealmsFilterModel!: Gtk.FilterListModel; + private _realmSorter!: Gtk.CustomSorter; + + static { + GObject.registerClass({ + GTypeName: 'RealmsView', + Template: 'resource:///com/subgraph/citadel/Realms/ui/RealmsView.ui', + Properties: { + 'selected-realm': GObject.ParamSpec.object('selected-realm', '', '', GObject.ParamFlags.READWRITE, Realm), + }, + InternalChildren: ['realmsSelection', 'hiddenRealmsFilterModel', 'realmSorter'], + }, this); + } + + _selectedRealm = null; + + constructor() { + super(); + this._setupHiddenRealmsFilter(); + this._setupRealmSorter(); + const keyController = new Gtk.EventControllerKey(); + keyController.connect('key-pressed', (_, keyval) => { + switch (keyval) { + case Gdk.KEY_j: + case Gdk.KEY_Down: + this.nextRealm(); + break; + case Gdk.KEY_k: + case Gdk.KEY_Up: + this.prevRealm(); + break; + case Gdk.KEY_Escape: + this.activate_action('app.quit', null); + print ("escaped"); + break; + } + }); + this.add_controller(keyController); + } + + _changeSelected(offset: number) { + const n_items = this._realmsSelection.n_items; + + if (n_items <= 1) { + return; + } + const pos = this._realmsSelection.selected; + if (pos == Gtk.INVALID_LIST_POSITION) { + return; + } + + const newPos = pos + offset; + + if (newPos < 0 || newPos >= n_items) { + return; + } + + this._realmsSelection.selected = newPos; + } + + nextRealm() { + this._changeSelected(1); + } + + prevRealm() { + this._changeSelected(-1); + } + + get selectedRealm() { + return this._selectedRealm; + } + + set selectedRealm(value) { + if (this.selectedRealm === value) { + return; + } + this._selectedRealm = value; + } + + _setupHiddenRealmsFilter() { + this._hiddenRealmsFilterModel.filter = Gtk.CustomFilter.new(item => !(item as Realm).is_system_realm); + } + + _setupRealmSorter() { + // 1) Sort 'Current' the lowest (top of list). + // 2) Then sort 'Running' lower than not 'Running' + // 3) Realms in the same run state sorted by lowest timestamp + this._realmSorter.set_sort_func((a,b) => { + if (a.is_current || (a.is_running && !b.is_running)) { + return Gtk.Ordering.SMALLER; + } else if (b.is_current || (b.is_running && !a.is_running)) { + return Gtk.Ordering.LARGER; + } else { + return b.timestamp - a.timestamp; + } + }); + } +} diff --git a/src/Window.ts b/src/Window.ts new file mode 100644 index 0000000..78c1565 --- /dev/null +++ b/src/Window.ts @@ -0,0 +1,41 @@ +import GObject from 'gi://GObject'; +import Adw from 'gi://Adw'; +import { Realm } from './model/Realm.js'; +import {ConfigureRealm} from './ConfigureRealm.js' +import { RealmsView } from './RealmsView.js'; + +export class Window extends Adw.ApplicationWindow { + + private _realmsView!: RealmsView; + private _configureRealm!: ConfigureRealm; + private _navView!: Adw.NavigationView; + + static { + GObject.registerClass({ + GTypeName: 'RealmsWindow', + Template: 'resource:///com/subgraph/citadel/Realms/ui/Window.ui', + InternalChildren: ['realmsView', 'configureRealm', 'navView'], + }, this); + } + + constructor(application: Adw.Application) { + super({ application: application }); + } + + + configureRealm(realm: Realm) { + this._configureRealm.configure(realm); + this._navView.push(this._configureRealm); + } + + get realms_view() { + return this._realmsView; + } + + + vfunc_close_request() { + super.vfunc_close_request(); + this.run_dispose(); + return true; + } +} diff --git a/src/colors/Base16Theme.ts b/src/colors/Base16Theme.ts new file mode 100644 index 0000000..e9c4a4f --- /dev/null +++ b/src/colors/Base16Theme.ts @@ -0,0 +1,1097 @@ + + + + +export class Base16Theme { + + id: string; + name: string; + colors: number[]; + + static CATEGORIES: [string,string][] = [ + ['atelier', 'Atelier'], + ['black-metal', 'Black Metal'], + ['brushtrees', 'Brush Trees'], + ['classic', 'Classic'], + ['default', 'Default'], + ['google', 'Google'], + ['grayscale', 'Grayscale'], + ['gruvbox', 'Gruvbox'], + ['harmonic', 'Harmonic'], + ['ia', 'iA'], + ['material', 'Material'], + ['papercolor', 'PaperColor'], + ['solarized', 'Solarized'], + ['summerfruit', 'Summerfruit'], + ['tomorrow', 'Tomorrow'], + ['unikitty', 'Unikitty'], + ]; + + static TERM_MAP = [ + 0x00, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x05, + 0x03, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x07, + 0x09, 0x0F, 0x01, 0x02, 0x04, 0x06, + ]; + static THEMES: Base16Theme[] = []; + + static add(id: string, name: string, colors: number[]) { + const theme = new Base16Theme(id, name, colors); + Base16Theme.THEMES.push(theme); + } + + constructor(id: string, name: string, colors: number[]) { + this.id = id; + this.name = name; + this.colors = colors; + } + + color(idx: number) { + let hex = this.colors[idx].toString(16).padStart(6, '0'); + return `#${hex}`; + } + + terminal_background() { + return this.color(0); + } + + terminal_foreground() { + return this.color(5); + } + + terminal_palette_color(idx: number) { + return this.color(Base16Theme.TERM_MAP[idx]); + } +} + +Base16Theme.add("3024", "3024", + [ + 0x090300, 0x3a3432, 0x4a4543, 0x5c5855, + 0x807d7c, 0xa5a2a2, 0xd6d5d4, 0xf7f7f7, + 0xdb2d20, 0xe8bbd0, 0xfded02, 0x01a252, + 0xb5e4f4, 0x01a0e4, 0xa16a94, 0xcdab53, + ]); + +Base16Theme.add("apathy", 'Apathy', + [ + 0x031A16, 0x0B342D, 0x184E45, 0x2B685E, + 0x5F9C92, 0x81B5AC, 0xA7CEC8, 0xD2E7E4, + 0x3E9688, 0x3E7996, 0x3E4C96, 0x883E96, + 0x963E4C, 0x96883E, 0x4C963E, 0x3E965B, + ]); + +Base16Theme.add("ashes", "Ashes", + [ + 0x1C2023, 0x393F45, 0x565E65, 0x747C84, + 0xADB3BA, 0xC7CCD1, 0xDFE2E5, 0xF3F4F5, + 0xC7AE95, 0xC7C795, 0xAEC795, 0x95C7AE, + 0x95AEC7, 0xAE95C7, 0xC795AE, 0xC79595, + ]); + + +Base16Theme.add("atelier-cave-light", "Atelier Cave Light", + [ + 0xefecf4, 0xe2dfe7, 0x8b8792, 0x7e7887, + 0x655f6d, 0x585260, 0x26232a, 0x19171c, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, + ]); + +Base16Theme.add("atelier-cave", "Atelier Cave", + [ + 0x19171c, 0x26232a, 0x585260, 0x655f6d, + 0x7e7887, 0x8b8792, 0xe2dfe7, 0xefecf4, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, + ]); + +Base16Theme.add("atelier-dune-light", "Atelier Dune Light", + [ + 0xfefbec, 0xe8e4cf, 0xa6a28c, 0x999580, + 0x7d7a68, 0x6e6b5e, 0x292824, 0x20201d, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, + ]); + +Base16Theme.add("atelier-dune", "Atelier Dune", + [ + 0x20201d, 0x292824, 0x6e6b5e, 0x7d7a68, + 0x999580, 0xa6a28c, 0xe8e4cf, 0xfefbec, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, + ]); + +Base16Theme.add("atelier-estuary-light", "Atelier Estuary Light", + [ + 0xf4f3ec, 0xe7e6df, 0x929181, 0x878573, + 0x6c6b5a, 0x5f5e4e, 0x302f27, 0x22221b, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, + ]); + +Base16Theme.add("atelier-estuary", "Atelier Estuary", + [ + 0x22221b, 0x302f27, 0x5f5e4e, 0x6c6b5a, + 0x878573, 0x929181, 0xe7e6df, 0xf4f3ec, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, + ]); + +Base16Theme.add("atelier-forest-light", "Atelier Forest Light", + [ + 0xf1efee, 0xe6e2e0, 0xa8a19f, 0x9c9491, + 0x766e6b, 0x68615e, 0x2c2421, 0x1b1918, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, + ]); + +Base16Theme.add("atelier-forest", "Atelier Forest", + [ + 0x1b1918, 0x2c2421, 0x68615e, 0x766e6b, + 0x9c9491, 0xa8a19f, 0xe6e2e0, 0xf1efee, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, + ]); + +Base16Theme.add("atelier-heath-light", "Atelier Heath Light", + [ + 0xf7f3f7, 0xd8cad8, 0xab9bab, 0x9e8f9e, + 0x776977, 0x695d69, 0x292329, 0x1b181b, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, + ]); + +Base16Theme.add("atelier-heath", "Atelier Heath", + [ + 0x1b181b, 0x292329, 0x695d69, 0x776977, + 0x9e8f9e, 0xab9bab, 0xd8cad8, 0xf7f3f7, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, + ]); + +Base16Theme.add("atelier-lakeside-light", "Atelier Lakeside Light", + [ + 0xebf8ff, 0xc1e4f6, 0x7ea2b4, 0x7195a8, + 0x5a7b8c, 0x516d7b, 0x1f292e, 0x161b1d, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, + ]); + +Base16Theme.add("atelier-lakeside", "Atelier Lakeside", + [ + 0x161b1d, 0x1f292e, 0x516d7b, 0x5a7b8c, + 0x7195a8, 0x7ea2b4, 0xc1e4f6, 0xebf8ff, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, + ]); + +Base16Theme.add("atelier-plateau-light", "Atelier Plateau Light", + [ + 0xf4ecec, 0xe7dfdf, 0x8a8585, 0x7e7777, + 0x655d5d, 0x585050, 0x292424, 0x1b1818, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, + ]); + +Base16Theme.add("atelier-plateau", "Atelier Plateau", + [ + 0x1b1818, 0x292424, 0x585050, 0x655d5d, + 0x7e7777, 0x8a8585, 0xe7dfdf, 0xf4ecec, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, + ]); + +Base16Theme.add("atelier-savanna-light", "Atelier Savanna Light", + [ + 0xecf4ee, 0xdfe7e2, 0x87928a, 0x78877d, + 0x5f6d64, 0x526057, 0x232a25, 0x171c19, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, + ]); + +Base16Theme.add("atelier-savanna", "Atelier Savanna", + [ + 0x171c19, 0x232a25, 0x526057, 0x5f6d64, + 0x78877d, 0x87928a, 0xdfe7e2, 0xecf4ee, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, + ]); + +Base16Theme.add("atelier-seaside-light", "Atelier Seaside Light", + [ + 0xf4fbf4, 0xcfe8cf, 0x8ca68c, 0x809980, + 0x687d68, 0x5e6e5e, 0x242924, 0x131513, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, + ]); + +Base16Theme.add("atelier-seaside", "Atelier Seaside", + [ + 0x131513, 0x242924, 0x5e6e5e, 0x687d68, + 0x809980, 0x8ca68c, 0xcfe8cf, 0xf4fbf4, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, + ]); + +Base16Theme.add("atelier-sulphurpool-light", "Atelier Sulphurpool Light", + [ + 0xf5f7ff, 0xdfe2f1, 0x979db4, 0x898ea4, + 0x6b7394, 0x5e6687, 0x293256, 0x202746, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, + ]); + +Base16Theme.add("atelier-sulphurpool", "Atelier Sulphurpool", + [ + 0x202746, 0x293256, 0x5e6687, 0x6b7394, + 0x898ea4, 0x979db4, 0xdfe2f1, 0xf5f7ff, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, + ]); + +Base16Theme.add("atlas", "Atlas", + [ + 0x002635, 0x00384d, 0x517F8D, 0x6C8B91, + 0x869696, 0xa1a19a, 0xe6e6dc, 0xfafaf8, + 0xff5a67, 0xf08e48, 0xffcc1b, 0x7fc06e, + 0x14747e, 0x5dd7b9, 0x9a70a4, 0xc43060, + ]); + +Base16Theme.add("bespin", "Bespin", + [ + 0x28211c, 0x36312e, 0x5e5d5c, 0x666666, + 0x797977, 0x8a8986, 0x9d9b97, 0xbaae9e, + 0xcf6a4c, 0xcf7d34, 0xf9ee98, 0x54be0d, + 0xafc4db, 0x5ea6ea, 0x9b859d, 0x937121, + ]); + +Base16Theme.add("black-metal-bathory", "Black Metal (Bathory)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xe78a53, 0xfbcb97, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-burzum", "Black Metal (Burzum)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x99bbaa, 0xddeecc, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-dark-funeral", "Black Metal (Dark Funeral)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x5f81a5, 0xd0dfee, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-gorgoroth", "Black Metal (Gorgoroth)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x8c7f70, 0x9b8d7f, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-immortal", "Black Metal (Immortal)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x556677, 0x7799bb, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-khold", "Black Metal (Khold)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x974b46, 0xeceee3, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-marduk", "Black Metal (Marduk)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x626b67, 0xa5aaa7, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-mayhem", "Black Metal (Mayhem)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xeecc6c, 0xf3ecd4, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-nile", "Black Metal (Nile)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x777755, 0xaa9988, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-venom", "Black Metal (Venom)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x79241f, 0xf8f7f2, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal", "Black Metal", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xa06666, 0xdd9999, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("brewer", "Brewer", + [ + 0x0c0d0e, 0x2e2f30, 0x515253, 0x737475, + 0x959697, 0xb7b8b9, 0xdadbdc, 0xfcfdfe, + 0xe31a1c, 0xe6550d, 0xdca060, 0x31a354, + 0x80b1d3, 0x3182bd, 0x756bb1, 0xb15928, + ]); + +Base16Theme.add("bright", "Bright", + [ + 0x000000, 0x303030, 0x505050, 0xb0b0b0, + 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, 0xffffff, + 0xfb0120, 0xfc6d24, 0xfda331, 0xa1c659, + 0x76c7b7, 0x6fb3d2, 0xd381c3, 0xbe643c, + ]); + +Base16Theme.add("brogrammer", "Brogrammer", + [ + 0x1f1f1f, 0xf81118, 0x2dc55e, 0xecba0f, + 0x2a84d2, 0x4e5ab7, 0x1081d6, 0xd6dbe5, + 0xd6dbe5, 0xde352e, 0x1dd361, 0xf3bd09, + 0x1081d6, 0x5350b9, 0x0f7ddb, 0xffffff, + ]); + +Base16Theme.add("brushtrees-dark", "Brush Trees Dark", + [ + 0x485867, 0x5A6D7A, 0x6D828E, 0x8299A1, + 0x98AFB5, 0xB0C5C8, 0xC9DBDC, 0xE3EFEF, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, + ]); + +Base16Theme.add("brushtrees", "Brush Trees", + [ + 0xE3EFEF, 0xC9DBDC, 0xB0C5C8, 0x98AFB5, + 0x8299A1, 0x6D828E, 0x5A6D7A, 0x485867, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, + ]); + +Base16Theme.add("chalk", "Chalk", + [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, + 0xfb9fb1, 0xeda987, 0xddb26f, 0xacc267, + 0x12cfc0, 0x6fc2ef, 0xe1a3ee, 0xdeaf8f, + ]); + +Base16Theme.add("circus", "Circus", + [ + 0x191919, 0x202020, 0x303030, 0x5f5a60, + 0x505050, 0xa7a7a7, 0x808080, 0xffffff, + 0xdc657d, 0x4bb1a7, 0xc3ba63, 0x84b97c, + 0x4bb1a7, 0x639ee4, 0xb888e2, 0xb888e2, + ]); + +Base16Theme.add("classic-dark", "Classic Dark", + [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xF5F5F5, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, + ]); + +Base16Theme.add("classic-light", "Classic Light", + [ + 0xF5F5F5, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x505050, 0x303030, 0x202020, 0x151515, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, + ]); + +Base16Theme.add("codeschool", "Codeschool", + [ + 0x232c31, 0x1c3657, 0x2a343a, 0x3f4944, + 0x84898c, 0x9ea7a6, 0xa7cfa3, 0xb5d8f6, + 0x2a5491, 0x43820d, 0xa03b1e, 0x237986, + 0xb02f30, 0x484d79, 0xc59820, 0xc98344, + ]); + +Base16Theme.add("cupcake", "Cupcake", + [ + 0xfbf1f2, 0xf2f1f4, 0xd8d5dd, 0xbfb9c6, + 0xa59daf, 0x8b8198, 0x72677E, 0x585062, + 0xD57E85, 0xEBB790, 0xDCB16C, 0xA3B367, + 0x69A9A7, 0x7297B9, 0xBB99B4, 0xBAA58C, + ]); + +Base16Theme.add("cupertino", "Cupertino", + [ + 0xffffff, 0xc0c0c0, 0xc0c0c0, 0x808080, + 0x808080, 0x404040, 0x404040, 0x5e5e5e, + 0xc41a15, 0xeb8500, 0x826b28, 0x007400, + 0x318495, 0x0000ff, 0xa90d91, 0x826b28, + ]); + +Base16Theme.add("darktooth", "Darktooth", + [ + 0x1D2021, 0x32302F, 0x504945, 0x665C54, + 0x928374, 0xA89984, 0xD5C4A1, 0xFDF4C1, + 0xFB543F, 0xFE8625, 0xFAC03B, 0x95C085, + 0x8BA59B, 0x0D6678, 0x8F4673, 0xA87322, + ]); + +Base16Theme.add("default-dark", "Default Dark", + [ + 0x181818, 0x282828, 0x383838, 0x585858, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, + ]); + +Base16Theme.add("default-light", "Default Light", + [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, + ]); + +Base16Theme.add("dracula", "Dracula", + [ + 0x282936, 0x3a3c4e, 0x4d4f68, 0x626483, + 0x62d6e8, 0xe9e9f4, 0xf1f2f8, 0xf7f7fb, + 0xea51b2, 0xb45bcf, 0x00f769, 0xebff87, + 0xa1efe4, 0x62d6e8, 0xb45bcf, 0x00f769, + ]); + +Base16Theme.add("eighties", "Eighties", + [ + 0x2d2d2d, 0x393939, 0x515151, 0x747369, + 0xa09f93, 0xd3d0c8, 0xe8e6df, 0xf2f0ec, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xd27b53, + ]); + +Base16Theme.add("embers", "Embers", + [ + 0x16130F, 0x2C2620, 0x433B32, 0x5A5047, + 0x8A8075, 0xA39A90, 0xBEB6AE, 0xDBD6D1, + 0x826D57, 0x828257, 0x6D8257, 0x57826D, + 0x576D82, 0x6D5782, 0x82576D, 0x825757, + ]); + +Base16Theme.add("flat", "Flat", + [ + 0x2C3E50, 0x34495E, 0x7F8C8D, 0x95A5A6, + 0xBDC3C7, 0xe0e0e0, 0xf5f5f5, 0xECF0F1, + 0xE74C3C, 0xE67E22, 0xF1C40F, 0x2ECC71, + 0x1ABC9C, 0x3498DB, 0x9B59B6, 0xbe643c, + ]); + +Base16Theme.add("fruit-soda", "Fruit Soda", + [ + 0xf1ecf1, 0xe0dee0, 0xd8d5d5, 0xb5b4b6, + 0x979598, 0x515151, 0x474545, 0x2d2c2c, + 0xfe3e31, 0xfe6d08, 0xf7e203, 0x47f74c, + 0x0f9cfd, 0x2931df, 0x611fce, 0xb16f40, + ]); + +Base16Theme.add("github", "Github", + [ + 0xffffff, 0xf5f5f5, 0xc8c8fa, 0x969896, + 0xe8e8e8, 0x333333, 0xffffff, 0xffffff, + 0xed6a43, 0x0086b3, 0x795da3, 0x183691, + 0x183691, 0x795da3, 0xa71d5d, 0x333333, + ]); + +Base16Theme.add("google-dark", "Google Dark", + [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, + ]); + +Base16Theme.add("google-light", "Google Light", + [ + 0xffffff, 0xe0e0e0, 0xc5c8c6, 0xb4b7b4, + 0x969896, 0x373b41, 0x282a2e, 0x1d1f21, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, + ]); + +Base16Theme.add("grayscale-dark", "Grayscale Dark", + [ + 0x101010, 0x252525, 0x464646, 0x525252, + 0xababab, 0xb9b9b9, 0xe3e3e3, 0xf7f7f7, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, + ]); + +Base16Theme.add("grayscale-light", "Grayscale Light", + [ + 0xf7f7f7, 0xe3e3e3, 0xb9b9b9, 0xababab, + 0x525252, 0x464646, 0x252525, 0x101010, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, + ]); + +Base16Theme.add("greenscreen", "Green Screen", + [ + 0x001100, 0x003300, 0x005500, 0x007700, + 0x009900, 0x00bb00, 0x00dd00, 0x00ff00, + 0x007700, 0x009900, 0x007700, 0x00bb00, + 0x005500, 0x009900, 0x00bb00, 0x005500, + ]); + +Base16Theme.add("gruvbox-dark-hard", "Gruvbox dark, hard", + [ + 0x1d2021, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-dark-medium", "Gruvbox dark, medium", + [ + 0x282828, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-dark-pale", "Gruvbox dark, pale", + [ + 0x262626, 0x3a3a3a, 0x4e4e4e, 0x8a8a8a, + 0x949494, 0xdab997, 0xd5c4a1, 0xebdbb2, + 0xd75f5f, 0xff8700, 0xffaf00, 0xafaf00, + 0x85ad85, 0x83adad, 0xd485ad, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-dark-soft", "Gruvbox dark, soft", + [ + 0x32302f, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-light-hard", "Gruvbox light, hard", + [ + 0xf9f5d7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-light-medium", "Gruvbox light, medium", + [ + 0xfbf1c7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-light-soft", "Gruvbox light, soft", + [ + 0xf2e5bc, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, + ]); + +Base16Theme.add("harmonic-dark", "Harmonic16 Dark", + [ + 0x0b1c2c, 0x223b54, 0x405c79, 0x627e99, + 0xaabcce, 0xcbd6e2, 0xe5ebf1, 0xf7f9fb, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, + ]); + +Base16Theme.add("harmonic-light", "Harmonic16 Light", + [ + 0xf7f9fb, 0xe5ebf1, 0xcbd6e2, 0xaabcce, + 0x627e99, 0x405c79, 0x223b54, 0x0b1c2c, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, + ]); + +Base16Theme.add("heetch-light", "Heetch Light", + [ + 0xfeffff, 0x392551, 0x7b6d8b, 0x9c92a8, + 0xddd6e5, 0x5a496e, 0x470546, 0x190134, + 0x27d9d5, 0xbdb6c5, 0x5ba2b6, 0xf80059, + 0xc33678, 0x47f9f5, 0xbd0152, 0xdedae2, + ]); + +Base16Theme.add("heetch", "Heetch Dark", + [ + 0x190134, 0x392551, 0x5A496E, 0x7B6D8B, + 0x9C92A8, 0xBDB6C5, 0xDEDAE2, 0xFEFFFF, + 0x27D9D5, 0x5BA2B6, 0x8F6C97, 0xC33678, + 0xF80059, 0xBD0152, 0x82034C, 0x470546, + ]); + +Base16Theme.add("helios", "Helios", + [ + 0x1d2021, 0x383c3e, 0x53585b, 0x6f7579, + 0xcdcdcd, 0xd5d5d5, 0xdddddd, 0xe5e5e5, + 0xd72638, 0xeb8413, 0xf19d1a, 0x88b92d, + 0x1ba595, 0x1e8bac, 0xbe4264, 0xc85e0d, + ]); + +Base16Theme.add("hopscotch", "Hopscotch", + [ + 0x322931, 0x433b42, 0x5c545b, 0x797379, + 0x989498, 0xb9b5b8, 0xd5d3d5, 0xffffff, + 0xdd464c, 0xfd8b19, 0xfdcc59, 0x8fc13e, + 0x149b93, 0x1290bf, 0xc85e7c, 0xb33508, + ]); + +Base16Theme.add("horizon-dark", "Horizon Dark", + [ + 0x1c1e26, 0x232530, 0x2e303e, 0x676a8d, + 0xced1d0, 0xcbced0, 0xdcdfe4, 0xe3e6ee, + 0xe93c58, 0xe58d7d, 0xefb993, 0xefaf8e, + 0x24a8b4, 0xdf5273, 0xb072d1, 0xe4a382, + ]); + +Base16Theme.add("ia-dark", "iA Dark", + [ + 0x1a1a1a, 0x222222, 0x1d414d, 0x767676, + 0xb8b8b8, 0xcccccc, 0xe8e8e8, 0xf8f8f8, + 0xd88568, 0xd86868, 0xb99353, 0x83a471, + 0x7c9cae, 0x8eccdd, 0xb98eb2, 0x8b6c37, + ]); + +Base16Theme.add("ia-light", "iA Light", + [ + 0xf6f6f6, 0xdedede, 0xbde5f2, 0x898989, + 0x767676, 0x181818, 0xe8e8e8, 0xf8f8f8, + 0x9c5a02, 0xc43e18, 0xc48218, 0x38781c, + 0x2d6bb1, 0x48bac2, 0xa94598, 0x8b6c37, + ]); + +Base16Theme.add("icy", "Icy Dark", + [ + 0x021012, 0x031619, 0x041f23, 0x052e34, + 0x064048, 0x095b67, 0x0c7c8c, 0x109cb0, + 0x16c1d9, 0xb3ebf2, 0x80deea, 0x4dd0e1, + 0x26c6da, 0x00bcd4, 0x00acc1, 0x0097a7, + ]); + +Base16Theme.add("irblack", "IR Black", + [ + 0x000000, 0x242422, 0x484844, 0x6c6c66, + 0x918f88, 0xb5b3aa, 0xd9d7cc, 0xfdfbee, + 0xff6c60, 0xe9c062, 0xffffb6, 0xa8ff60, + 0xc6c5fe, 0x96cbfe, 0xff73fd, 0xb18a3d, + ]); + +Base16Theme.add("isotope", "Isotope", + [ + 0x000000, 0x404040, 0x606060, 0x808080, + 0xc0c0c0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xff0000, 0xff9900, 0xff0099, 0x33ff00, + 0x00ffff, 0x0066ff, 0xcc00ff, 0x3300ff, + ]); + +Base16Theme.add("macintosh", "Macintosh", + [ + 0x000000, 0x404040, 0x404040, 0x808080, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0xffffff, + 0xdd0907, 0xff6403, 0xfbf305, 0x1fb714, + 0x02abea, 0x0000d3, 0x4700a5, 0x90713a, + ]); + +Base16Theme.add("marrakesh", "Marrakesh", + [ + 0x201602, 0x302e00, 0x5f5b17, 0x6c6823, + 0x86813b, 0x948e48, 0xccc37a, 0xfaf0a5, + 0xc35359, 0xb36144, 0xa88339, 0x18974e, + 0x75a738, 0x477ca1, 0x8868b3, 0xb3588e, + ]); + +Base16Theme.add("materia", "Materia", + [ + 0x263238, 0x2C393F, 0x37474F, 0x707880, + 0xC9CCD3, 0xCDD3DE, 0xD5DBE5, 0xFFFFFF, + 0xEC5F67, 0xEA9560, 0xFFCC00, 0x8BD649, + 0x80CBC4, 0x89DDFF, 0x82AAFF, 0xEC5F67, + ]); + +Base16Theme.add("material-darker", "Material Darker", + [ + 0x212121, 0x303030, 0x353535, 0x4A4A4A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, + ]); + +Base16Theme.add("material-lighter", "Material Lighter", + [ + 0xFAFAFA, 0xE7EAEC, 0xCCEAE7, 0xCCD7DA, + 0x8796B0, 0x80CBC4, 0x80CBC4, 0xFFFFFF, + 0xFF5370, 0xF76D47, 0xFFB62C, 0x91B859, + 0x39ADB5, 0x6182B8, 0x7C4DFF, 0xE53935, + ]); + +Base16Theme.add("material-palenight", "Material Palenight", + [ + 0x292D3E, 0x444267, 0x32374D, 0x676E95, + 0x8796B0, 0x959DCB, 0x959DCB, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, + ]); + +Base16Theme.add("material-vivid", "Material Vivid", + [ + 0x202124, 0x27292c, 0x323639, 0x44464d, + 0x676c71, 0x80868b, 0x9e9e9e, 0xffffff, + 0xf44336, 0xff9800, 0xffeb3b, 0x00e676, + 0x00bcd4, 0x2196f3, 0x673ab7, 0x8d6e63, + ]); + +Base16Theme.add("material", "Material", + [ + 0x263238, 0x2E3C43, 0x314549, 0x546E7A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, + ]); + +Base16Theme.add("mellow-purple", "Mellow Purple", + [ + 0x1e0528, 0x1A092D, 0x331354, 0x320f55, + 0x873582, 0xffeeff, 0xffeeff, 0xf8c0ff, + 0x00d9e9, 0xaa00a3, 0x955ae7, 0x05cb0d, + 0xb900b1, 0x550068, 0x8991bb, 0x4d6fff, + ]); + +Base16Theme.add("mexico-light", "Mexico Light", + [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf79a0e, 0x538947, + 0x4b8093, 0x7cafc2, 0x96609e, 0xa16946, + ]); + +Base16Theme.add("mocha", "Mocha", + [ + 0x3B3228, 0x534636, 0x645240, 0x7e705a, + 0xb8afad, 0xd0c8c6, 0xe9e1dd, 0xf5eeeb, + 0xcb6077, 0xd28b71, 0xf4bc87, 0xbeb55b, + 0x7bbda4, 0x8ab3b5, 0xa89bb9, 0xbb9584, + ]); + +Base16Theme.add("monokai", "Monokai", + [ + 0x272822, 0x383830, 0x49483e, 0x75715e, + 0xa59f85, 0xf8f8f2, 0xf5f4f1, 0xf9f8f5, + 0xf92672, 0xfd971f, 0xf4bf75, 0xa6e22e, + 0xa1efe4, 0x66d9ef, 0xae81ff, 0xcc6633, + ]); + +Base16Theme.add("nord", "Nord", + [ + 0x2E3440, 0x3B4252, 0x434C5E, 0x4C566A, + 0xD8DEE9, 0xE5E9F0, 0xECEFF4, 0x8FBCBB, + 0x88C0D0, 0x81A1C1, 0x5E81AC, 0xBF616A, + 0xD08770, 0xEBCB8B, 0xA3BE8C, 0xB48EAD, + ]); + +Base16Theme.add("ocean", "Ocean", + [ + 0x2b303b, 0x343d46, 0x4f5b66, 0x65737e, + 0xa7adba, 0xc0c5ce, 0xdfe1e8, 0xeff1f5, + 0xbf616a, 0xd08770, 0xebcb8b, 0xa3be8c, + 0x96b5b4, 0x8fa1b3, 0xb48ead, 0xab7967, + ]); + +Base16Theme.add("oceanicnext", "OceanicNext", + [ + 0x1B2B34, 0x343D46, 0x4F5B66, 0x65737E, + 0xA7ADBA, 0xC0C5CE, 0xCDD3DE, 0xD8DEE9, + 0xEC5F67, 0xF99157, 0xFAC863, 0x99C794, + 0x5FB3B3, 0x6699CC, 0xC594C5, 0xAB7967, + ]); + +Base16Theme.add("one-light", "One Light", + [ + 0xfafafa, 0xf0f0f1, 0xe5e5e6, 0xa0a1a7, + 0x696c77, 0x383a42, 0x202227, 0x090a0b, + 0xca1243, 0xd75f00, 0xc18401, 0x50a14f, + 0x0184bc, 0x4078f2, 0xa626a4, 0x986801, + ]); + +Base16Theme.add("onedark", "OneDark", + [ + 0x282c34, 0x353b45, 0x3e4451, 0x545862, + 0x565c64, 0xabb2bf, 0xb6bdca, 0xc8ccd4, + 0xe06c75, 0xd19a66, 0xe5c07b, 0x98c379, + 0x56b6c2, 0x61afef, 0xc678dd, 0xbe5046, + ]); + +Base16Theme.add("outrun-dark", "Outrun Dark", + [ + 0x00002A, 0x20204A, 0x30305A, 0x50507A, + 0xB0B0DA, 0xD0D0FA, 0xE0E0FF, 0xF5F5FF, + 0xFF4242, 0xFC8D28, 0xF3E877, 0x59F176, + 0x0EF0F0, 0x66B0FF, 0xF10596, 0xF003EF, + ]); + +Base16Theme.add("papercolor-dark", "PaperColor Dark", + [ + 0x1c1c1c, 0xaf005f, 0x5faf00, 0xd7af5f, + 0x5fafd7, 0x808080, 0xd7875f, 0xd0d0d0, + 0x585858, 0x5faf5f, 0xafd700, 0xaf87d7, + 0xffaf00, 0xff5faf, 0x00afaf, 0x5f8787, + ]); + +Base16Theme.add("papercolor-light", "PaperColor Light", + [ + 0xeeeeee, 0xaf0000, 0x008700, 0x5f8700, + 0x0087af, 0x878787, 0x005f87, 0x444444, + 0xbcbcbc, 0xd70000, 0xd70087, 0x8700af, + 0xd75f00, 0xd75f00, 0x005faf, 0x005f87, + ]); + +Base16Theme.add("paraiso", "Paraiso", + [ + 0x2f1e2e, 0x41323f, 0x4f424c, 0x776e71, + 0x8d8687, 0xa39e9b, 0xb9b6b0, 0xe7e9db, + 0xef6155, 0xf99b15, 0xfec418, 0x48b685, + 0x5bc4bf, 0x06b6ef, 0x815ba4, 0xe96ba8, + ]); + +Base16Theme.add("phd", "PhD", + [ + 0x061229, 0x2a3448, 0x4d5666, 0x717885, + 0x9a99a3, 0xb8bbc2, 0xdbdde0, 0xffffff, + 0xd07346, 0xf0a000, 0xfbd461, 0x99bf52, + 0x72b9bf, 0x5299bf, 0x9989cc, 0xb08060, + ]); + +Base16Theme.add("pico", "Pico", + [ + 0x000000, 0x1d2b53, 0x7e2553, 0x008751, + 0xab5236, 0x5f574f, 0xc2c3c7, 0xfff1e8, + 0xff004d, 0xffa300, 0xfff024, 0x00e756, + 0x29adff, 0x83769c, 0xff77a8, 0xffccaa, + ]); + +Base16Theme.add("pop", "Pop", + [ + 0x000000, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xeb008a, 0xf29333, 0xf8ca12, 0x37b349, + 0x00aabb, 0x0e5a94, 0xb31e8d, 0x7a2d00, + ]); + +Base16Theme.add("porple", "Porple", + [ + 0x292c36, 0x333344, 0x474160, 0x65568a, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xf84547, 0xd28e5d, 0xefa16b, 0x95c76f, + 0x64878f, 0x8485ce, 0xb74989, 0x986841, + ]); + +Base16Theme.add("qualia", "Qualia", + [ + 0x101010, 0x454545, 0x454545, 0x454545, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0x454545, + 0xefa6a2, 0xa3b8ef, 0xe6a3dc, 0x80c990, + 0xc8c874, 0x50cacd, 0xe0af85, 0x808080, + ]); + +Base16Theme.add("railscasts", "Railscasts", + [ + 0x2b2b2b, 0x272935, 0x3a4055, 0x5a647e, + 0xd4cfc9, 0xe6e1dc, 0xf4f1ed, 0xf9f7f3, + 0xda4939, 0xcc7833, 0xffc66d, 0xa5c261, + 0x519f50, 0x6d9cbe, 0xb6b3eb, 0xbc9458, + ]); + +Base16Theme.add("rebecca", "Rebecca", + [ + 0x292a44, 0x663399, 0x383a62, 0x666699, + 0xa0a0c5, 0xf1eff8, 0xccccff, 0x53495d, + 0xa0a0c5, 0xefe4a1, 0xae81ff, 0x6dfedf, + 0x8eaee0, 0x2de0a7, 0x7aa5ff, 0xff79c6, + ]); + +Base16Theme.add("seti", "Seti UI", + [ + 0x151718, 0x282a2b, 0x3B758C, 0x41535B, + 0x43a5d5, 0xd6d6d6, 0xeeeeee, 0xffffff, + 0xcd3f45, 0xdb7b55, 0xe6cd69, 0x9fca56, + 0x55dbbe, 0x55b5db, 0xa074c4, 0x8a553f, + ]); + +Base16Theme.add("shapeshifter", "Shapeshifter", + [ + 0xf9f9f9, 0xe0e0e0, 0xababab, 0x555555, + 0x343434, 0x102015, 0x040404, 0x000000, + 0xe92f2f, 0xe09448, 0xdddd13, 0x0ed839, + 0x23edda, 0x3b48e3, 0xf996e2, 0x69542d, + ]); + +Base16Theme.add("snazzy", "Snazzy", + [ + 0x282a36, 0x34353e, 0x43454f, 0x78787e, + 0xa5a5a9, 0xe2e4e5, 0xeff0eb, 0xf1f1f0, + 0xff5c57, 0xff9f43, 0xf3f99d, 0x5af78e, + 0x9aedfe, 0x57c7ff, 0xff6ac1, 0xb2643c, + ]); + +Base16Theme.add("solarflare", "Solar Flare", + [ + 0x18262F, 0x222E38, 0x586875, 0x667581, + 0x85939E, 0xA6AFB8, 0xE8E9ED, 0xF5F7FA, + 0xEF5253, 0xE66B2B, 0xE4B51C, 0x7CC844, + 0x52CBB0, 0x33B5E1, 0xA363D5, 0xD73C9A, + ]); + +Base16Theme.add("solarized-dark", "Solarized Dark", + [ + 0x002b36, 0x073642, 0x586e75, 0x657b83, + 0x839496, 0x93a1a1, 0xeee8d5, 0xfdf6e3, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, + ]); + +Base16Theme.add("solarized-light", "Solarized Light", + [ + 0xfdf6e3, 0xeee8d5, 0x93a1a1, 0x839496, + 0x657b83, 0x586e75, 0x073642, 0x002b36, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, + ]); + +Base16Theme.add("spacemacs", "Spacemacs", + [ + 0x1f2022, 0x282828, 0x444155, 0x585858, + 0xb8b8b8, 0xa3a3a3, 0xe8e8e8, 0xf8f8f8, + 0xf2241f, 0xffa500, 0xb1951d, 0x67b11d, + 0x2d9574, 0x4f97d7, 0xa31db1, 0xb03060, + ]); + +Base16Theme.add("summerfruit-dark", "Summerfruit Dark", + [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xFFFFFF, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, + ]); + +Base16Theme.add("summerfruit-light", "Summerfruit Light", + [ + 0xFFFFFF, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x000000, 0x101010, 0x151515, 0x202020, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, + ]); + +Base16Theme.add("synth-midnight-dark", "Synth Midnight", + [ + 0x040404, 0x141414, 0x242424, 0x61507A, + 0xBFBBBF, 0xDFDBDF, 0xEFEBEF, 0xFFFBFF, + 0xB53B50, 0xE4600E, 0xDAE84D, 0x06EA61, + 0x7CEDE9, 0x03AEFF, 0xEA5CE2, 0x9D4D0E, + ]); + +Base16Theme.add("tomorrow-night-eighties", "Tomorrow Night Eighties", + [ + 0x2d2d2d, 0x393939, 0x515151, 0x999999, + 0xb4b7b4, 0xcccccc, 0xe0e0e0, 0xffffff, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xa3685a, + ]); + +Base16Theme.add("tomorrow-night", "Tomorrow Night", + [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xcc6666, 0xde935f, 0xf0c674, 0xb5bd68, + 0x8abeb7, 0x81a2be, 0xb294bb, 0xa3685a, + ]); + +Base16Theme.add("tomorrow", "Tomorrow", + [ + 0xffffff, 0xe0e0e0, 0xd6d6d6, 0x8e908c, + 0x969896, 0x4d4d4c, 0x282a2e, 0x1d1f21, + 0xc82829, 0xf5871f, 0xeab700, 0x718c00, + 0x3e999f, 0x4271ae, 0x8959a8, 0xa3685a, + ]); + +Base16Theme.add("tube", "London Tube", + [ + 0x231f20, 0x1c3f95, 0x5a5758, 0x737171, + 0x959ca1, 0xd9d8d8, 0xe7e7e8, 0xffffff, + 0xee2e24, 0xf386a1, 0xffd204, 0x00853e, + 0x85cebc, 0x009ddc, 0x98005d, 0xb06110, + ]); + +Base16Theme.add("twilight", "Twilight", + [ + 0x1e1e1e, 0x323537, 0x464b50, 0x5f5a60, + 0x838184, 0xa7a7a7, 0xc3c3c3, 0xffffff, + 0xcf6a4c, 0xcda869, 0xf9ee98, 0x8f9d6a, + 0xafc4db, 0x7587a6, 0x9b859d, 0x9b703f, + ]); + +Base16Theme.add("unikitty-dark", "Unikitty Dark", + [ + 0x2e2a31, 0x4a464d, 0x666369, 0x838085, + 0x9f9da2, 0xbcbabe, 0xd8d7da, 0xf5f4f7, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x796af5, 0xbb60ea, 0xc720ca, + ]); + +Base16Theme.add("unikitty-light", "Unikitty Light", + [ + 0xffffff, 0xe1e1e2, 0xc4c3c5, 0xa7a5a8, + 0x89878b, 0x6c696e, 0x4f4b51, 0x322d34, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x775dff, 0xaa17e6, 0xe013d0, + ]); + +Base16Theme.add("woodland", "Woodland", + [ + 0x231e18, 0x302b25, 0x48413a, 0x9d8b70, + 0xb4a490, 0xcabcb1, 0xd7c8bc, 0xe4d4c8, + 0xd35c5c, 0xca7f32, 0xe0ac16, 0xb7ba53, + 0x6eb958, 0x88a4d3, 0xbb90e2, 0xb49368, + ]); + +Base16Theme.add("xcode-dusk", "XCode Dusk", + [ + 0x282B35, 0x3D4048, 0x53555D, 0x686A71, + 0x7E8086, 0x939599, 0xA9AAAE, 0xBEBFC2, + 0xB21889, 0x786DC5, 0x438288, 0xDF0002, + 0x00A0BE, 0x790EAD, 0xB21889, 0xC77C48, + ]); + +Base16Theme.add("zenburn", "Zenburn", + [ + 0x383838, 0x404040, 0x606060, 0x6f6f6f, + 0x808080, 0xdcdccc, 0xc0c0c0, 0xffffff, + 0xdca3a3, 0xdfaf8f, 0xe0cf9f, 0x5f7f5f, + 0x93e0e3, 0x7cb8bb, 0xdc8cc3, 0x000000, + ]); diff --git a/src/colors/ColorSchemeModel.ts b/src/colors/ColorSchemeModel.ts new file mode 100644 index 0000000..d2fcc11 --- /dev/null +++ b/src/colors/ColorSchemeModel.ts @@ -0,0 +1,147 @@ +import GObject from 'gi://GObject'; +import Gio from 'gi://Gio'; +import Gtk from 'gi://Gtk?version=4.0'; + +import { Base16Theme } from './Base16Theme.js'; + + +export class ColorSchemeModel { + selection: Gtk.SingleSelection; + treeModel: Gtk.TreeListModel; + + constructor() { + let builder = new TreeModelBuilder(); + this.treeModel = builder.buildTreeModel(); + this.selection = Gtk.SingleSelection.new(this.treeModel); + } +} + +class ColorModelNode extends GObject.Object { + static { + GObject.registerClass({ + GTypeName: 'ColorModelNode', + Properties: { + 'text': GObject.ParamSpec.string('text', '', '', GObject.ParamFlags.READWRITE, ''), + + } + }, this); + } + + data: Base16Theme | ColorThemeCategory; + + constructor(data: Base16Theme | ColorThemeCategory) { + super(); + this.data = data; + } + + get text(): string { + return this.data.name; + } + + child_model() { + if (this.data instanceof ColorThemeCategory) { + return this.data.children; + } else { + return null; + } + } + + isThemeWithId(id: string): boolean { + return (this.data instanceof Base16Theme) && + (this.data.id === id); + } + + hasChildThemeWithId(id: string): boolean { + const child_model = this.child_model(); + + if (child_model) { + for (let i = 0; i < child_model.n_items; i++) { + let node = child_model.get_item(i) as ColorModelNode; + if (node.isThemeWithId(id)) { + return true; + } + } + } + return false; + } + + static newScheme(color: Base16Theme) { + return new ColorModelNode(color); + } + + static newCategory(category: ColorThemeCategory) { + return new ColorModelNode(category); + } +} + +class ColorThemeCategory { + name: string; + children: Gio.ListStore; + + constructor(name: string) { + this.name = name; + this.children = new Gio.ListStore(ColorModelNode); + } + + append(color: Base16Theme) { + this.children.append(ColorModelNode.newScheme(color)); + } +} + +class TreeModelBuilder { + categories: [string,string][]; + currentCategory: null | ColorThemeCategory; + storeModel: Gio.ListStore; + + constructor() { + this.categories = Base16Theme.CATEGORIES; + this.currentCategory = null; + this.storeModel = new Gio.ListStore(ColorModelNode); + } + + buildTreeModel() { + Base16Theme.THEMES.forEach(theme => this.addTheme(theme)); + return Gtk.TreeListModel.new( + this.storeModel, + false, + false, + item => (item as ColorModelNode).child_model(), + ); + } + + appendCurrentCategory() { + if (this.currentCategory) { + this.storeModel.append(ColorModelNode.newCategory(this.currentCategory)); + this.currentCategory = null; + this.categories.shift(); + } + } + + matchesNextCategory(theme: Base16Theme): boolean { + if (this.categories.length === 0) { + return false; + } + let [id, _name] = this.categories[0]; + return theme.id === id; + } + + addTheme(theme: Base16Theme) { + if (this.matchesNextCategory(theme)) { + this.addToCategory(theme); + return; + } + if (this.currentCategory) { + this.appendCurrentCategory(); + } + this.storeModel.append(ColorModelNode.newScheme(theme)); + } + + addToCategory(theme: Base16Theme) { + if (!this.currentCategory) { + let [_id, name] = this.categories[0]; + this.currentCategory = new ColorThemeCategory(name); + } + this.currentCategory.append(theme); + } + +} diff --git a/src/com.subgraph.citadel.Realms.js b/src/com.subgraph.citadel.Realms.js new file mode 100644 index 0000000..943101d --- /dev/null +++ b/src/com.subgraph.citadel.Realms.js @@ -0,0 +1,27 @@ +#!@GJS@ -m + +import GLib from 'gi://GLib' + +// Initialize the package +imports.package.init({ + name: '@PACKAGE_NAME@', + version: '@PACKAGE_VERSION@', + prefix: '@PREFIX@', + libdir: '@LIBDIR@', +}); + +// Import the main module and run the main function +const loop = new GLib.MainLoop(null, false); + +// @ts-ignore +import('resource:///com/subgraph/citadel/Realms/js/main.js') + .then((main) => { + GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { + loop.quit(); + imports.package.run(main); + return GLib.SOURCE_REMOVE; + }); + }) + .catch(logError); + +loop.run(); diff --git a/src/com.subgraph.citadel.Realms.src.gresource.xml b/src/com.subgraph.citadel.Realms.src.gresource.xml new file mode 100644 index 0000000..8ae1cac --- /dev/null +++ b/src/com.subgraph.citadel.Realms.src.gresource.xml @@ -0,0 +1,26 @@ + + + + main.js + model/Base16Themes.js + model/LabelColors.js + model/ObjectManager.js + model/RealmManager.js + model/Realm.js + model/RealmConfig.js + model/OptionData.js + model/RealmFS.js + model/Utils.js + Application.js + ConfigureRealm.js + ColorSchemeChooser.js + ColorSchemeModel.js + + RealmRow.js + RealmsView.js + RealmInfo.js + RealmInfoEntry.js + RealmModel.js + Window.js + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..59001b1 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,8 @@ +import 'gi://Gdk?version=4.0' +import 'gi://Gtk?version=4.0' + +import { Application } from './Application.js' + +export function main(argv: string[]) { + return new Application().run(argv); +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..b377c79 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,24 @@ +configure_file( + input: APP_ID + '.js', + output: APP_ID, + configuration: { + 'GJS': find_program('gjs').full_path(), + 'PACKAGE_NAME': APP_ID, + 'PACKAGE_VERSION': meson.project_version(), + 'PREFIX': get_option('prefix'), + 'LIBDIR': get_option('prefix') / get_option('libdir') + }, + install_dir: get_option('bindir'), + install_mode: 'rwxr-xr-x' +) + + + +app_resource = gnome.compile_resources( + APP_ID + '.src', + APP_ID + '.src.gresource.xml', + gresource_bundle: true, + source_dir: '../js', + install: true, + install_dir: get_option('datadir') / APP_ID, +) diff --git a/src/model/Base16Themes.ts b/src/model/Base16Themes.ts new file mode 100644 index 0000000..a805916 --- /dev/null +++ b/src/model/Base16Themes.ts @@ -0,0 +1,1081 @@ + + +const TERM_MAP = [ + 0x00, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x05, + 0x03, 0x08, 0x0B, 0x0A, 0x0D, 0x0E, 0x0C, 0x07, + 0x09, 0x0F, 0x01, 0x02, 0x04, 0x06, +]; + +export class Base16Theme { + id: string; + name: string; + colors: number[]; + + constructor(id: string, name: string, colors: number[]) { + this.id = id; + this.name = name; + this.colors = colors; + } + + static THEMES = new Map(); + static THEME_LIST: Base16Theme[] = []; + + static add(id: string, name: string, colors: number[]) { + const theme = new Base16Theme(id, name, colors); + Base16Theme.THEME_LIST.push(theme); + Base16Theme.THEMES.set(id, theme); + } + + static lookup(id: string) { + return Base16Theme.THEMES.get(id); + } + + color(idx: number) { + let hex = this.colors[idx].toString(16).padStart(6, '0'); + return `#${hex}`; + } + + terminal_background() { + return this.color(0); + } + + terminal_foreground() { + return this.color(5); + } + + terminal_palette_color(idx: number) { + return this.color(TERM_MAP[idx]); + } +} + +Base16Theme.add("3024", "3024", + [ + 0x090300, 0x3a3432, 0x4a4543, 0x5c5855, + 0x807d7c, 0xa5a2a2, 0xd6d5d4, 0xf7f7f7, + 0xdb2d20, 0xe8bbd0, 0xfded02, 0x01a252, + 0xb5e4f4, 0x01a0e4, 0xa16a94, 0xcdab53, + ]); + +Base16Theme.add("apathy", 'Apathy', + [ + 0x031A16, 0x0B342D, 0x184E45, 0x2B685E, + 0x5F9C92, 0x81B5AC, 0xA7CEC8, 0xD2E7E4, + 0x3E9688, 0x3E7996, 0x3E4C96, 0x883E96, + 0x963E4C, 0x96883E, 0x4C963E, 0x3E965B, + ]); + +Base16Theme.add("ashes", "Ashes", + [ + 0x1C2023, 0x393F45, 0x565E65, 0x747C84, + 0xADB3BA, 0xC7CCD1, 0xDFE2E5, 0xF3F4F5, + 0xC7AE95, 0xC7C795, 0xAEC795, 0x95C7AE, + 0x95AEC7, 0xAE95C7, 0xC795AE, 0xC79595, + ]); + + +Base16Theme.add("atelier-cave-light", "Atelier Cave Light", + [ + 0xefecf4, 0xe2dfe7, 0x8b8792, 0x7e7887, + 0x655f6d, 0x585260, 0x26232a, 0x19171c, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, + ]); + +Base16Theme.add("atelier-cave", "Atelier Cave", + [ + 0x19171c, 0x26232a, 0x585260, 0x655f6d, + 0x7e7887, 0x8b8792, 0xe2dfe7, 0xefecf4, + 0xbe4678, 0xaa573c, 0xa06e3b, 0x2a9292, + 0x398bc6, 0x576ddb, 0x955ae7, 0xbf40bf, + ]); + +Base16Theme.add("atelier-dune-light", "Atelier Dune Light", + [ + 0xfefbec, 0xe8e4cf, 0xa6a28c, 0x999580, + 0x7d7a68, 0x6e6b5e, 0x292824, 0x20201d, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, + ]); + +Base16Theme.add("atelier-dune", "Atelier Dune", + [ + 0x20201d, 0x292824, 0x6e6b5e, 0x7d7a68, + 0x999580, 0xa6a28c, 0xe8e4cf, 0xfefbec, + 0xd73737, 0xb65611, 0xae9513, 0x60ac39, + 0x1fad83, 0x6684e1, 0xb854d4, 0xd43552, + ]); + +Base16Theme.add("atelier-estuary-light", "Atelier Estuary Light", + [ + 0xf4f3ec, 0xe7e6df, 0x929181, 0x878573, + 0x6c6b5a, 0x5f5e4e, 0x302f27, 0x22221b, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, + ]); + +Base16Theme.add("atelier-estuary", "Atelier Estuary", + [ + 0x22221b, 0x302f27, 0x5f5e4e, 0x6c6b5a, + 0x878573, 0x929181, 0xe7e6df, 0xf4f3ec, + 0xba6236, 0xae7313, 0xa5980d, 0x7d9726, + 0x5b9d48, 0x36a166, 0x5f9182, 0x9d6c7c, + ]); + +Base16Theme.add("atelier-forest-light", "Atelier Forest Light", + [ + 0xf1efee, 0xe6e2e0, 0xa8a19f, 0x9c9491, + 0x766e6b, 0x68615e, 0x2c2421, 0x1b1918, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, + ]); + +Base16Theme.add("atelier-forest", "Atelier Forest", + [ + 0x1b1918, 0x2c2421, 0x68615e, 0x766e6b, + 0x9c9491, 0xa8a19f, 0xe6e2e0, 0xf1efee, + 0xf22c40, 0xdf5320, 0xc38418, 0x7b9726, + 0x3d97b8, 0x407ee7, 0x6666ea, 0xc33ff3, + ]); + +Base16Theme.add("atelier-heath-light", "Atelier Heath Light", + [ + 0xf7f3f7, 0xd8cad8, 0xab9bab, 0x9e8f9e, + 0x776977, 0x695d69, 0x292329, 0x1b181b, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, + ]); + +Base16Theme.add("atelier-heath", "Atelier Heath", + [ + 0x1b181b, 0x292329, 0x695d69, 0x776977, + 0x9e8f9e, 0xab9bab, 0xd8cad8, 0xf7f3f7, + 0xca402b, 0xa65926, 0xbb8a35, 0x918b3b, + 0x159393, 0x516aec, 0x7b59c0, 0xcc33cc, + ]); + +Base16Theme.add("atelier-lakeside-light", "Atelier Lakeside Light", + [ + 0xebf8ff, 0xc1e4f6, 0x7ea2b4, 0x7195a8, + 0x5a7b8c, 0x516d7b, 0x1f292e, 0x161b1d, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, + ]); + +Base16Theme.add("atelier-lakeside", "Atelier Lakeside", + [ + 0x161b1d, 0x1f292e, 0x516d7b, 0x5a7b8c, + 0x7195a8, 0x7ea2b4, 0xc1e4f6, 0xebf8ff, + 0xd22d72, 0x935c25, 0x8a8a0f, 0x568c3b, + 0x2d8f6f, 0x257fad, 0x6b6bb8, 0xb72dd2, + ]); + +Base16Theme.add("atelier-plateau-light", "Atelier Plateau Light", + [ + 0xf4ecec, 0xe7dfdf, 0x8a8585, 0x7e7777, + 0x655d5d, 0x585050, 0x292424, 0x1b1818, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, + ]); + +Base16Theme.add("atelier-plateau", "Atelier Plateau", + [ + 0x1b1818, 0x292424, 0x585050, 0x655d5d, + 0x7e7777, 0x8a8585, 0xe7dfdf, 0xf4ecec, + 0xca4949, 0xb45a3c, 0xa06e3b, 0x4b8b8b, + 0x5485b6, 0x7272ca, 0x8464c4, 0xbd5187, + ]); + +Base16Theme.add("atelier-savanna-light", "Atelier Savanna Light", + [ + 0xecf4ee, 0xdfe7e2, 0x87928a, 0x78877d, + 0x5f6d64, 0x526057, 0x232a25, 0x171c19, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, + ]); + +Base16Theme.add("atelier-savanna", "Atelier Savanna", + [ + 0x171c19, 0x232a25, 0x526057, 0x5f6d64, + 0x78877d, 0x87928a, 0xdfe7e2, 0xecf4ee, + 0xb16139, 0x9f713c, 0xa07e3b, 0x489963, + 0x1c9aa0, 0x478c90, 0x55859b, 0x867469, + ]); + +Base16Theme.add("atelier-seaside-light", "Atelier Seaside Light", + [ + 0xf4fbf4, 0xcfe8cf, 0x8ca68c, 0x809980, + 0x687d68, 0x5e6e5e, 0x242924, 0x131513, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, + ]); + +Base16Theme.add("atelier-seaside", "Atelier Seaside", + [ + 0x131513, 0x242924, 0x5e6e5e, 0x687d68, + 0x809980, 0x8ca68c, 0xcfe8cf, 0xf4fbf4, + 0xe6193c, 0x87711d, 0x98981b, 0x29a329, + 0x1999b3, 0x3d62f5, 0xad2bee, 0xe619c3, + ]); + +Base16Theme.add("atelier-sulphurpool-light", "Atelier Sulphurpool Light", + [ + 0xf5f7ff, 0xdfe2f1, 0x979db4, 0x898ea4, + 0x6b7394, 0x5e6687, 0x293256, 0x202746, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, + ]); + +Base16Theme.add("atelier-sulphurpool", "Atelier Sulphurpool", + [ + 0x202746, 0x293256, 0x5e6687, 0x6b7394, + 0x898ea4, 0x979db4, 0xdfe2f1, 0xf5f7ff, + 0xc94922, 0xc76b29, 0xc08b30, 0xac9739, + 0x22a2c9, 0x3d8fd1, 0x6679cc, 0x9c637a, + ]); + +Base16Theme.add("atlas", "Atlas", + [ + 0x002635, 0x00384d, 0x517F8D, 0x6C8B91, + 0x869696, 0xa1a19a, 0xe6e6dc, 0xfafaf8, + 0xff5a67, 0xf08e48, 0xffcc1b, 0x7fc06e, + 0x14747e, 0x5dd7b9, 0x9a70a4, 0xc43060, + ]); + +Base16Theme.add("bespin", "Bespin", + [ + 0x28211c, 0x36312e, 0x5e5d5c, 0x666666, + 0x797977, 0x8a8986, 0x9d9b97, 0xbaae9e, + 0xcf6a4c, 0xcf7d34, 0xf9ee98, 0x54be0d, + 0xafc4db, 0x5ea6ea, 0x9b859d, 0x937121, + ]); + +Base16Theme.add("black-metal-bathory", "Black Metal (Bathory)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xe78a53, 0xfbcb97, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-burzum", "Black Metal (Burzum)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x99bbaa, 0xddeecc, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-dark-funeral", "Black Metal (Dark Funeral)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x5f81a5, 0xd0dfee, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-gorgoroth", "Black Metal (Gorgoroth)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x8c7f70, 0x9b8d7f, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-immortal", "Black Metal (Immortal)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x556677, 0x7799bb, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-khold", "Black Metal (Khold)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x974b46, 0xeceee3, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-marduk", "Black Metal (Marduk)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x626b67, 0xa5aaa7, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-mayhem", "Black Metal (Mayhem)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xeecc6c, 0xf3ecd4, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-nile", "Black Metal (Nile)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x777755, 0xaa9988, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal-venom", "Black Metal (Venom)", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0x79241f, 0xf8f7f2, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("black-metal", "Black Metal", + [ + 0x000000, 0x121212, 0x222222, 0x333333, + 0x999999, 0xc1c1c1, 0x999999, 0xc1c1c1, + 0x5f8787, 0xaaaaaa, 0xa06666, 0xdd9999, + 0xaaaaaa, 0x888888, 0x999999, 0x444444, + ]); + +Base16Theme.add("brewer", "Brewer", + [ + 0x0c0d0e, 0x2e2f30, 0x515253, 0x737475, + 0x959697, 0xb7b8b9, 0xdadbdc, 0xfcfdfe, + 0xe31a1c, 0xe6550d, 0xdca060, 0x31a354, + 0x80b1d3, 0x3182bd, 0x756bb1, 0xb15928, + ]); + +Base16Theme.add("bright", "Bright", + [ + 0x000000, 0x303030, 0x505050, 0xb0b0b0, + 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, 0xffffff, + 0xfb0120, 0xfc6d24, 0xfda331, 0xa1c659, + 0x76c7b7, 0x6fb3d2, 0xd381c3, 0xbe643c, + ]); + +Base16Theme.add("brogrammer", "Brogrammer", + [ + 0x1f1f1f, 0xf81118, 0x2dc55e, 0xecba0f, + 0x2a84d2, 0x4e5ab7, 0x1081d6, 0xd6dbe5, + 0xd6dbe5, 0xde352e, 0x1dd361, 0xf3bd09, + 0x1081d6, 0x5350b9, 0x0f7ddb, 0xffffff, + ]); + +Base16Theme.add("brushtrees-dark", "Brush Trees Dark", + [ + 0x485867, 0x5A6D7A, 0x6D828E, 0x8299A1, + 0x98AFB5, 0xB0C5C8, 0xC9DBDC, 0xE3EFEF, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, + ]); + +Base16Theme.add("brushtrees", "Brush Trees", + [ + 0xE3EFEF, 0xC9DBDC, 0xB0C5C8, 0x98AFB5, + 0x8299A1, 0x6D828E, 0x5A6D7A, 0x485867, + 0xb38686, 0xd8bba2, 0xaab386, 0x87b386, + 0x86b3b3, 0x868cb3, 0xb386b2, 0xb39f9f, + ]); + +Base16Theme.add("chalk", "Chalk", + [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xf5f5f5, + 0xfb9fb1, 0xeda987, 0xddb26f, 0xacc267, + 0x12cfc0, 0x6fc2ef, 0xe1a3ee, 0xdeaf8f, + ]); + +Base16Theme.add("circus", "Circus", + [ + 0x191919, 0x202020, 0x303030, 0x5f5a60, + 0x505050, 0xa7a7a7, 0x808080, 0xffffff, + 0xdc657d, 0x4bb1a7, 0xc3ba63, 0x84b97c, + 0x4bb1a7, 0x639ee4, 0xb888e2, 0xb888e2, + ]); + +Base16Theme.add("classic-dark", "Classic Dark", + [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xF5F5F5, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, + ]); + +Base16Theme.add("classic-light", "Classic Light", + [ + 0xF5F5F5, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x505050, 0x303030, 0x202020, 0x151515, + 0xAC4142, 0xD28445, 0xF4BF75, 0x90A959, + 0x75B5AA, 0x6A9FB5, 0xAA759F, 0x8F5536, + ]); + +Base16Theme.add("codeschool", "Codeschool", + [ + 0x232c31, 0x1c3657, 0x2a343a, 0x3f4944, + 0x84898c, 0x9ea7a6, 0xa7cfa3, 0xb5d8f6, + 0x2a5491, 0x43820d, 0xa03b1e, 0x237986, + 0xb02f30, 0x484d79, 0xc59820, 0xc98344, + ]); + +Base16Theme.add("cupcake", "Cupcake", + [ + 0xfbf1f2, 0xf2f1f4, 0xd8d5dd, 0xbfb9c6, + 0xa59daf, 0x8b8198, 0x72677E, 0x585062, + 0xD57E85, 0xEBB790, 0xDCB16C, 0xA3B367, + 0x69A9A7, 0x7297B9, 0xBB99B4, 0xBAA58C, + ]); + +Base16Theme.add("cupertino", "Cupertino", + [ + 0xffffff, 0xc0c0c0, 0xc0c0c0, 0x808080, + 0x808080, 0x404040, 0x404040, 0x5e5e5e, + 0xc41a15, 0xeb8500, 0x826b28, 0x007400, + 0x318495, 0x0000ff, 0xa90d91, 0x826b28, + ]); + +Base16Theme.add("darktooth", "Darktooth", + [ + 0x1D2021, 0x32302F, 0x504945, 0x665C54, + 0x928374, 0xA89984, 0xD5C4A1, 0xFDF4C1, + 0xFB543F, 0xFE8625, 0xFAC03B, 0x95C085, + 0x8BA59B, 0x0D6678, 0x8F4673, 0xA87322, + ]); + +Base16Theme.add("default-dark", "Default Dark", + [ + 0x181818, 0x282828, 0x383838, 0x585858, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, + ]); + +Base16Theme.add("default-light", "Default Light", + [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf7ca88, 0xa1b56c, + 0x86c1b9, 0x7cafc2, 0xba8baf, 0xa16946, + ]); + +Base16Theme.add("dracula", "Dracula", + [ + 0x282936, 0x3a3c4e, 0x4d4f68, 0x626483, + 0x62d6e8, 0xe9e9f4, 0xf1f2f8, 0xf7f7fb, + 0xea51b2, 0xb45bcf, 0x00f769, 0xebff87, + 0xa1efe4, 0x62d6e8, 0xb45bcf, 0x00f769, + ]); + +Base16Theme.add("eighties", "Eighties", + [ + 0x2d2d2d, 0x393939, 0x515151, 0x747369, + 0xa09f93, 0xd3d0c8, 0xe8e6df, 0xf2f0ec, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xd27b53, + ]); + +Base16Theme.add("embers", "Embers", + [ + 0x16130F, 0x2C2620, 0x433B32, 0x5A5047, + 0x8A8075, 0xA39A90, 0xBEB6AE, 0xDBD6D1, + 0x826D57, 0x828257, 0x6D8257, 0x57826D, + 0x576D82, 0x6D5782, 0x82576D, 0x825757, + ]); + +Base16Theme.add("flat", "Flat", + [ + 0x2C3E50, 0x34495E, 0x7F8C8D, 0x95A5A6, + 0xBDC3C7, 0xe0e0e0, 0xf5f5f5, 0xECF0F1, + 0xE74C3C, 0xE67E22, 0xF1C40F, 0x2ECC71, + 0x1ABC9C, 0x3498DB, 0x9B59B6, 0xbe643c, + ]); + +Base16Theme.add("fruit-soda", "Fruit Soda", + [ + 0xf1ecf1, 0xe0dee0, 0xd8d5d5, 0xb5b4b6, + 0x979598, 0x515151, 0x474545, 0x2d2c2c, + 0xfe3e31, 0xfe6d08, 0xf7e203, 0x47f74c, + 0x0f9cfd, 0x2931df, 0x611fce, 0xb16f40, + ]); + +Base16Theme.add("github", "Github", + [ + 0xffffff, 0xf5f5f5, 0xc8c8fa, 0x969896, + 0xe8e8e8, 0x333333, 0xffffff, 0xffffff, + 0xed6a43, 0x0086b3, 0x795da3, 0x183691, + 0x183691, 0x795da3, 0xa71d5d, 0x333333, + ]); + +Base16Theme.add("google-dark", "Google Dark", + [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, + ]); + +Base16Theme.add("google-light", "Google Light", + [ + 0xffffff, 0xe0e0e0, 0xc5c8c6, 0xb4b7b4, + 0x969896, 0x373b41, 0x282a2e, 0x1d1f21, + 0xCC342B, 0xF96A38, 0xFBA922, 0x198844, + 0x3971ED, 0x3971ED, 0xA36AC7, 0x3971ED, + ]); + +Base16Theme.add("grayscale-dark", "Grayscale Dark", + [ + 0x101010, 0x252525, 0x464646, 0x525252, + 0xababab, 0xb9b9b9, 0xe3e3e3, 0xf7f7f7, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, + ]); + +Base16Theme.add("grayscale-light", "Grayscale Light", + [ + 0xf7f7f7, 0xe3e3e3, 0xb9b9b9, 0xababab, + 0x525252, 0x464646, 0x252525, 0x101010, + 0x7c7c7c, 0x999999, 0xa0a0a0, 0x8e8e8e, + 0x868686, 0x686868, 0x747474, 0x5e5e5e, + ]); + +Base16Theme.add("greenscreen", "Green Screen", + [ + 0x001100, 0x003300, 0x005500, 0x007700, + 0x009900, 0x00bb00, 0x00dd00, 0x00ff00, + 0x007700, 0x009900, 0x007700, 0x00bb00, + 0x005500, 0x009900, 0x00bb00, 0x005500, + ]); + +Base16Theme.add("gruvbox-dark-hard", "Gruvbox dark, hard", + [ + 0x1d2021, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-dark-medium", "Gruvbox dark, medium", + [ + 0x282828, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-dark-pale", "Gruvbox dark, pale", + [ + 0x262626, 0x3a3a3a, 0x4e4e4e, 0x8a8a8a, + 0x949494, 0xdab997, 0xd5c4a1, 0xebdbb2, + 0xd75f5f, 0xff8700, 0xffaf00, 0xafaf00, + 0x85ad85, 0x83adad, 0xd485ad, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-dark-soft", "Gruvbox dark, soft", + [ + 0x32302f, 0x3c3836, 0x504945, 0x665c54, + 0xbdae93, 0xd5c4a1, 0xebdbb2, 0xfbf1c7, + 0xfb4934, 0xfe8019, 0xfabd2f, 0xb8bb26, + 0x8ec07c, 0x83a598, 0xd3869b, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-light-hard", "Gruvbox light, hard", + [ + 0xf9f5d7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-light-medium", "Gruvbox light, medium", + [ + 0xfbf1c7, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, + ]); + +Base16Theme.add("gruvbox-light-soft", "Gruvbox light, soft", + [ + 0xf2e5bc, 0xebdbb2, 0xd5c4a1, 0xbdae93, + 0x665c54, 0x504945, 0x3c3836, 0x282828, + 0x9d0006, 0xaf3a03, 0xb57614, 0x79740e, + 0x427b58, 0x076678, 0x8f3f71, 0xd65d0e, + ]); + +Base16Theme.add("harmonic-dark", "Harmonic16 Dark", + [ + 0x0b1c2c, 0x223b54, 0x405c79, 0x627e99, + 0xaabcce, 0xcbd6e2, 0xe5ebf1, 0xf7f9fb, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, + ]); + +Base16Theme.add("harmonic-light", "Harmonic16 Light", + [ + 0xf7f9fb, 0xe5ebf1, 0xcbd6e2, 0xaabcce, + 0x627e99, 0x405c79, 0x223b54, 0x0b1c2c, + 0xbf8b56, 0xbfbf56, 0x8bbf56, 0x56bf8b, + 0x568bbf, 0x8b56bf, 0xbf568b, 0xbf5656, + ]); + +Base16Theme.add("heetch-light", "Heetch Light", + [ + 0xfeffff, 0x392551, 0x7b6d8b, 0x9c92a8, + 0xddd6e5, 0x5a496e, 0x470546, 0x190134, + 0x27d9d5, 0xbdb6c5, 0x5ba2b6, 0xf80059, + 0xc33678, 0x47f9f5, 0xbd0152, 0xdedae2, + ]); + +Base16Theme.add("heetch", "Heetch Dark", + [ + 0x190134, 0x392551, 0x5A496E, 0x7B6D8B, + 0x9C92A8, 0xBDB6C5, 0xDEDAE2, 0xFEFFFF, + 0x27D9D5, 0x5BA2B6, 0x8F6C97, 0xC33678, + 0xF80059, 0xBD0152, 0x82034C, 0x470546, + ]); + +Base16Theme.add("helios", "Helios", + [ + 0x1d2021, 0x383c3e, 0x53585b, 0x6f7579, + 0xcdcdcd, 0xd5d5d5, 0xdddddd, 0xe5e5e5, + 0xd72638, 0xeb8413, 0xf19d1a, 0x88b92d, + 0x1ba595, 0x1e8bac, 0xbe4264, 0xc85e0d, + ]); + +Base16Theme.add("hopscotch", "Hopscotch", + [ + 0x322931, 0x433b42, 0x5c545b, 0x797379, + 0x989498, 0xb9b5b8, 0xd5d3d5, 0xffffff, + 0xdd464c, 0xfd8b19, 0xfdcc59, 0x8fc13e, + 0x149b93, 0x1290bf, 0xc85e7c, 0xb33508, + ]); + +Base16Theme.add("horizon-dark", "Horizon Dark", + [ + 0x1c1e26, 0x232530, 0x2e303e, 0x676a8d, + 0xced1d0, 0xcbced0, 0xdcdfe4, 0xe3e6ee, + 0xe93c58, 0xe58d7d, 0xefb993, 0xefaf8e, + 0x24a8b4, 0xdf5273, 0xb072d1, 0xe4a382, + ]); + +Base16Theme.add("ia-dark", "iA Dark", + [ + 0x1a1a1a, 0x222222, 0x1d414d, 0x767676, + 0xb8b8b8, 0xcccccc, 0xe8e8e8, 0xf8f8f8, + 0xd88568, 0xd86868, 0xb99353, 0x83a471, + 0x7c9cae, 0x8eccdd, 0xb98eb2, 0x8b6c37, + ]); + +Base16Theme.add("ia-light", "iA Light", + [ + 0xf6f6f6, 0xdedede, 0xbde5f2, 0x898989, + 0x767676, 0x181818, 0xe8e8e8, 0xf8f8f8, + 0x9c5a02, 0xc43e18, 0xc48218, 0x38781c, + 0x2d6bb1, 0x48bac2, 0xa94598, 0x8b6c37, + ]); + +Base16Theme.add("icy", "Icy Dark", + [ + 0x021012, 0x031619, 0x041f23, 0x052e34, + 0x064048, 0x095b67, 0x0c7c8c, 0x109cb0, + 0x16c1d9, 0xb3ebf2, 0x80deea, 0x4dd0e1, + 0x26c6da, 0x00bcd4, 0x00acc1, 0x0097a7, + ]); + +Base16Theme.add("irblack", "IR Black", + [ + 0x000000, 0x242422, 0x484844, 0x6c6c66, + 0x918f88, 0xb5b3aa, 0xd9d7cc, 0xfdfbee, + 0xff6c60, 0xe9c062, 0xffffb6, 0xa8ff60, + 0xc6c5fe, 0x96cbfe, 0xff73fd, 0xb18a3d, + ]); + +Base16Theme.add("isotope", "Isotope", + [ + 0x000000, 0x404040, 0x606060, 0x808080, + 0xc0c0c0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xff0000, 0xff9900, 0xff0099, 0x33ff00, + 0x00ffff, 0x0066ff, 0xcc00ff, 0x3300ff, + ]); + +Base16Theme.add("macintosh", "Macintosh", + [ + 0x000000, 0x404040, 0x404040, 0x808080, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0xffffff, + 0xdd0907, 0xff6403, 0xfbf305, 0x1fb714, + 0x02abea, 0x0000d3, 0x4700a5, 0x90713a, + ]); + +Base16Theme.add("marrakesh", "Marrakesh", + [ + 0x201602, 0x302e00, 0x5f5b17, 0x6c6823, + 0x86813b, 0x948e48, 0xccc37a, 0xfaf0a5, + 0xc35359, 0xb36144, 0xa88339, 0x18974e, + 0x75a738, 0x477ca1, 0x8868b3, 0xb3588e, + ]); + +Base16Theme.add("materia", "Materia", + [ + 0x263238, 0x2C393F, 0x37474F, 0x707880, + 0xC9CCD3, 0xCDD3DE, 0xD5DBE5, 0xFFFFFF, + 0xEC5F67, 0xEA9560, 0xFFCC00, 0x8BD649, + 0x80CBC4, 0x89DDFF, 0x82AAFF, 0xEC5F67, + ]); + +Base16Theme.add("material-darker", "Material Darker", + [ + 0x212121, 0x303030, 0x353535, 0x4A4A4A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, + ]); + +Base16Theme.add("material-lighter", "Material Lighter", + [ + 0xFAFAFA, 0xE7EAEC, 0xCCEAE7, 0xCCD7DA, + 0x8796B0, 0x80CBC4, 0x80CBC4, 0xFFFFFF, + 0xFF5370, 0xF76D47, 0xFFB62C, 0x91B859, + 0x39ADB5, 0x6182B8, 0x7C4DFF, 0xE53935, + ]); + +Base16Theme.add("material-palenight", "Material Palenight", + [ + 0x292D3E, 0x444267, 0x32374D, 0x676E95, + 0x8796B0, 0x959DCB, 0x959DCB, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, + ]); + +Base16Theme.add("material-vivid", "Material Vivid", + [ + 0x202124, 0x27292c, 0x323639, 0x44464d, + 0x676c71, 0x80868b, 0x9e9e9e, 0xffffff, + 0xf44336, 0xff9800, 0xffeb3b, 0x00e676, + 0x00bcd4, 0x2196f3, 0x673ab7, 0x8d6e63, + ]); + +Base16Theme.add("material", "Material", + [ + 0x263238, 0x2E3C43, 0x314549, 0x546E7A, + 0xB2CCD6, 0xEEFFFF, 0xEEFFFF, 0xFFFFFF, + 0xF07178, 0xF78C6C, 0xFFCB6B, 0xC3E88D, + 0x89DDFF, 0x82AAFF, 0xC792EA, 0xFF5370, + ]); + +Base16Theme.add("mellow-purple", "Mellow Purple", + [ + 0x1e0528, 0x1A092D, 0x331354, 0x320f55, + 0x873582, 0xffeeff, 0xffeeff, 0xf8c0ff, + 0x00d9e9, 0xaa00a3, 0x955ae7, 0x05cb0d, + 0xb900b1, 0x550068, 0x8991bb, 0x4d6fff, + ]); + +Base16Theme.add("mexico-light", "Mexico Light", + [ + 0xf8f8f8, 0xe8e8e8, 0xd8d8d8, 0xb8b8b8, + 0x585858, 0x383838, 0x282828, 0x181818, + 0xab4642, 0xdc9656, 0xf79a0e, 0x538947, + 0x4b8093, 0x7cafc2, 0x96609e, 0xa16946, + ]); + +Base16Theme.add("mocha", "Mocha", + [ + 0x3B3228, 0x534636, 0x645240, 0x7e705a, + 0xb8afad, 0xd0c8c6, 0xe9e1dd, 0xf5eeeb, + 0xcb6077, 0xd28b71, 0xf4bc87, 0xbeb55b, + 0x7bbda4, 0x8ab3b5, 0xa89bb9, 0xbb9584, + ]); + +Base16Theme.add("monokai", "Monokai", + [ + 0x272822, 0x383830, 0x49483e, 0x75715e, + 0xa59f85, 0xf8f8f2, 0xf5f4f1, 0xf9f8f5, + 0xf92672, 0xfd971f, 0xf4bf75, 0xa6e22e, + 0xa1efe4, 0x66d9ef, 0xae81ff, 0xcc6633, + ]); + +Base16Theme.add("nord", "Nord", + [ + 0x2E3440, 0x3B4252, 0x434C5E, 0x4C566A, + 0xD8DEE9, 0xE5E9F0, 0xECEFF4, 0x8FBCBB, + 0x88C0D0, 0x81A1C1, 0x5E81AC, 0xBF616A, + 0xD08770, 0xEBCB8B, 0xA3BE8C, 0xB48EAD, + ]); + +Base16Theme.add("ocean", "Ocean", + [ + 0x2b303b, 0x343d46, 0x4f5b66, 0x65737e, + 0xa7adba, 0xc0c5ce, 0xdfe1e8, 0xeff1f5, + 0xbf616a, 0xd08770, 0xebcb8b, 0xa3be8c, + 0x96b5b4, 0x8fa1b3, 0xb48ead, 0xab7967, + ]); + +Base16Theme.add("oceanicnext", "OceanicNext", + [ + 0x1B2B34, 0x343D46, 0x4F5B66, 0x65737E, + 0xA7ADBA, 0xC0C5CE, 0xCDD3DE, 0xD8DEE9, + 0xEC5F67, 0xF99157, 0xFAC863, 0x99C794, + 0x5FB3B3, 0x6699CC, 0xC594C5, 0xAB7967, + ]); + +Base16Theme.add("one-light", "One Light", + [ + 0xfafafa, 0xf0f0f1, 0xe5e5e6, 0xa0a1a7, + 0x696c77, 0x383a42, 0x202227, 0x090a0b, + 0xca1243, 0xd75f00, 0xc18401, 0x50a14f, + 0x0184bc, 0x4078f2, 0xa626a4, 0x986801, + ]); + +Base16Theme.add("onedark", "OneDark", + [ + 0x282c34, 0x353b45, 0x3e4451, 0x545862, + 0x565c64, 0xabb2bf, 0xb6bdca, 0xc8ccd4, + 0xe06c75, 0xd19a66, 0xe5c07b, 0x98c379, + 0x56b6c2, 0x61afef, 0xc678dd, 0xbe5046, + ]); + +Base16Theme.add("outrun-dark", "Outrun Dark", + [ + 0x00002A, 0x20204A, 0x30305A, 0x50507A, + 0xB0B0DA, 0xD0D0FA, 0xE0E0FF, 0xF5F5FF, + 0xFF4242, 0xFC8D28, 0xF3E877, 0x59F176, + 0x0EF0F0, 0x66B0FF, 0xF10596, 0xF003EF, + ]); + +Base16Theme.add("papercolor-dark", "PaperColor Dark", + [ + 0x1c1c1c, 0xaf005f, 0x5faf00, 0xd7af5f, + 0x5fafd7, 0x808080, 0xd7875f, 0xd0d0d0, + 0x585858, 0x5faf5f, 0xafd700, 0xaf87d7, + 0xffaf00, 0xff5faf, 0x00afaf, 0x5f8787, + ]); + +Base16Theme.add("papercolor-light", "PaperColor Light", + [ + 0xeeeeee, 0xaf0000, 0x008700, 0x5f8700, + 0x0087af, 0x878787, 0x005f87, 0x444444, + 0xbcbcbc, 0xd70000, 0xd70087, 0x8700af, + 0xd75f00, 0xd75f00, 0x005faf, 0x005f87, + ]); + +Base16Theme.add("paraiso", "Paraiso", + [ + 0x2f1e2e, 0x41323f, 0x4f424c, 0x776e71, + 0x8d8687, 0xa39e9b, 0xb9b6b0, 0xe7e9db, + 0xef6155, 0xf99b15, 0xfec418, 0x48b685, + 0x5bc4bf, 0x06b6ef, 0x815ba4, 0xe96ba8, + ]); + +Base16Theme.add("phd", "PhD", + [ + 0x061229, 0x2a3448, 0x4d5666, 0x717885, + 0x9a99a3, 0xb8bbc2, 0xdbdde0, 0xffffff, + 0xd07346, 0xf0a000, 0xfbd461, 0x99bf52, + 0x72b9bf, 0x5299bf, 0x9989cc, 0xb08060, + ]); + +Base16Theme.add("pico", "Pico", + [ + 0x000000, 0x1d2b53, 0x7e2553, 0x008751, + 0xab5236, 0x5f574f, 0xc2c3c7, 0xfff1e8, + 0xff004d, 0xffa300, 0xfff024, 0x00e756, + 0x29adff, 0x83769c, 0xff77a8, 0xffccaa, + ]); + +Base16Theme.add("pop", "Pop", + [ + 0x000000, 0x202020, 0x303030, 0x505050, + 0xb0b0b0, 0xd0d0d0, 0xe0e0e0, 0xffffff, + 0xeb008a, 0xf29333, 0xf8ca12, 0x37b349, + 0x00aabb, 0x0e5a94, 0xb31e8d, 0x7a2d00, + ]); + +Base16Theme.add("porple", "Porple", + [ + 0x292c36, 0x333344, 0x474160, 0x65568a, + 0xb8b8b8, 0xd8d8d8, 0xe8e8e8, 0xf8f8f8, + 0xf84547, 0xd28e5d, 0xefa16b, 0x95c76f, + 0x64878f, 0x8485ce, 0xb74989, 0x986841, + ]); +Base16Theme.add("qualia", "Qualia", + [ + 0x101010, 0x454545, 0x454545, 0x454545, + 0x808080, 0xc0c0c0, 0xc0c0c0, 0x454545, + 0xefa6a2, 0xa3b8ef, 0xe6a3dc, 0x80c990, + 0xc8c874, 0x50cacd, 0xe0af85, 0x808080, + ]); + +Base16Theme.add("railscasts", "Railscasts", + [ + 0x2b2b2b, 0x272935, 0x3a4055, 0x5a647e, + 0xd4cfc9, 0xe6e1dc, 0xf4f1ed, 0xf9f7f3, + 0xda4939, 0xcc7833, 0xffc66d, 0xa5c261, + 0x519f50, 0x6d9cbe, 0xb6b3eb, 0xbc9458, + ]); + +Base16Theme.add("rebecca", "Rebecca", + [ + 0x292a44, 0x663399, 0x383a62, 0x666699, + 0xa0a0c5, 0xf1eff8, 0xccccff, 0x53495d, + 0xa0a0c5, 0xefe4a1, 0xae81ff, 0x6dfedf, + 0x8eaee0, 0x2de0a7, 0x7aa5ff, 0xff79c6, + ]); + +Base16Theme.add("seti", "Seti UI", + [ + 0x151718, 0x282a2b, 0x3B758C, 0x41535B, + 0x43a5d5, 0xd6d6d6, 0xeeeeee, 0xffffff, + 0xcd3f45, 0xdb7b55, 0xe6cd69, 0x9fca56, + 0x55dbbe, 0x55b5db, 0xa074c4, 0x8a553f, + ]); + +Base16Theme.add("shapeshifter", "Shapeshifter", + [ + 0xf9f9f9, 0xe0e0e0, 0xababab, 0x555555, + 0x343434, 0x102015, 0x040404, 0x000000, + 0xe92f2f, 0xe09448, 0xdddd13, 0x0ed839, + 0x23edda, 0x3b48e3, 0xf996e2, 0x69542d, + ]); + +Base16Theme.add("snazzy", "Snazzy", + [ + 0x282a36, 0x34353e, 0x43454f, 0x78787e, + 0xa5a5a9, 0xe2e4e5, 0xeff0eb, 0xf1f1f0, + 0xff5c57, 0xff9f43, 0xf3f99d, 0x5af78e, + 0x9aedfe, 0x57c7ff, 0xff6ac1, 0xb2643c, + ]); + +Base16Theme.add("solarflare", "Solar Flare", + [ + 0x18262F, 0x222E38, 0x586875, 0x667581, + 0x85939E, 0xA6AFB8, 0xE8E9ED, 0xF5F7FA, + 0xEF5253, 0xE66B2B, 0xE4B51C, 0x7CC844, + 0x52CBB0, 0x33B5E1, 0xA363D5, 0xD73C9A, + ]); + +Base16Theme.add("solarized-dark", "Solarized Dark", + [ + 0x002b36, 0x073642, 0x586e75, 0x657b83, + 0x839496, 0x93a1a1, 0xeee8d5, 0xfdf6e3, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, + ]); + +Base16Theme.add("solarized-light", "Solarized Light", + [ + 0xfdf6e3, 0xeee8d5, 0x93a1a1, 0x839496, + 0x657b83, 0x586e75, 0x073642, 0x002b36, + 0xdc322f, 0xcb4b16, 0xb58900, 0x859900, + 0x2aa198, 0x268bd2, 0x6c71c4, 0xd33682, + ]); + +Base16Theme.add("spacemacs", "Spacemacs", + [ + 0x1f2022, 0x282828, 0x444155, 0x585858, + 0xb8b8b8, 0xa3a3a3, 0xe8e8e8, 0xf8f8f8, + 0xf2241f, 0xffa500, 0xb1951d, 0x67b11d, + 0x2d9574, 0x4f97d7, 0xa31db1, 0xb03060, + ]); + +Base16Theme.add("summerfruit-dark", "Summerfruit Dark", + [ + 0x151515, 0x202020, 0x303030, 0x505050, + 0xB0B0B0, 0xD0D0D0, 0xE0E0E0, 0xFFFFFF, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, + ]); + +Base16Theme.add("summerfruit-light", "Summerfruit Light", + [ + 0xFFFFFF, 0xE0E0E0, 0xD0D0D0, 0xB0B0B0, + 0x000000, 0x101010, 0x151515, 0x202020, + 0xFF0086, 0xFD8900, 0xABA800, 0x00C918, + 0x1FAAAA, 0x3777E6, 0xAD00A1, 0xCC6633, + ]); + +Base16Theme.add("synth-midnight-dark", "Synth Midnight", + [ + 0x040404, 0x141414, 0x242424, 0x61507A, + 0xBFBBBF, 0xDFDBDF, 0xEFEBEF, 0xFFFBFF, + 0xB53B50, 0xE4600E, 0xDAE84D, 0x06EA61, + 0x7CEDE9, 0x03AEFF, 0xEA5CE2, 0x9D4D0E, + ]); + +Base16Theme.add("tomorrow-night-eighties", "Tomorrow Night Eighties", + [ + 0x2d2d2d, 0x393939, 0x515151, 0x999999, + 0xb4b7b4, 0xcccccc, 0xe0e0e0, 0xffffff, + 0xf2777a, 0xf99157, 0xffcc66, 0x99cc99, + 0x66cccc, 0x6699cc, 0xcc99cc, 0xa3685a, + ]); + +Base16Theme.add("tomorrow-night", "Tomorrow Night", + [ + 0x1d1f21, 0x282a2e, 0x373b41, 0x969896, + 0xb4b7b4, 0xc5c8c6, 0xe0e0e0, 0xffffff, + 0xcc6666, 0xde935f, 0xf0c674, 0xb5bd68, + 0x8abeb7, 0x81a2be, 0xb294bb, 0xa3685a, + ]); + +Base16Theme.add("tomorrow", "Tomorrow", + [ + 0xffffff, 0xe0e0e0, 0xd6d6d6, 0x8e908c, + 0x969896, 0x4d4d4c, 0x282a2e, 0x1d1f21, + 0xc82829, 0xf5871f, 0xeab700, 0x718c00, + 0x3e999f, 0x4271ae, 0x8959a8, 0xa3685a, + ]); + +Base16Theme.add("tube", "London Tube", + [ + 0x231f20, 0x1c3f95, 0x5a5758, 0x737171, + 0x959ca1, 0xd9d8d8, 0xe7e7e8, 0xffffff, + 0xee2e24, 0xf386a1, 0xffd204, 0x00853e, + 0x85cebc, 0x009ddc, 0x98005d, 0xb06110, + ]); + +Base16Theme.add("twilight", "Twilight", + [ + 0x1e1e1e, 0x323537, 0x464b50, 0x5f5a60, + 0x838184, 0xa7a7a7, 0xc3c3c3, 0xffffff, + 0xcf6a4c, 0xcda869, 0xf9ee98, 0x8f9d6a, + 0xafc4db, 0x7587a6, 0x9b859d, 0x9b703f, + ]); + +Base16Theme.add("unikitty-dark", "Unikitty Dark", + [ + 0x2e2a31, 0x4a464d, 0x666369, 0x838085, + 0x9f9da2, 0xbcbabe, 0xd8d7da, 0xf5f4f7, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x796af5, 0xbb60ea, 0xc720ca, + ]); + +Base16Theme.add("unikitty-light", "Unikitty Light", + [ + 0xffffff, 0xe1e1e2, 0xc4c3c5, 0xa7a5a8, + 0x89878b, 0x6c696e, 0x4f4b51, 0x322d34, + 0xd8137f, 0xd65407, 0xdc8a0e, 0x17ad98, + 0x149bda, 0x775dff, 0xaa17e6, 0xe013d0, + ]); + +Base16Theme.add("woodland", "Woodland", + [ + 0x231e18, 0x302b25, 0x48413a, 0x9d8b70, + 0xb4a490, 0xcabcb1, 0xd7c8bc, 0xe4d4c8, + 0xd35c5c, 0xca7f32, 0xe0ac16, 0xb7ba53, + 0x6eb958, 0x88a4d3, 0xbb90e2, 0xb49368, + ]); + +Base16Theme.add("xcode-dusk", "XCode Dusk", + [ + 0x282B35, 0x3D4048, 0x53555D, 0x686A71, + 0x7E8086, 0x939599, 0xA9AAAE, 0xBEBFC2, + 0xB21889, 0x786DC5, 0x438288, 0xDF0002, + 0x00A0BE, 0x790EAD, 0xB21889, 0xC77C48, + ]); + +Base16Theme.add("zenburn", "Zenburn", + [ + 0x383838, 0x404040, 0x606060, 0x6f6f6f, + 0x808080, 0xdcdccc, 0xc0c0c0, 0xffffff, + 0xdca3a3, 0xdfaf8f, 0xe0cf9f, 0x5f7f5f, + 0x93e0e3, 0x7cb8bb, 0xdc8cc3, 0x000000, + ]); diff --git a/src/model/LabelColors.ts b/src/model/LabelColors.ts new file mode 100644 index 0000000..2854272 --- /dev/null +++ b/src/model/LabelColors.ts @@ -0,0 +1,89 @@ +import Gdk from 'gi://Gdk?version=4.0'; +import Gio from 'gi://Gio'; +import {Realm} from './Realm.js' + +const CITADEL_SETTINGS_SCHEMA = 'com.subgraph.citadel'; +const LABEL_COLOR_LIST_KEY = 'label-color-list'; +const REALM_LABEL_COLORS_KEY = 'realm-label-colors'; + +const DEFAULT_LABEL_COLOR = new Gdk.RGBA({ red: 153, green: 193, blue: 241, }); + +export class LabelColorManager { + private _citadelSettings: Gio.Settings; + private _defaultColors: Gdk.RGBA[]; + private _realmLabelColors: Map; + + constructor() { + this._citadelSettings = new Gio.Settings({ schema_id: CITADEL_SETTINGS_SCHEMA }); + this._defaultColors = []; + this._realmLabelColors = new Map(); + this._loadColors(); + } + + _loadColors() { + let entries = this._citadelSettings.get_strv(LABEL_COLOR_LIST_KEY); + entries.forEach(entry => { + let c = new Gdk.RGBA(); + if (c.parse(entry)) { + this._defaultColors.push(c); + + } + }); + + entries = this._citadelSettings.get_strv(REALM_LABEL_COLORS_KEY); + entries.forEach(entry => { + let parts = entry.split(":"); + if (parts.length === 2) { + let c = new Gdk.RGBA(); + if (c.parse(parts[1])) { + this._realmLabelColors.set(parts[0], c); + } + } + }) + } + + + updateRealmColor(realm: Realm, color: Gdk.RGBA) { + this._realmLabelColors.set(realm.name, color); + this._storeRealmColors(); + } + + lookupRealmColor(realm: Realm): Gdk.RGBA { + let c = this._realmLabelColors.get(realm.name); + if (c) { + return c; + } + + let newColor = this._allocateColor(); + this.updateRealmColor(realm, newColor); + return newColor; + } + + _storeRealmColors() { + let entries: string[] = []; + this._realmLabelColors.forEach((v,k) => { + entries.push(`${k}:${v.to_string()}`); + }); + entries.sort(); + + this._citadelSettings.set_strv(REALM_LABEL_COLORS_KEY, entries); + } + + _allocateColor() { + // 1) No default colors? return a built in color + if (this._defaultColors.length === 0) { + return DEFAULT_LABEL_COLOR; + } + + // 2) Find first color on default color list that isn't used already + let usedColors = Array.from(this._realmLabelColors.values()); + let defaultColor = this._defaultColors.find(color => !usedColors.some(c => c.equal(color))); + if (defaultColor) { + return defaultColor; + } + + // 3) Choose a random element of the default list + let index = Math.floor(Math.random() * this._defaultColors.length); + return this._defaultColors[index]; + } +} diff --git a/src/model/ObjectManager.ts b/src/model/ObjectManager.ts new file mode 100644 index 0000000..51ee855 --- /dev/null +++ b/src/model/ObjectManager.ts @@ -0,0 +1,239 @@ +import Gio from 'gi://Gio'; +import GLib from 'gi://GLib'; +const Signals = imports.signals; + +import type {SignalMethods} from 'gjs'; + +Gio._promisify(Gio.DBusProxy.prototype, 'init_async', 'init_finish'); + +// Specified in the D-Bus specification here: +// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager +const ObjectManagerIface = ` + + + + + + + + + + + + + + +`; + +const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface); + + +export interface ObjectManager extends SignalMethods {}; + +export class ObjectManager { + private _connection: Gio.DBusConnection; + private _serviceName: string; + private _managerPath: string; + private _cancellable: any; + private _interfaceInfos: { [s: string]: Gio.DBusInterfaceInfo }; + private _objects: { [s: string]: { [s: string]: Gio.DBusProxy }}; + private _onLoaded: any; + private _managerProxy: Gio.DBusProxy; + private _interfaces: { [s: string]: Gio.DBusProxy[] }; + + constructor(params: { connection: Gio.DBusConnection; name: string; objectPath: string; knownInterfaces: any; onLoaded: any; cancellable?: any; }) { + this._connection = params.connection; + this._serviceName = params.name; + this._managerPath = params.objectPath; + this._cancellable = params.cancellable ?? null; + + this._managerProxy = new Gio.DBusProxy({ + g_connection: this._connection, + g_interface_name: ObjectManagerInfo.name, + g_interface_info: ObjectManagerInfo, + g_name: this._serviceName, + g_object_path: this._managerPath, + g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START, + }); + + this._interfaceInfos = {}; + this._objects = {}; + this._interfaces = {}; + this._onLoaded = params.onLoaded; + + if (params.knownInterfaces) + this._registerInterfaces(params.knownInterfaces); + + this._initManagerProxy(); + } + + _completeLoad() { + if (this._onLoaded) + this._onLoaded(); + } + + async _addInterface(objectPath: string, interfaceName: string) { + let info = this._interfaceInfos[interfaceName]; + + if (!info) + return; + + const proxy = new Gio.DBusProxy({ + g_connection: this._connection, + g_name: this._serviceName, + g_object_path: objectPath, + g_interface_name: interfaceName, + g_interface_info: info, + g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START, + }); + + try { + await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable); + } catch (e: any) { + logError(e, `could not initialize proxy for interface ${interfaceName}`); + return; + } + + let isNewObject; + if (!this._objects[objectPath]) { + this._objects[objectPath] = {}; + isNewObject = true; + } else { + isNewObject = false; + } + + this._objects[objectPath][interfaceName] = proxy; + + if (!this._interfaces[interfaceName]) + this._interfaces[interfaceName] = []; + + this._interfaces[interfaceName].push(proxy); + + if (isNewObject) + this.emit('object-added', objectPath); + + this.emit('interface-added', interfaceName, proxy); + } + + _removeInterface(objectPath: string, interfaceName: string) { + if (!this._objects[objectPath]) + return; + + let proxy = this._objects[objectPath][interfaceName]; + + if (this._interfaces[interfaceName]) { + let index = this._interfaces[interfaceName].indexOf(proxy); + + if (index >= 0) + this._interfaces[interfaceName].splice(index, 1); + + if (this._interfaces[interfaceName].length === 0) + delete this._interfaces[interfaceName]; + } + + this.emit('interface-removed', interfaceName, proxy); + + delete this._objects[objectPath][interfaceName]; + + if (Object.keys(this._objects[objectPath]).length === 0) { + delete this._objects[objectPath]; + this.emit('object-removed', objectPath); + } + } + + async _initManagerProxy() { + try { + await this._managerProxy.init_async( + GLib.PRIORITY_DEFAULT, this._cancellable); + } catch (e: any) { + logError(e, `could not initialize object manager for object ${this._serviceName}`); + + this._completeLoad(); + return; + } + + this._managerProxy.connectSignal('InterfacesAdded', + (_objectManager: any, _sender: any, [objectPath, interfaces]: any) => { + let interfaceNames = Object.keys(interfaces); + for (let i = 0; i < interfaceNames.length; i++) + this._addInterface(objectPath, interfaceNames[i]); + }); + this._managerProxy.connectSignal('InterfacesRemoved', + (_objectManager: any, _sender: any, [objectPath, interfaceNames]: any) => { + for (let i = 0; i < interfaceNames.length; i++) + this._removeInterface(objectPath, interfaceNames[i]); + }); + + if (Object.keys(this._interfaceInfos).length === 0) { + this._completeLoad(); + return; + } + + this._managerProxy.connect('notify::g-name-owner', () => { + if (this._managerProxy.g_name_owner) + this._onNameAppeared(); + else + this._onNameVanished(); + }); + + if (this._managerProxy.g_name_owner) + this._onNameAppeared().catch(logError); + } + + async _onNameAppeared() { + try { + const [objects] = await this._managerProxy.GetManagedObjectsAsync(); + + if (!objects) { + this._completeLoad(); + return; + } + + const objectPaths = Object.keys(objects); + await Promise.allSettled(objectPaths.flatMap(objectPath => { + const object = objects[objectPath]; + const interfaceNames = Object.getOwnPropertyNames(object); + return interfaceNames.map( + ifaceName => this._addInterface(objectPath, ifaceName)); + })); + } catch (error: any) { + logError(error, `could not get remote objects for service ${this._serviceName} path ${this._managerPath}`); + } finally { + this._completeLoad(); + } + } + + _onNameVanished() { + let objectPaths = Object.keys(this._objects); + for (let i = 0; i < objectPaths.length; i++) { + let objectPath = objectPaths[i]; + let object = this._objects[objectPath]; + + let interfaceNames = Object.keys(object); + for (let j = 0; j < interfaceNames.length; j++) { + let interfaceName = interfaceNames[j]; + + if (object[interfaceName]) + this._removeInterface(objectPath, interfaceName); + } + } + } + + _registerInterfaces(interfaces: string | any[]) { + for (let i = 0; i < interfaces.length; i++) { + let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]); + this._interfaceInfos[info.name] = info; + } + } + + + getProxiesForInterface(interfaceName: string) { + let proxyList = this._interfaces[interfaceName]; + + if (!proxyList) + return []; + + return proxyList; + } +} +Signals.addSignalMethods(ObjectManager.prototype); diff --git a/src/model/OptionData.ts b/src/model/OptionData.ts new file mode 100644 index 0000000..6bc6dc2 --- /dev/null +++ b/src/model/OptionData.ts @@ -0,0 +1,109 @@ + +export class OptionData { + tooltip; + description; + static map: Map = new Map(); + + constructor(description: string, tooltip: string) { + this.tooltip = tooltip; + this.description = description; + } + + static add(name: string, description: string, tooltip: string) { + OptionData.map.set(name, new OptionData(description, tooltip)); + } + + static description(name: string) { + return OptionData.map.get(name)?.description; + } + + static tooltip(name: string) { + return OptionData.map.get(name)?.tooltip; + } +} + +OptionData.add('use-gpu','Use GPU in Realm', + +`If enabled the render node device /dev/dri/renderD128 will be mounted into the realm container. + +If privileged device /dev/dri/card0 is also needed set +additional variable in realm configuration file: + + use-gpu-card0 = true +`); + +OptionData.add('use-wayland', 'Use Wayland in Realm', + +`If enabled access to Wayland display will be permitted in realm by adding wayland socket to realm. + + /run/user/1000/wayland-0 + +`); + +OptionData.add('use-x11', 'Use X11 in Realm', + +`If enabled access to X11 server will be added by mounting directory X11 directory into realm. + + /tmp/.X11-unix + +`); + +OptionData.add('use-sound', 'Use sound in Realm', + +`If enabled allows use of sound inside of realm. The following items will be added: + + /dev/snd + /dev/shm + /run/user/1000/pulse + +`); + +OptionData.add('use-shared-dir', 'Mount /Shared directory in Realm', + +`If enabled the shared directory will be mounted as /Shared in home directory of realm. + +This directory is shared between all realms with this option enabled and is an easy way to move files between realms. + +`); + +OptionData.add('use-network', 'Realm has network access', + `If enabled the realm will have access to the network.`); + +OptionData.add('use-kvm', 'Use KVM (/dev/kvm) in Realm', + `If enabled device /dev/kvm will be added to realm`); + + +OptionData.add('use-ephemeral-home', 'Use ephemeral tmpfs mount for home directory', + +`If enabled the home directory of realm will be set up in ephemeral mode. + +The ephemeral home directory is set up with the following steps: + + 1. Home directory is mounted as tmpfs filesystem + 2. Any files in /realms/skel are copied into home directory + 3. Any files in /realms/realm-$name/skel are copied into home directory. + 4. Any directories listed in config file variable ephemeral_persistent_dirs + are bind mounted from /realms/realm-$name/home into ephemeral + home directory. + +`); + +OptionData.add('overlay', 'Type of rootfs overlay Realm is configured to use.', +`Overlay +Type of rootfs overlay realm is configured to use. + None Don't use a rootfs overlay + TmpFS Use a rootfs overlay stored on tmpfs + Storage Use a rootfs overlay stored on disk in storage partition +`); + +OptionData.add('realmfs', 'Root filesystem image to use for Realm.', +`RealmFS +Root filesystem image to use for realm.`); + +OptionData.add('colorscheme', 'Terminal Color Scheme', +`Terminal Color Scheme +Choose a color scheme to use in the terminals in this realm.`); + +OptionData.add('window-label-color', 'Window Label Color', +`Window Label Color +Set a color to be used when a label is drawn on the window titlebar indicating which realm the application is running in.`); diff --git a/src/model/Realm.ts b/src/model/Realm.ts new file mode 100644 index 0000000..69bb813 --- /dev/null +++ b/src/model/Realm.ts @@ -0,0 +1,129 @@ +import GObject from 'gi://GObject'; +import Gio from 'gi://Gio'; + +import {RealmFS} from './RealmFS.js'; +import {RealmConfig} from './RealmConfig.js'; +import {LabelColorManager} from './LabelColors.js'; +import { RGBA } from 'gi-types/gdk4.js'; + +export const RunStatus = { + STOPPED: 0, + STARTING: 1, + RUNNING: 2, + CURRENT: 3, + STOPPING: 4, +}; + +export class Realm extends GObject.Object { + private _name!: string; + private _description!: string; + private _pidns!: number; + private _run_status!: number; + private _is_system_realm!: boolean; + private _realmfs!: RealmFS | null; + private _labelColors: LabelColorManager; + + static { + GObject.registerClass({ + GTypeName: 'Realm', + Properties: { + 'name': GObject.ParamSpec.string('name', '', '', GObject.ParamFlags.READWRITE, ''), + 'description': GObject.ParamSpec.string('description', '', '', GObject.ParamFlags.READWRITE, ''), + 'pidns': GObject.ParamSpec.uint64('pidns', '', '', GObject.ParamFlags.READWRITE, + 0, Number.MAX_SAFE_INTEGER, 0), + 'run-status': GObject.ParamSpec.uint('run-status', '', '', GObject.ParamFlags.READWRITE, + 0, 4, 0), + 'is-system-realm': GObject.ParamSpec.boolean('is-system-realm', '', '', GObject.ParamFlags.READWRITE, false), + 'realmfs': GObject.ParamSpec.object('realmfs', '', '', GObject.ParamFlags.READWRITE, RealmFS), + }, + Signals: { 'changed': {}}, + }, this); + } + + _proxy: Gio.DBusProxy; + + config = new RealmConfig(); + + + constructor(proxy: Gio.DBusProxy, labelColors: LabelColorManager) { + super(); + this._proxy = proxy; + this._labelColors = labelColors; + this._proxy.connect('g-properties-changed', (_proxy, _changed, _invalidated) => { + this._sync(); + }); + this._sync(); + } + + get realmfs(): RealmFS | null { + return this._realmfs; + } + + set realmfs(value: RealmFS | null) { + if (this.realmfs === value) { + return; + } + this._realmfs = value; + this.emit('changed'); + } + + _sync() { + this._name = this._proxy.Name; + this._description = this._proxy.Description; + this._pidns = this._proxy.PidNS; + this._run_status = this._proxy.RunStatus; + this._is_system_realm = this._proxy.IsSystemRealm; + this.emit('changed'); + } + + get name() { + return this._name; + } + get description() { + return this._description; + } + + get pidns() { + return this._pidns; + } + + get run_status() { + return this._run_status; + } + + get is_system_realm() { + return this._is_system_realm; + } + + is_running() { + return this.run_status === RunStatus.RUNNING || this.run_status === RunStatus.CURRENT; + } + + is_current() { + return this.run_status === RunStatus.CURRENT + } + + getLabelColor() { + return this._labelColors.lookupRealmColor(this); + } + + setLabelColor(color: RGBA) { + this._labelColors.updateRealmColor(this, color); + } + + + realmfs_index() { + return this._proxy.RealmFS + } + + set_global_config(config: { [s: string]: string; }) { + this.config.set_global_config(config); + } + + async load_config() { + const result = await this._proxy.GetConfigAsync(); + this.config.set_config(result[0]); + this.emit('changed'); + } +} + diff --git a/src/model/RealmConfig.ts b/src/model/RealmConfig.ts new file mode 100644 index 0000000..382e777 --- /dev/null +++ b/src/model/RealmConfig.ts @@ -0,0 +1,116 @@ + +import {OptionData} from './OptionData.js'; + +export class BoolOptionData { + static ALL_OPTIONS = [ + 'use-gpu', + 'use-wayland', + 'use-x11', + 'use-sound', + 'use-network', + 'use-kvm', + 'use-shared-dir', + 'use-ephemeral-home', + ] + + name; + description; + tooltip; + + constructor(name: string) { + this.name = name; + this.description = OptionData.description(name) ?? name; + this.tooltip = OptionData.tooltip(name) ?? ""; + } + + static allOptions(): BoolOptionData[] { + let options: BoolOptionData[] = []; + BoolOptionData.ALL_OPTIONS.forEach(name => { + options.push(new BoolOptionData(name)); + + }) + return options; + } +} + +export class ConfigOption { + name; + value; + defaultValue; + description; + tooltip; + + constructor(name: string, value: string, defaultValue: string, description: string, tooltip: string) { + this.name = name; + this.value = value; + this.defaultValue = defaultValue; + this.description = description; + this.tooltip = tooltip; + } +} + +export class RealmConfig { + _configVars: { [s: string]: string; } = {}; + _globalConfig: { [s: string]: string; } = {}; + + set_config(config: { [s: string]: string; }) { + this._configVars = config; + } + + set_global_config(globalConfig: { [s: string]: string; }) { + this._globalConfig = globalConfig; + } + + get_var(name: string) { + let value = this._configVars[name]; + if (value && value.length > 0) { + return value; + } + value = this._globalConfig[name]; + if (value && value.length > 0) { + return value; + } + return null; + } + + get_bool(name: string): boolean { + return this.get_var(name) === 'true'; + } + + get_colorscheme() { + return this.get_var('terminal-scheme') ?? 'default-dark'; + } + + get_realmfs() { + return this.get_var('realmfs') ?? 'base'; + } + + static capitalize(term: string) { + const acronyms = ["gpu", "kvm"]; + if (acronyms.find(s => term === s)) { + return term.toUpperCase(); + } else { + return term.charAt(0).toUpperCase() + term.slice(1); + } + } + + static option_label(key: string) { + return key.substring(4) + .split('-') + .map(RealmConfig.capitalize) + .join(''); + } + + is_enabled_bool_option(name: string, value: string, isDefault: boolean) { + const default_val = this._globalConfig[name]; + return name.startsWith("use-") && value === "true" && (value === default_val) === isDefault; + } + + enabled_bool_option_labels(isDefault: boolean) { + return Object.entries(this._configVars) + .filter(([k,v]) => this.is_enabled_bool_option(k, v, isDefault)) + .map(([k,]) => RealmConfig.option_label(k)) + .sort(); + } +} + diff --git a/src/model/RealmFS.ts b/src/model/RealmFS.ts new file mode 100644 index 0000000..f0e5532 --- /dev/null +++ b/src/model/RealmFS.ts @@ -0,0 +1,93 @@ +import GObject from 'gi://GObject'; +import Gio from 'gi://Gio'; + +const OBJECT_PREFIX = "/com/subgraph/Realms2/RealmFS"; + +export class RealmFS extends GObject.Object { + private _name!: string; + private _in_use!: boolean; + private _activated!: boolean; + private _mountpoint!: string; + private _path!: string; + private _free_space!: number; + private _allocated_space!: number; + + static { + GObject.registerClass({ + GTypeName: 'RealmFS', + Properties: { + 'name': GObject.ParamSpec.string('name', '', '', GObject.ParamFlags.READWRITE, ''), + 'in-use': GObject.ParamSpec.boolean('in-use', '', '', GObject.ParamFlags.READWRITE, false), + 'activated': GObject.ParamSpec.boolean('activated', '', '', GObject.ParamFlags.READWRITE, false), + 'mountpoint': GObject.ParamSpec.string('mountpoint', '', '', GObject.ParamFlags.READWRITE, ''), + 'path': GObject.ParamSpec.string('path', '', '', GObject.ParamFlags.READWRITE, ''), + 'free-space': GObject.ParamSpec.uint64('free-space', '', '', GObject.ParamFlags.READWRITE, + 0, Number.MAX_SAFE_INTEGER, 0), + 'allocated-space': GObject.ParamSpec.uint64('allocated-space', '', '', GObject.ParamFlags.READWRITE, + 0, Number.MAX_SAFE_INTEGER, 0), + }, + }, this); + } + + _proxy: Gio.DBusProxy; + + constructor(proxy: Gio.DBusProxy) { + super(); + this._proxy = proxy; + this._proxy.connect('g-properties-changed', (_proxy, _changed, _invalidated) => { + this._sync(); + }); + this._sync(); + } + + index() { + let path = this._proxy.get_object_path(); + if (path.startsWith(OBJECT_PREFIX)) { + const tail = path.substring(OBJECT_PREFIX.length); + let index = Number.parseInt(tail); + if (!Number.isNaN(index)) { + return index; + } + } + return -1; + } + + get name() { + return this._name; + } + + get in_use() { + return this._in_use; + } + + get activated() { + return this._activated; + } + + get mountpoint() { + return this._mountpoint; + } + + get path() { + return this._path; + } + + get free_space() { + return this._free_space; + } + + get allocated_space() { + return this._allocated_space; + } + + _sync() { + this._name = this._proxy.Name; + this._in_use = this._proxy.InUse; + this._activated = this._proxy.Activated; + this._mountpoint = this._proxy.Mountpoint; + this._path = this._proxy.Path; + this._free_space = this._proxy.FreeSpace; + this._allocated_space = this._proxy.AllocatedSpace; + } +} + diff --git a/src/model/RealmManager.ts b/src/model/RealmManager.ts new file mode 100644 index 0000000..5a33e51 --- /dev/null +++ b/src/model/RealmManager.ts @@ -0,0 +1,171 @@ +import Gio from 'gi://Gio'; + +import {ObjectManager} from './ObjectManager.js'; +import {loadInterfaceXML} from './Utils.js' +import {Realm} from './Realm.js'; +import {RealmFS} from './RealmFS.js'; +import {LabelColorManager} from './LabelColors.js'; + +import type {SignalMethods} from 'gjs'; + +const Signals = imports.signals; + +const RealmIface = loadInterfaceXML("com.subgraph.realms.Realm"); +const RealmFSIface = loadInterfaceXML("com.subgraph.realms.RealmFS"); + +const BUS_NAME = 'com.subgraph.Realms2'; +const OBJECT_PATH = '/com/subgraph/Realms2'; +const ManagerInterface = loadInterfaceXML("com.subgraph.realms.Manager2"); +const ManagerProxy = Gio.DBusProxy.makeProxyWrapper(ManagerInterface); + + + +export interface RealmManager extends SignalMethods {}; + +export class RealmManager { + + _globalConfig: { [s: string]: string; } = {}; + _realms: { [s: string]: Realm; } = {}; + _realmfs: { [s: string]: RealmFS; } = {}; + + static INSTANCE = new RealmManager(); + private _objectManager: ObjectManager; + private _labelColors: LabelColorManager; + private _proxy: Gio.DBusProxy; + + + static instance(): RealmManager { + return RealmManager.INSTANCE; + } + + constructor() { + this._realmfs = {}; + + this._objectManager = new ObjectManager({ + connection: Gio.DBus.system, + name: 'com.subgraph.Realms2', + objectPath: '/com/subgraph/Realms2', + knownInterfaces: [RealmIface, RealmFSIface], + onLoaded: this._onLoaded.bind(this), + }); + this._proxy = new ManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH, + (_proxy: any, error: any) => { + if(error) { + logError(error); + } else { + this._setGlobalConfig().catch(logError); + } + }); + + this._labelColors = new LabelColorManager(); + } + + + async _setGlobalConfig() { + let result = await this._proxy.GetGlobalConfigAsync(); + this._globalConfig = result[0]; + this._assignGlobalConfigToRealms(); + } + + async _onLoaded() { + let realms = this._objectManager.getProxiesForInterface('com.subgraph.realms.Realm'); + for (let i = 0; i < realms.length; i++) { + this._addRealm(realms[i]); + } + + let realmfs = this._objectManager.getProxiesForInterface('com.subgraph.realms.RealmFS'); + for (let i = 0; i < realmfs.length; i++) { + this._addRealmFS(realmfs[i]); + } + + + this._objectManager.connect('interface-added', (_objectManager, interfaceName, proxy) => { + if (interfaceName === 'com.subgraph.Realm') { + this._addRealm(proxy); + } else if (interfaceName === 'com.subgraph.RealmFS') { + this._addRealmFS(proxy); + } + }); + + this._objectManager.connect('interface-removed', (_objectManager, interfaceName, proxy) => { + if (interfaceName === 'com.subgraph.Realm') { + this._removeRealm(proxy); + } else if (interfaceName === 'com.subgraph.RealmFS') { + this._removeRealmFS(proxy); + } + }); + } + + async _addRealm(proxy: Gio.DBusProxy) { + let objectPath = proxy.get_object_path(); + let realm = new Realm(proxy, this._labelColors); + this._realms[objectPath] = realm; + this._findRealmFSForRealm(realm); + if (this._globalConfig) { + realm.set_global_config(this._globalConfig); + } + await realm.load_config(); + this.emit('realm-added', realm); + } + + _removeRealm(proxy: Gio.DBusProxy) { + let objectPath = proxy.get_object_path(); + if (this._realms[objectPath]?._proxy === proxy) { + let realm = this._realms[objectPath]; + delete this._realms[objectPath]; + this.emit('realm-removed', realm); + } + proxy.disconnectAll(); + } + + _addRealmFS(proxy: Gio.DBusProxy) { + let objectPath = proxy.get_object_path(); + let realmfs = new RealmFS(proxy); + this._realmfs[objectPath] = realmfs; + this._assignRealmFSToRealms(realmfs); + this.emit('realmfs-added', realmfs); + } + + _findRealmFSForRealm(realm: Realm) { + if (realm.realmfs_index() > 0) { + realm.realmfs = Object.values(this._realmfs) + .find(realmfs => realmfs.index() === realm.realmfs_index()) ?? null; + } + } + + realmfsList() { + return Object.values(this._realmfs); + } + + _assignRealmFSToRealms(realmfs: RealmFS) { + Object.values(this._realms).forEach(r => { + if (r.realmfs_index() > 0 && r.realmfs_index() === realmfs.index() && r.realmfs != realmfs) { + r.realmfs = realmfs; + } + }) ; + } + + _assignGlobalConfigToRealms() { + Object.values(this._realms).forEach(r => r.set_global_config(this._globalConfig)); + } + + _removeRealmFSFromRealms(realmfs: RealmFS) { + Object.values(this._realms).forEach(r => { + if (r.realmfs === realmfs) { + r.realmfs = null; + } + }); + } + + _removeRealmFS(proxy: Gio.DBusProxy) { + let objectPath = proxy.get_object_path(); + if (this._realmfs[objectPath]?._proxy === proxy) { + let realmfs = this._realmfs[objectPath]; + delete this._realmfs[objectPath]; + this._removeRealmFSFromRealms(realmfs); + this.emit('realmfs-removed', realmfs); + } + proxy.disconnectAll(); + } +} +Signals.addSignalMethods(RealmManager.prototype); diff --git a/src/model/Utils.ts b/src/model/Utils.ts new file mode 100644 index 0000000..186b81c --- /dev/null +++ b/src/model/Utils.ts @@ -0,0 +1,17 @@ +import Gio from 'gi://Gio'; + +export function loadInterfaceXML(iface: string): string | null { + + let uri = `resource:///com/subgraph/citadel/Realms/dbus-interfaces/${iface}.xml`; + let f = Gio.File.new_for_uri(uri); + + try { + let [_ok, bytes] = f.load_contents(null); + // @ts-ignore + return new TextDecoder().decode(bytes); + } catch (e) { + log(`Failed to load D-Bus interface ${iface}`); + } + + return null; +} diff --git a/subprojects/blueprint-compiler.wrap b/subprojects/blueprint-compiler.wrap new file mode 100644 index 0000000..decb0d0 --- /dev/null +++ b/subprojects/blueprint-compiler.wrap @@ -0,0 +1,9 @@ +[wrap-git] +directory = blueprint-compiler +url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git +revision = main +depth = 1 + +[provide] +program_names = blueprint-compiler + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d1a1cb9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + "strictNullChecks": true, + "noImplicitReturns": true, + "noImplicitAny": true, + "noUnusedParameters": true, + "experimentalDecorators": true, + "strict": true, + + "paths": { + "*": [ + "*", + "types/*", + "gi-types/*" + ] + }, + "target": "ES2018", + "baseUrl": ".", + "moduleResolution": "node", + "module": "ES2020", + "outDir": "js", + "lib": [ + "es2020" + ], + "skipLibCheck": true, + "typeRoots": [ + "types", + "gi-types", + ], + }, + "include": [ + "gi-types/gi.d.ts", + "types/ambient.d.ts", + "types/gjs.d.ts", + "src/**/*", + ], + "exclude": [ + "node_modules/@types/**", + ], +} diff --git a/types/ambient.d.ts b/types/ambient.d.ts new file mode 100644 index 0000000..141d177 --- /dev/null +++ b/types/ambient.d.ts @@ -0,0 +1,32 @@ +declare function _(id: string): string; +declare function print(args: string): void; +declare function log(obj: object, others?: object[]): void; +declare function log(msg: string, subsitutions?: any[]): void; + +declare const pkg: { + version: string; + name: string; +}; + +declare module console { + export function error(obj: object, others?: object[]): void; + export function error(msg: string, subsitutions?: any[]): void; +} + +declare class TextDecoder { + constructor(format: string); + decode(buffer: ArrayBuffer): string; +} +declare class TextEncoder { + constructor(); + encode(str: string): Uint8Array; +} + +declare interface String { + format(...replacements: string[]): string; + format(...replacements: number[]): string; +} +declare interface Number { + toFixed(digits: number): number; +} + diff --git a/types/gettext.d.ts b/types/gettext.d.ts new file mode 100644 index 0000000..ffde984 --- /dev/null +++ b/types/gettext.d.ts @@ -0,0 +1,35 @@ +export namespace Gettext { + export enum LocaleCategory { + CTYPE = 0, + NUMERIC = 1, + TIME = 2, + COLLATE = 3, + MONETARY = 4, + MESSAGES = 5, + ALL = 6, + } + + export function setlocale(category: LocaleCategory, locale: string | null): string | null; + export function textdomain(domainName: string): void; + export function bindtextdomain(domainName: string, dirName: string): void; + + export function gettext(msgid: string): string; + export function dgettext(domainName: string | null, msgid: string): string; + export function dcgettext(domainName: string | null, msgid: string, category: LocaleCategory): string; + + export function ngettext(msgid1: string, msgid2: string, n: number): string; + export function dngettext(domainName: string | null, msgid1: string, msgid2: string, n: number): string; + + export function pgettext(context: string | null, msgid: string): string; + export function dpgettext(domainName: string | null, context: string | null, msgid: string): string; + + export class GettextObject { + gettext(msgid: string): string; + ngettext(msgid1: string, msgid2: string, n: number): string; + pgettext(context: string | null, msgid: string): string; + } + + export function domain(domainName: string | null): GettextObject; +} + +export default Gettext; \ No newline at end of file diff --git a/types/gjs.d.ts b/types/gjs.d.ts new file mode 100644 index 0000000..1ff9405 --- /dev/null +++ b/types/gjs.d.ts @@ -0,0 +1,183 @@ +/** + * Type Definitions for Gjs (https://gjs.guide/) + * + * These type definitions are automatically generated, do not edit them by hand. + * If you found a bug fix it in ts-for-gir itself or create a bug report on https://github.com/gjsify/ts-for-gir + */ + +/* +import type GObject from '@girs/gobject-2.0'; +import type GLib from '@girs/glib-2.0'; + +import gettext from './gettext.js'; +import system from './system.js'; +import cairo from './cairo.js'; +*/ + + + + +/** + * You can use the `Signals.addSignalMethods` method to apply the `Signals` convenience methods to an `Object`. + * Generally, this is called on an object prototype, but may also be called on an object instance. + * You can use this Interface for this object or prototype to make the methods in typescript known + * @example + * ```ts + * const Signals = imports.signals; + * + * // Define an interface with the same name of your class to make the methods known + * interface Events extends Signals.Methods {} + * + * class Events {} + * Signals.addSignalMethods(Events.prototype); + * + * const events = new Events(); + * + * // Typescript will not complain here + * events.emit("test-signal", "test argument"); + * ``` + */ +export interface SignalMethods { + /** + * Connects a callback to a signal for an object. Pass the returned ID to + * `disconnect()` to remove the handler. + * + * If `callback` returns `true`, emission will stop and no other handlers will be + * invoked. + * + * > Warning: Unlike GObject signals, `this` within a signal callback will always + * > refer to the global object (ie. `globalThis`). + * + * @param sigName A signal name + * @param callback A callback function + * @returns A handler ID + */ + connect(sigName: string, callback: (self: any, ...args: any[]) => void): number; + /** + * Emits a signal for an object. Emission stops if a signal handler returns `true`. + * + * Unlike GObject signals, it is not necessary to declare signals or define their + * signature. Simply call `emit()` with whatever signal name you wish, with + * whatever arguments you wish. + * @param sigName A signal name + * @param args Any number of arguments, of any type + */ + emit(sigName: string, ...args: any[]): void; + /** + * Disconnects a handler for a signal. + * @param id The ID of the handler to be disconnected + */ + disconnect(id: number): void; + /** + * Disconnects all signal handlers for an object. + */ + disconnectAll(): void; + /** + * Checks if a handler ID is connected. + * @param id The ID of the handler to be disconnected + * @returns `true` if connected, or `false` if not + */ + signalHandlerIsConnected(id: number): boolean; +} + +declare namespace signals { + interface Methods { + /** + * Connects a callback to a signal for an object. Pass the returned ID to + * `disconnect()` to remove the handler. + * + * If `callback` returns `true`, emission will stop and no other handlers will be + * invoked. + * + * > Warning: Unlike GObject signals, `this` within a signal callback will always + * > refer to the global object (ie. `globalThis`). + * + * @param sigName A signal name + * @param callback A callback function + * @returns A handler ID + */ + connect(sigName: string, callback: (self: any, ...args: any[]) => void): number; + /** + * Emits a signal for an object. Emission stops if a signal handler returns `true`. + * + * Unlike GObject signals, it is not necessary to declare signals or define their + * signature. Simply call `emit()` with whatever signal name you wish, with + * whatever arguments you wish. + * @param sigName A signal name + * @param args Any number of arguments, of any type + */ + emit(sigName: string, ...args: any[]): void; + /** + * Disconnects a handler for a signal. + * @param id The ID of the handler to be disconnected + */ + disconnect(id: number): void; + /** + * Disconnects all signal handlers for an object. + */ + disconnectAll(): void; + /** + * Checks if a handler ID is connected. + * @param id The ID of the handler to be disconnected + * @returns `true` if connected, or `false` if not + */ + signalHandlerIsConnected(id: number): boolean; + } + export function addSignalMethods(proto: T): proto is T & Methods; +} + +declare global { + interface GjsGiImports { + // Will be extended by the import of more gir types + versions: { + [namespace: string]: string; + }; + } + + interface GjsImports { + gi: GjsGiImports; + signals: typeof signals; + searchPath: string[]; + } + + /** + * Run `pkg.initGettext()` before using this. + * Currently not implemented. + */ + const N_: undefined | ((x: string) => string); + + function print(...args: any[]): void; + function printerr(...args: any[]): void; + function log(obj: object, others?: object[]): void; + function log(msg: string, substitutions?: any[]): void; + function logError(exception: object, message?: any): void; + function logError(message?: any): void; + + interface BooleanConstructor { + $gtype: GObject.GType; + } + + interface NumberConstructor { + $gtype: GObject.GType; + } + + interface StringConstructor { + $gtype: GObject.GType; + } + + interface StringConstructor { + $gtype: GObject.GType; + } + + interface ObjectConstructor { + $gtype: GObject.GType; + } + + const imports: GjsImports; + + const ARGV: string[]; +} + +declare const _imports: GjsImports; +export default _imports; +export { _imports as imports }; diff --git a/types/gjs.js b/types/gjs.js new file mode 100644 index 0000000..1a74967 --- /dev/null +++ b/types/gjs.js @@ -0,0 +1,6 @@ +const imports = globalThis.imports || {}; + +export { imports } +export default imports; + +