Skip to content

Commit

Permalink
feat: add settings side bar
Browse files Browse the repository at this point in the history
  • Loading branch information
Belar committed Jan 4, 2025
1 parent cda3855 commit 8fb1cef
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 248 deletions.
30 changes: 25 additions & 5 deletions src/base/components/controls.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
<div class="controls">
<button id="reload-tab" title="Reload active tab">
<sl-button-group class="controls">
<sl-button id="toggle-settings" size="small" title="Toggle settings">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#000000"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-settings"
>
<path
d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"
/>
<circle cx="12" cy="12" r="3" />
</svg>
<sl-visually-hidden>Toggle settings</sl-visually-hidden>
</sl-button>
<sl-button id="reload-tab" size="small" title="Reload active tab">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -16,6 +36,6 @@
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
<path d="M21 3v5h-5" />
</svg>
<span class="visually-hidden">Reload active tab</span>
</button>
</div>
<sl-visually-hidden>Reload active tab</sl-visually-hidden>
</sl-button>
</sl-button-group>
67 changes: 22 additions & 45 deletions src/base/components/settings.html
Original file line number Diff line number Diff line change
@@ -1,49 +1,26 @@
<div id="settings" class="dropdown-modal">
<div class="settings-section">
<div class="settings-section-header">
<h2>Instance</h2>
</div>
<div class="settings-section-content">
<input
style="width: -webkit-fill-available"
<sl-drawer id="settings" class="settings" placement="start" label="Settings">
<div>
<form id="instance-form" class="inline">
<sl-input
id="instance-field"
label="Instance"
type="url"
pattern="https?://.*"
placeholder="https://design.penpot.app/"
value=""
/>
<input id="instance-save" type="button" value="Save" />
</div>
size="small"
></sl-input>
<sl-button id="instance-save" type="submit" size="small">Save</sl-button>
</form>

<sl-select id="theme-select" label="Theme" size="small">
<sl-option value="light">Light</sl-option>
<sl-option value="dark">Dark</sl-option>
<sl-option value="system">System</sl-option>
<sl-option value="tab">Penpot</sl-option>
</sl-select>
</div>
<div class="settings-section">
<div class="settings-section-header">
<h2>Theme</h2>
</div>
<div id="theme" class="settings-section-content">
<select name="theme" id="theme-select">
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="system">System</option>
<option value="tab">Penpot</option>
</select>
</div>
</div>
<div class="settings-section">
<div class="settings-section-header">
<h2>Help</h2>
</div>
<div class="settings-section-content">
<div
style="
display: flex;
gap: 12px;
justify-content: space-evenly;
flex: auto;
"
>
<a href="#" onclick="window.api.send('OpenHelp')">Help</a>
<a href="#" onclick="window.api.send('OpenOffline')">Selfhost</a>
</div>
</div>
</div>
</div>

<sl-button-group class="footer" label="Help Center">
<sl-button id="open-docs" href="#" size="small">Documentation</sl-button>
<sl-button id="open-selfhost" href="#" size="small">Selfhost</sl-button>
</sl-button-group>
</sl-drawer>
2 changes: 1 addition & 1 deletion src/base/components/tabs.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
width: calc(100% - var(--navBarWF));
filter: var(--theme-filter, none);

margin-left: 2.25rem;
margin-left: 4rem;
}
.tab {
-webkit-app-region: no-drag;
Expand Down
30 changes: 0 additions & 30 deletions src/base/components/titlebar.html
Original file line number Diff line number Diff line change
@@ -1,34 +1,4 @@
<div class="titlebar">
<!-- Controls -->
<sl-tooltip content="Settings" style="--sl-tooltip-arrow-size: 0">
<button id="toggle-settings">
<?xml version="1.0" encoding="UTF-8"?><svg
width="24px"
height="24px"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
color="#000000"
>
<path
d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
stroke="#000000"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M19.6224 10.3954L18.5247 7.7448L20 6L18 4L16.2647 5.48295L13.5578 4.36974L12.9353 2H10.981L10.3491 4.40113L7.70441 5.51596L6 4L4 6L5.45337 7.78885L4.3725 10.4463L2 11V13L4.40111 13.6555L5.51575 16.2997L4 18L6 20L7.79116 18.5403L10.397 19.6123L11 22H13L13.6045 19.6132L16.2551 18.5155C16.6969 18.8313 18 20 18 20L20 18L18.5159 16.2494L19.6139 13.598L21.9999 12.9772L22 11L19.6224 10.3954Z"
stroke="#000000"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
</button>
</sl-tooltip>

<!-- Titlebar Buttons -->
<div class="linux-titlebar">
<button onclick="window.api.send('MinimizeWindow')">
Expand Down
7 changes: 5 additions & 2 deletions src/base/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<html>
<head>
<title>Penpot Desktop</title>
<link rel="stylesheet" href="./styles/index.css" />
<link
rel="stylesheet"
href="../../node_modules/@shoelace-style/shoelace/cdn/themes/light.css"
/>
<link
rel="stylesheet"
href="../../node_modules/@shoelace-style/shoelace/cdn/themes/dark.css"
onload="document.documentElement.classList.add('sl-theme-dark')"
/>
<link rel="stylesheet" href="./styles/index.css" />
<script src="./scripts/main.js" type="module"></script>
</head>
<body>
Expand Down
42 changes: 23 additions & 19 deletions src/base/scripts/instance.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { getIncludedElement } from "./dom.js";
import { openTab, resetTabs, setDefaultTab } from "./electron-tabs.js";
import {
SlButton,
SlInput,
} from "../../../node_modules/@shoelace-style/shoelace/cdn/shoelace.js";

const INSTANCE_STORE_KEY = "Instance";
const INSTANCE_EVENTS = Object.freeze({
Expand All @@ -16,21 +20,16 @@ export async function initInstance() {
}

async function prepareSaveButton() {
const { instanceSaveButton } = await getInstanceSettingsForm();
const { instanceForm } = await getInstanceSettingsForm();

instanceSaveButton?.addEventListener("click", (event) => {
const target = event.target;
const element = target instanceof HTMLElement ? target : null;
saveInstance(element);
instanceForm?.addEventListener("submit", (event) => {
event.preventDefault();
saveInstance();
});
}

/**
* @param {HTMLElement | null} trigger
*/
async function saveInstance(trigger) {
const isInputButton = trigger instanceof HTMLInputElement;
const { instanceField } = await getInstanceSettingsForm();
async function saveInstance() {
const { instanceField, instanceSaveButton } = await getInstanceSettingsForm();
const instance = instanceField?.value;

if (instance) {
Expand All @@ -50,12 +49,12 @@ async function saveInstance(trigger) {

resetTabs();

if (isInputButton) {
trigger.style.backgroundColor = "#00ff89";
trigger.setAttribute("value", "Saved!");
if (instanceSaveButton) {
instanceSaveButton.setAttribute("variant", "success");
instanceSaveButton.innerText = "Saved!";
setTimeout(() => {
trigger.style.backgroundColor = "#575151";
trigger.setAttribute("value", "Save");
instanceSaveButton.removeAttribute("variant");
instanceSaveButton.innerText = "Save";
}, 1200);
}
}
Expand All @@ -77,16 +76,21 @@ async function registerSavedInstance() {
}

async function getInstanceSettingsForm() {
const instanceForm = await getIncludedElement(
"#instance-form",
"#include-settings",
HTMLFormElement,
);
const instanceField = await getIncludedElement(
"#instance-field",
"#include-settings",
HTMLInputElement,
SlInput,
);
const instanceSaveButton = await getIncludedElement(
"#instance-save",
"#include-settings",
HTMLInputElement,
SlButton,
);

return { instanceField, instanceSaveButton };
return { instanceForm, instanceField, instanceSaveButton };
}
2 changes: 2 additions & 0 deletions src/base/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "../../../node_modules/electron-tabs/dist/electron-tabs.js";

import { initTabs } from "./electron-tabs.js";
import { initInstance } from "./instance.js";
import { initSettings } from "./settings.js";
import { initTheme } from "./theme.js";
import { initToggles } from "./toggles.js";

Expand All @@ -11,4 +12,5 @@ window.addEventListener("DOMContentLoaded", () => {
initInstance();
initTheme();
initToggles();
initSettings();
});
51 changes: 51 additions & 0 deletions src/base/scripts/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
SlButton,
SlDrawer,
} from "../../../node_modules/@shoelace-style/shoelace/cdn/shoelace.js";
import { getIncludedElement } from "./dom.js";

export async function initSettings() {
const { toggleSettingsButton, openDocsButton, openSelfhostButton } =
await getTriggers();

toggleSettingsButton?.addEventListener("click", () => toggleSettings());
openDocsButton?.addEventListener("click", () => window.api.send("OpenHelp"));
openSelfhostButton?.addEventListener("click", () =>
window.api.send("OpenOffline"),
);
}

async function toggleSettings() {
const settingsDrawer = await getIncludedElement(
"#settings",
"#include-settings",
SlDrawer,
);

if (settingsDrawer?.open) {
settingsDrawer?.hide();
return;
}

settingsDrawer?.show();
}

async function getTriggers() {
const toggleSettingsButton = await getIncludedElement(
"#toggle-settings",
"#include-controls",
SlButton,
);
const openDocsButton = await getIncludedElement(
"#open-docs",
"#include-settings",
SlButton,
);
const openSelfhostButton = await getIncludedElement(
"#open-selfhost",
"#include-settings",
SlButton,
);

return { toggleSettingsButton, openDocsButton, openSelfhostButton };
}
42 changes: 38 additions & 4 deletions src/base/scripts/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* @typedef {import("electron").IpcMessageEvent} IpcMessageEvent
*/

import { SlSelect } from "../../../node_modules/@shoelace-style/shoelace/cdn/shoelace.js";
import { getIncludedElement } from "./dom.js";
import { requestTabTheme } from "./electron-tabs.js";

Expand All @@ -12,6 +13,10 @@ export const THEME_TAB_EVENTS = Object.freeze({
REQUEST_UPDATE: "theme-request-update",
UPDATE: "theme-update",
});
const THEME_MEDIA = Object.freeze({
LIGHT: "(prefers-color-scheme: light)",
DARK: "(prefers-color-scheme: dark)",
});

/** @type {ThemeSetting | null} */
let currentThemeSetting = null;
Expand All @@ -26,6 +31,35 @@ export function initTheme() {
}

prepareForm(currentThemeSetting);
syncThemeClass();
}

function syncThemeClass() {
/**
* @function
* @param {MediaQueryListEvent} arg0
*/
const mediaMatchListener = ({ matches, media }) => {
if (!matches) {
return;
}

if (media === THEME_MEDIA.LIGHT) {
document.documentElement.classList.remove("sl-theme-dark");
document.documentElement.classList.add("sl-theme-light");
return;
}

if (media === THEME_MEDIA.DARK) {
document.documentElement.classList.remove("sl-theme-light");
document.documentElement.classList.add("sl-theme-dark");
}
};

Object.values(THEME_MEDIA).forEach((media) => {
const match = matchMedia(media);
match.addEventListener("change", mediaMatchListener);
});
}

/**
Expand All @@ -35,12 +69,12 @@ async function prepareForm(themeSetting) {
const { themeSelect } = await getThemeSettingsForm();

if (themeSelect && themeSetting) {
themeSelect.value = themeSetting;
themeSelect.setAttribute("value", themeSetting);
}

themeSelect?.addEventListener("change", (event) => {
themeSelect?.addEventListener("sl-change", (event) => {
const { target } = event;
const value = target instanceof HTMLSelectElement && target.value;
const value = target instanceof SlSelect && target.value;

if (isThemeSetting(value)) {
const isTabTheme = value === "tab";
Expand Down Expand Up @@ -74,7 +108,7 @@ async function getThemeSettingsForm() {
const themeSelect = await getIncludedElement(
"#theme-select",
"#include-settings",
HTMLSelectElement,
SlSelect,
);

return { themeSelect };
Expand Down
Loading

0 comments on commit 8fb1cef

Please sign in to comment.