Skip to content

Commit

Permalink
refactor: instance management
Browse files Browse the repository at this point in the history
  • Loading branch information
Belar committed Nov 29, 2024
1 parent 242345f commit 41e053f
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 103 deletions.
5 changes: 0 additions & 5 deletions src/base/components/alerts/no-instance.html

This file was deleted.

4 changes: 2 additions & 2 deletions src/base/components/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<h2>Instance</h2>
</div>
<div class="settings-section-content">
<input style="width: -webkit-fill-available;" id="InstanceField" type="url" pattern="https?://.*" placeholder="https://design.penpot.app/" value=""/>
<input id="InstanceSaveButton" type="button" value="Save" onclick="InstanceSave()" />
<input style="width: -webkit-fill-available;" id="instance-field" type="url" pattern="https?://.*" placeholder="https://design.penpot.app/" value=""/>
<input id="instance-save" type="button" value="Save" />
</div>
</div>
<!-- <div class="settings-section">
Expand Down
7 changes: 2 additions & 5 deletions src/base/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,19 @@
<script src="./scripts/theme.js"></script>
<script src="./scripts/toggles.js"></script>
</head>
<body onload="ThemeCheck(); InstanceGet()">
<body onload="ThemeCheck();">
<drag></drag>
<sl-include id="include-controls" src="./components/controls.html"></sl-include>
<sl-include src="./components/titlebar.html"></sl-include>
<sl-include src="./components/splash.html"></sl-include>
<sl-include id="include-tabs" src="./components/tabs.html"></sl-include>
<sl-include src="./components/settings.html"></sl-include>
<sl-include id="include-settings" src="./components/settings.html"></sl-include>

<div class="no-tabs-exist" style="display: none;">
<img src="./assets/penpot-logo/logo-white.png"/>
<h2>No tabs are opened</h2>
<p>Add a new tab to start making awesome things.</p>
<button onclick='document.querySelector("body > #include-tabs > tab-group").shadowRoot.querySelector("div > nav > div.buttons > button").click(); ATWC()'>Create a tab</button>
</div>

<!-- Alerts-->
<sl-include class="alert-modal" src="./components/alerts/no-instance.html"></sl-include>
</body>
</html>
53 changes: 37 additions & 16 deletions src/base/scripts/dom.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,69 @@
/**
* Retrieves an element from the DOM based on the provided element and include selectors.
* @template T
* @typedef {new (...args: any[]) => T} Class<T>
*/

/**
* Retrieves an element from the DOM based on the provided element and include selectors, and type.
*
* @overload
* @param {string} selector
* @param {string} includeSelector
* @returns {Promise<Element | null>}
*/
/**
* @template E
* @overload
* @param {string} selector
* @param {string} includeSelector
* @param {Class<E> =} type
* @returns {Promise<ReturnType<typeof typedQuerySelector<E>> | null>}
*
*/
/**
* @param {string} selector - The CSS selector of the element to retrieve.
* @param {string} includeSelector - The CSS selector of the sl-include element.
* @returns {Promise<Element|null>} A promise that resolves to the found element or null if not found.
* @param {Class<E> =} type - The expected type of the element.
*/
function getIncludedElement(selector, includeSelector) {
function getIncludedElement(selector, includeSelector, type) {
return new Promise((resolve) => {
const includeElement = document.querySelector(includeSelector);
if (!includeElement) {
return resolve(null);
}

const element = includeElement.querySelector(selector);
const getElement = () =>
type
? typedQuerySelector(selector, type, includeElement)
: includeElement.querySelector(selector);
const element = getElement();

if (element) {
return resolve(element);
}

includeElement.addEventListener("sl-load", () => {
const element = document.querySelector(selector);
const element = getElement();

resolve(element);
});
});
}


/**
* @template T
* @typedef {new (...args: any[]) => T} Class<T>
*/
/**
* Retrieves an element from the DOM based on the provided selector and expected type.
*
*
* @template E
* @param {string} selector
* @param {string} selector
* @param {Class<E>} type
* @param {ParentNode | null | undefined} parent
* @return {E | null}
*/
function typedQuerySelector(selector, type, parent = document) {
const element = parent?.querySelector(selector);
if(element instanceof type) {
return element
if (element instanceof type) {
return element;
}

return null
}
return null;
}
30 changes: 22 additions & 8 deletions src/base/scripts/electron-tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
* @typedef {import("electron").WebviewTag} WebviewTag
*/

const instance = localStorage.getItem("Instance") || undefined;

const DEFAULT_INSTANCE = "https://design.penpot.app/";
const PRELOAD_PATH = "./scripts/webviews/preload.js";
const DEFAULT_TAB_OPTIONS = Object.freeze({
src: instance,
src: DEFAULT_INSTANCE,
active: true,
webviewAttributes: {
preload: PRELOAD_PATH,
Expand All @@ -23,20 +22,35 @@ window.addEventListener("DOMContentLoaded", async () => {
tabGroup?.on("tab-removed", () => {
ATWC();
});
tabGroup?.setDefaultTab(DEFAULT_TAB_OPTIONS);
tabGroup?.addTab();

prepareTabReloadButton();
});

window.api.onOpenTab(async (href) => {
window.api.onOpenTab(openTab);

/**
* @param {string =} href
*/
async function setDefaultTab(href) {
const tabGroup = await getTabGroup();

tabGroup?.setDefaultTab({
...DEFAULT_TAB_OPTIONS,
...(href ? { src: href } : {}),
});
}

/**
* @param {string =} href
*/
async function openTab(href) {
const tabGroup = await getTabGroup();

tabGroup?.addTab({
...DEFAULT_TAB_OPTIONS,
src: href,
...(href ? { src: href } : {}),
});
});
}

async function prepareTabReloadButton() {
const reloadButton = await getIncludedElement(
Expand Down
125 changes: 60 additions & 65 deletions src/base/scripts/instance.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,74 @@
function InstanceSave() {
// If save button is clicked
const instanceField = typedQuerySelector("input#InstanceField", HTMLInputElement)
const INSTANCE_STORE_KEY = "Instance";

if (instanceField) {
const instance = instanceField.value || "";
localStorage.setItem("Instance", instance);
}
window.addEventListener("DOMContentLoaded", async () => {
const savedInstance = await registerSavedInstance();

const instanceSaveButton = typedQuerySelector("#InstanceSaveButton", HTMLInputElement)
if (instanceSaveButton) {
instanceSaveButton.style.backgroundColor = "#00ff89";
instanceSaveButton.setAttribute("value", "Saved!");
setTimeout(() => {
instanceSaveButton.style.backgroundColor = "#575151";
instanceSaveButton.setAttribute("value", "Save");
}, 1200);
}
}
setDefaultTab(savedInstance);
openTab(savedInstance);
prepareSaveButton();
});

function InstanceGet() {
// Runs on start
const InstanceStore = localStorage.getItem("Instance");
async function prepareSaveButton() {
const { instanceSaveButton } = await getInstanceSettingsForm();

if (InstanceStore) {
window.api.send("registerInstance", InstanceStore);
setTimeout(() => {
const instanceField = typedQuerySelector("input#InstanceField", HTMLInputElement)
instanceSaveButton?.addEventListener("click", (event) => {
const target = event.target;
const element = target instanceof HTMLElement ? target : null;
saveInstance(element);
});
}

if (instanceField) {
instanceField.value = InstanceStore;
}
}, 0o500);
/**
* @param {HTMLElement | null} trigger
*/
async function saveInstance(trigger) {
const isInputButton = trigger instanceof HTMLInputElement;
const { instanceField } = await getInstanceSettingsForm();

const instance = instanceField?.value;
if (instance) {
localStorage.setItem(INSTANCE_STORE_KEY, instance);
} else {
localStorage.removeItem(INSTANCE_STORE_KEY);
}

if (isInputButton) {
trigger.style.backgroundColor = "#00ff89";
trigger.setAttribute("value", "Saved!");
setTimeout(() => {
trigger.style.backgroundColor = "#575151";
trigger.setAttribute("value", "Save");
}, 1200);
}
}

if (!localStorage.getItem("firstTime")) {
localStorage.setItem("Instance", "https://design.penpot.app/"); // If not set, by default on first launch, the app will be blank (to fix issue #3)
localStorage.setItem("firstTime", "true");
// setTimeout(() => {welcome()}, 2500)
} else {
}
async function registerSavedInstance() {
const savedInstance = localStorage.getItem(INSTANCE_STORE_KEY);

if (savedInstance) {
const { instanceField } = await getInstanceSettingsForm();

setTimeout(() => {
const instanceField = typedQuerySelector("input#InstanceField", HTMLInputElement)
window.api.send("registerInstance", savedInstance);

if (instanceField) {
instanceField.value = savedInstance;
}

if (instanceField) {
instanceField.value = localStorage.getItem("Instance") || "";
return savedInstance;
}
}, 0o500);
}

setTimeout(async () => {
const tabGroup = await getTabGroup();
const webview = /** @type {import("electron").WebviewTag | null} */ (
tabGroup?.shadowRoot?.querySelector("div > div > webview")
async function getInstanceSettingsForm() {
const instanceField = await getIncludedElement(
"#instance-field",
"#include-settings",
HTMLInputElement
);
const instanceSaveButton = await getIncludedElement(
"#instance-save",
"#include-settings",
HTMLInputElement
);
const nav = typedQuerySelector("div > nav", HTMLElement, tabGroup?.shadowRoot)
if (webview?.src === "") {
webview.style.opacity = "0";
if (nav) {
nav.style.opacity = "0";
}

console.log("You need to set an instance.");

const titlebarButton = typedQuerySelector("body > titlebar > div.actions > div > button:nth-child(2)", HTMLButtonElement);
const tdmWarnings = typedQuerySelector(".tdm-warnings", HTMLElement);

if (titlebarButton) {
titlebarButton?.click();
}

if (tdmWarnings) {
tdmWarnings.style.display = "inherit";
}
} else {
console.log("An instance is set.");
}
}, 1500);
return { instanceField, instanceSaveButton };
}
2 changes: 1 addition & 1 deletion src/base/styles/index.css

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

2 changes: 1 addition & 1 deletion src/base/styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ drag {
border: 1px #656565 solid;
margin-right: 6px;
}
input#InstanceSaveButton {
input#instance-save {
background: #575151;
color: white;
border: none;
Expand Down

0 comments on commit 41e053f

Please sign in to comment.