Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
<button id="btn-mode-editor" class="mode-button active">Editor</button>
<button id="btn-mode-serial" class="mode-button">Serial</button>
<div class="spacer"></div>
<button class="purple-button btn-settings">Settings<i class="fa-solid fa-gear"></i></button>
<button class="purple-button btn-info" disabled>Info<i class="fa-solid fa-info-circle"></i></button>
</div>
</div>
Expand Down Expand Up @@ -153,6 +154,14 @@
<button class="purple-button cancel-button">Cancel</button>
</div>
</div>
<div class="popup-modal shadow settings-dialog closable" data-popup-modal="settings">
<i class="fa-solid fa-2x fa-xmark text-white bg-primary p-3 popup-modal__close"></i>
<div id="settings-content"></div>
<div class="buttons centered">
<button class="purple-button ok-button">Save</button>
<button class="purple-button cancel-button">Cancel</button>
</div>
</div>
<div class="popup-modal shadow file-dialog closable" data-popup-modal="folder-select">
<span id="current-path"></span>
<i class="fa-solid fa-2x fa-xmark text-white bg-primary p-3 popup-modal__close"></i>
Expand Down
125 changes: 125 additions & 0 deletions js/common/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import {GenericModal} from './dialogs.js';

class SettingsDialog extends GenericModal {
constructor(modalId, settingsData) {
super(modalId);
this._settingsData = settingsData;
this._settings = {}
}

async open(settings) {
let p = super.open();
const cancelButton = this._currentModal.querySelector("button.cancel-button");
this._addDialogElement('cancelButton', cancelButton, 'click', this._closeModal);
const okButton = this._currentModal.querySelector("button.ok-button");
this._addDialogElement('okButton', okButton, 'click', this._handleOkButton);

const contentDiv = this._currentModal.querySelector("#settings-content");
contentDiv.innerHTML = '';

for (const setting of this._settingsData) {
const label = document.createElement('label');
label.textContent = setting.label;
if (setting.icon) {
const icon = document.createElement('i');
icon.className = `fa-solid fa-${setting.icon} setting-item-icon`;
label.prepend(icon);
}
label.htmlFor = `setting-${setting.key}`;
contentDiv.appendChild(label);

const control = await this._createControl(setting);
control.value = settings[setting.key];
contentDiv.appendChild(control);
}

return p;
}

async _handleOkButton() {
let settings = {}
for (const setting of this._settingsData) {
const control = this._currentModal.querySelector(`#setting-${setting.key}`);
settings[setting.key] = control.value;
}
this._returnValue(settings);
}

async _createControl(settingData) {
// Return the created control
let control;
if (settingData.type === 'select') {
control = document.createElement('select');
for (const optionValue of settingData.options) {
const option = document.createElement('option');
option.value = optionValue;
option.textContent = optionValue.charAt(0).toUpperCase() + optionValue.slice(1);
control.appendChild(option);
}
}
control.id = `setting-${settingData.key}`;

// this will also call this._addDialogElement to add event listeners as needed
this._addDialogElement(`setting-${settingData.key}`, control);
return control;
}
}

class Settings {
// This is a class that handles loading/saving settings as well as providing a settings dialog
constructor() {
// This will hold the layout/save data for the settings
this._settingsData = [
{ key: 'theme', type: 'select', label: 'Editor Theme', icon: 'palette', options: ['dark', 'light'], default: 'dark' }
];
this._settings = {};
this._loadSettings();

this._settingsDialog = new SettingsDialog('settings', this._settingsData);
}

_loadSettings() {
// Load all saved settings or defaults
for (const setting of this._settingsData) {
this._settings[setting.key] = this._loadSetting(setting.key, setting.default);
}
}

_saveSettings() {
// Save all settings
for (const key in this._settings) {
this._saveSetting(key, this._settings[key]);
}
}

_loadSetting(setting, defaultValue) {
let value = JSON.parse(window.localStorage.getItem(setting));
if (value == null) {
return defaultValue;
}

return value;
}

_saveSetting(setting, value) {
window.localStorage.setItem(setting, JSON.stringify(value));
}

getSetting(key) {
return this._settings[key];
}

async showDialog() {
this._settings = await this._settingsDialog.open(this._settings);
if (this._settings) {
this._saveSettings();
return true;
}
return false;
}
}


export {
Settings
};
64 changes: 57 additions & 7 deletions js/script.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { basicSetup } from "codemirror";
import { EditorView, keymap } from "@codemirror/view";
import { EditorState } from "@codemirror/state";
import {indentWithTab} from "@codemirror/commands"
import { indentWithTab } from "@codemirror/commands"
import { python } from "@codemirror/lang-python";
import { syntaxHighlighting, indentUnit } from "@codemirror/language";
import { classHighlighter } from "@lezer/highlight";
Expand All @@ -17,9 +17,10 @@ import { WebWorkflow } from './workflows/web.js';
import { isValidBackend, getBackendWorkflow, getWorkflowBackendName } from './workflows/workflow.js';
import { ButtonValueDialog, MessageModal } from './common/dialogs.js';
import { isLocal, switchUrl, getUrlParam } from './common/utilities.js';
import { Settings } from './common/settings.js';
import { CONNTYPE } from './constants.js';
import './layout.js'; // load for side effects only
import {setupPlotterChart} from "./common/plotter.js";
import { setupPlotterChart } from "./common/plotter.js";
import { mainContent, showSerial } from './layout.js';

// Instantiate workflows
Expand All @@ -31,6 +32,7 @@ workflows[CONNTYPE.Web] = new WebWorkflow();
let workflow = null;
let unchanged = 0;
let connectionPromise = null;
let debugMessageAnsi = null;

const btnRestart = document.querySelector('.btn-restart');
const btnHalt = document.querySelector('.btn-halt');
Expand All @@ -43,13 +45,15 @@ const btnSave = document.querySelectorAll('.btn-save');
const btnSaveAs = document.querySelectorAll('.btn-save-as');
const btnSaveRun = document.querySelectorAll('.btn-save-run');
const btnInfo = document.querySelector('.btn-info');
const btnSettings = document.querySelector('.btn-settings');
const terminalTitle = document.getElementById('terminal-title');
const serialPlotter = document.getElementById('plotter');

const messageDialog = new MessageModal("message");
const connectionType = new ButtonValueDialog("connection-type");
const settings = new Settings();

const editorTheme = EditorView.theme({}, {dark: true});
const editorTheme = EditorView.theme({}, {dark: getCssVar('editor-theme-dark').trim() === '1'});

document.addEventListener('DOMContentLoaded', function() {
document.getElementById('mobile-menu-button').addEventListener('click', handleMobileToggle);
Expand Down Expand Up @@ -168,6 +172,12 @@ btnInfo.addEventListener('click', async function(e) {
}
});

btnSettings.addEventListener('click', async function(e) {
if (await settings.showDialog()) {
applySettings();
}
});

// Basic functions used for buttons and hotkeys
async function openFile() {
if (await checkConnected()) {
Expand Down Expand Up @@ -420,8 +430,12 @@ async function showMessage(message) {
}

async function debugLog(msg) {
if (debugMessageAnsi === null) {
const colorCode = getCssVar('debug-message-color').trim();
debugMessageAnsi = `\x1b[38;2;${parseInt(colorCode.slice(1,3),16)};${parseInt(colorCode.slice(3,5),16)};${parseInt(colorCode.slice(5,7),16)}m`;
}
state.terminal.writeln(''); // get a fresh line without any prior content (a '>>>' prompt might be there without newline)
state.terminal.writeln(`\x1b[93m${msg}\x1b[0m`);
state.terminal.writeln(`${debugMessageAnsi}${msg}\x1b[0m`);
}

function updateUIConnected(isConnected) {
Expand Down Expand Up @@ -547,12 +561,16 @@ editor = new EditorView({
parent: document.querySelector('#editor')
});

function getCssVar(varName) {
return window.getComputedStyle(document.body).getPropertyValue("--" + varName);
}

async function setupXterm() {
state.terminal = new Terminal({
theme: {
background: '#333',
foreground: '#ddd',
cursor: '#ddd',
background: getCssVar('background-color'),
foreground: getCssVar('terminal-text-color'),
cursor: getCssVar('terminal-text-color'),
}
});

Expand Down Expand Up @@ -585,8 +603,40 @@ function loadParameterizedContent() {
return documentState;
}

function applySettings() {
// ----- Themes -----
const theme = settings.getSetting('theme');
// Remove all theme-[option] classes from body
document.body.classList.forEach((className) => {
if (className.startsWith('theme-')) {
document.body.classList.remove(className);
}
});

// Add the selected theme class
document.body.classList.add(`theme-${theme}`);

// Apply to EditorView.theme dark parameter
editor.darkTheme = getCssVar('editor-theme-dark').trim() === '1';

// Apply to xterm
state.terminal.options.theme = {
background: getCssVar('background-color'),
foreground: getCssVar('terminal-text-color'),
cursor: getCssVar('terminal-text-color'),
};

debugMessageAnsi = null;

// Note: Debug Message color is applied on next debug message or reload
// I'm not sure how to go through the xterm's existing content and change escape sequences
// Changing the CSS style reverts to the old style on terminal update/redraw

}

document.addEventListener('DOMContentLoaded', async (event) => {
await setupXterm();
applySettings();
btnConnect.forEach((element) => {
element.addEventListener('click', async function(e) {
e.preventDefault();
Expand Down
25 changes: 13 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
"chart.js": "^4.5.1",
"codemirror": "^6.0.2",
"file-saver": "^2.0.5",
"focus-trap": "^7.7.0",
"focus-trap": "^7.7.1",
"idb-keyval": "^6.2.2",
"jszip": "^3.10.1"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "^4.54.0"
"@rollup/rollup-linux-x64-gnu": "^4.55.1"
}
}
Loading