From 1e877a5d9278705616a8c3d3d1d864a8dd387fc8 Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Tue, 14 Jan 2025 17:41:14 +0100 Subject: [PATCH 01/10] Populate the list --- static/crossroad.css | 9 +++++++++ static/crossroad.html | 16 ++++++++++------ static/crossroad.mts | 39 +++++++++++++++++++++++++++++++++++++- static/storage_manager.mts | 6 ++++++ 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/static/crossroad.css b/static/crossroad.css index 92bcd3c..5569ae5 100644 --- a/static/crossroad.css +++ b/static/crossroad.css @@ -119,4 +119,13 @@ abbr[title] { top: 50%; left: 50%; translate: -50% -50%; +} + +.logo { + height: 4em; +} + +.inlineIcon { + height: var(--medium); + vertical-align: text-top; } \ No newline at end of file diff --git a/static/crossroad.html b/static/crossroad.html index 0ab8ba3..c5fb33d 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -20,15 +20,19 @@

FeDirect

  By Nekomata

- Nekomata Logo +
-
- - + +
+ + +

diff --git a/static/crossroad.mts b/static/crossroad.mts index 8d212c4..ad0bfe9 100644 --- a/static/crossroad.mts +++ b/static/crossroad.mts @@ -1,5 +1,7 @@ import { initializeAddInstanceFlow } from "./add_instance_flow.mjs"; -import { findDialogOrFail } from "./dom.mjs"; +import { findDialogOrFail, findFormOrFail } from "./dom.mjs"; +import knownSoftware from "./known_software.mjs"; +import storageManager from "./storage_manager.mjs"; export function getMainDialog(): HTMLDialogElement { return document.getElementById('mainDialog') as HTMLDialogElement; @@ -7,8 +9,43 @@ export function getMainDialog(): HTMLDialogElement { const detailsDialog = findDialogOrFail(document.body, "#instanceDetails"); const addDialog = findDialogOrFail(document.body, "#addInstance"); +const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm"); export const { showAddInstanceDialog, hideAddInstanceDialog } = initializeAddInstanceFlow(detailsDialog, addDialog); + +function createInstanceSelectOptions() { + instanceSelectForm.replaceChildren(); // Erase all child nodes + for (const instance of storageManager.storage.instances) { + const div = document.createElement("div"); + div.setAttribute("x-option", instance.origin); + const radio = document.createElement("input"); + radio.id = instance.origin; + radio.type = "radio"; + radio.name = "instanceSelect"; + const label = document.createElement("label"); + label.htmlFor = instance.origin; + label.innerText = instance.name + " "; + if (instance.iconURL) { + const img = new Image(); + img.src = instance.iconURL; + img.alt = `${instance.name} icon`; + img.className = "inlineIcon"; + label.append(img, " "); + } + const small = document.createElement("small"); + const softwareName = knownSoftware.software[instance.software].name; + small.innerText = `(${softwareName})`; + label.appendChild(small); + div.appendChild(radio); + div.appendChild(label); + instanceSelectForm.appendChild(div); + } + const firstInput = instanceSelectForm.querySelector("input"); + if (firstInput) firstInput.checked = true; +} + +createInstanceSelectOptions(); +storageManager.addSaveCallback(createInstanceSelectOptions); diff --git a/static/storage_manager.mts b/static/storage_manager.mts index da88774..dc89b95 100644 --- a/static/storage_manager.mts +++ b/static/storage_manager.mts @@ -33,6 +33,7 @@ type LocalStorage = { export default new class StorageManager { storage: LocalStorage; + saveCallbacks: (() => void)[] = []; constructor() { this.load(); @@ -50,5 +51,10 @@ export default new class StorageManager { save() { window.localStorage.setItem("storage", JSON.stringify(this.storage)); + this.saveCallbacks.forEach(c => c()); + } + + addSaveCallback(callback: () => void) { + this.saveCallbacks.push(callback); } }(); \ No newline at end of file -- 2.45.3 From af41b8e10bbee2ec3879d02e82ae39d2c4125d64 Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Tue, 14 Jan 2025 17:45:16 +0100 Subject: [PATCH 02/10] Remove old dummy item --- static/crossroad.html | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/static/crossroad.html b/static/crossroad.html index c5fb33d..5405513 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -24,16 +24,7 @@
-
-
- - -
-
+

-- 2.45.3 From 6861a549acf7ea16b3fe3c07f1ba264e12b79c00 Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Tue, 14 Jan 2025 18:25:02 +0100 Subject: [PATCH 03/10] Naive redirect implementation --- static/crossroad.html | 4 +++- static/crossroad.mts | 26 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/static/crossroad.html b/static/crossroad.html index 5405513..4bff713 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -28,7 +28,9 @@
-
+
+ +
diff --git a/static/crossroad.mts b/static/crossroad.mts index ad0bfe9..4901180 100644 --- a/static/crossroad.mts +++ b/static/crossroad.mts @@ -1,8 +1,10 @@ import { initializeAddInstanceFlow } from "./add_instance_flow.mjs"; -import { findDialogOrFail, findFormOrFail } from "./dom.mjs"; +import { findButtonOrFail, findDialogOrFail, findFormOrFail, findInputOrFail } from "./dom.mjs"; import knownSoftware from "./known_software.mjs"; import storageManager from "./storage_manager.mjs"; +const radioButtonName = "instanceSelect"; + export function getMainDialog(): HTMLDialogElement { return document.getElementById('mainDialog') as HTMLDialogElement; } @@ -10,6 +12,7 @@ export function getMainDialog(): HTMLDialogElement { const detailsDialog = findDialogOrFail(document.body, "#instanceDetails"); const addDialog = findDialogOrFail(document.body, "#addInstance"); const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm"); +const redirectButton = findButtonOrFail(document.body, "#redirect"); export const { showAddInstanceDialog, @@ -23,8 +26,9 @@ function createInstanceSelectOptions() { div.setAttribute("x-option", instance.origin); const radio = document.createElement("input"); radio.id = instance.origin; + radio.value = instance.origin; radio.type = "radio"; - radio.name = "instanceSelect"; + radio.name = radioButtonName; const label = document.createElement("label"); label.htmlFor = instance.origin; label.innerText = instance.name + " "; @@ -44,8 +48,24 @@ function createInstanceSelectOptions() { instanceSelectForm.appendChild(div); } const firstInput = instanceSelectForm.querySelector("input"); - if (firstInput) firstInput.checked = true; + if (firstInput) { + firstInput.checked = true; + redirectButton.disabled = false; + } else { + redirectButton.disabled = true; + } } createInstanceSelectOptions(); storageManager.addSaveCallback(createInstanceSelectOptions); + +function redirect() { + // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default + const option = findInputOrFail(instanceSelectForm, `input[name="${radioButtonName}"]:checked`).value; + const url = URL.parse(option)!; + const currentURL = URL.parse(location.href)!; + url.pathname = currentURL.pathname.replace(/\/.*?\//, "/"); + location.href = url.toString(); +} + +redirectButton.addEventListener("click", e => redirect()); -- 2.45.3 From e66b399961f36c301880fd7f4b86307b89d0794f Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Wed, 15 Jan 2025 06:44:47 +0100 Subject: [PATCH 04/10] Implement autoredirect --- static/crossroad.css | 15 ++++++++ static/crossroad.html | 7 +++- static/crossroad.mts | 74 +++++++++++++++++++++++++++++++------- static/storage_manager.mts | 5 +++ 4 files changed, 88 insertions(+), 13 deletions(-) diff --git a/static/crossroad.css b/static/crossroad.css index 5569ae5..89f0b37 100644 --- a/static/crossroad.css +++ b/static/crossroad.css @@ -61,6 +61,14 @@ abbr[title] { height: 100%; } +.flex-hcenter { + display: flex; + flex-direction: row; + justify-content: center; + width: 100%; + height: 100%; +} + .flex-row { display: flex; flex-direction: row; @@ -76,6 +84,13 @@ abbr[title] { flex-direction: column-reverse; } +.flex-vevenly { + display: flex; + flex-direction: column; + justify-content: space-evenly; + height: 100%; +} + .half-width { min-width: 50%; } diff --git a/static/crossroad.html b/static/crossroad.html index 4bff713..29e0141 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -29,7 +29,12 @@
- +
+
+ + +
+
diff --git a/static/crossroad.mts b/static/crossroad.mts index 4901180..beb6e88 100644 --- a/static/crossroad.mts +++ b/static/crossroad.mts @@ -13,6 +13,7 @@ const detailsDialog = findDialogOrFail(document.body, "#instanceDetails"); const addDialog = findDialogOrFail(document.body, "#addInstance"); const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm"); const redirectButton = findButtonOrFail(document.body, "#redirect"); +const redirectAlwaysButton = findButtonOrFail(document.body, "#redirectAlways"); export const { showAddInstanceDialog, @@ -48,24 +49,73 @@ function createInstanceSelectOptions() { instanceSelectForm.appendChild(div); } const firstInput = instanceSelectForm.querySelector("input"); - if (firstInput) { - firstInput.checked = true; - redirectButton.disabled = false; - } else { - redirectButton.disabled = true; - } + if (firstInput) firstInput.checked = true; + setRedirectButtonState(firstInput !== null); } createInstanceSelectOptions(); storageManager.addSaveCallback(createInstanceSelectOptions); -function redirect() { - // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default - const option = findInputOrFail(instanceSelectForm, `input[name="${radioButtonName}"]:checked`).value; - const url = URL.parse(option)!; +function setRedirectButtonState(enabled: boolean) { + redirectButton.disabled = !enabled; + redirectAlwaysButton.disabled = !enabled; +} + +export function getTargetSoftwareOrGroup(): string { const currentURL = URL.parse(location.href)!; - url.pathname = currentURL.pathname.replace(/\/.*?\//, "/"); + const target = currentURL.pathname.match(/\/+([^\/]*)\/?/)?.[1]; + if (target == null) throw new Error("Crossroad was served on an invalid path (likely a backend routing mistake)"); + const softwareName = Object.entries(knownSoftware.software).find(([name, software]) => software.aliases.includes(target))?.[0]; + if (softwareName) return softwareName; + const groupName = Object.entries(knownSoftware.groups).find(([name, group]) => group.aliases.includes(target))?.[0]; + if (groupName) return groupName; + throw new Error("Could not identify target software or group"); +} + +function getTargetPath(): string { + const currentURL = URL.parse(location.href)!; + return currentURL.pathname.replace(/\/+[^\/]*\/?/, "/"); +} + +function getSelectedOption(): string | null { + try { + return findInputOrFail(instanceSelectForm, `input[name="${radioButtonName}"]:checked`).value; + } catch { + return null; + } +} + +function autoRedirect() { + const targetSoftware = getTargetSoftwareOrGroup(); + const preferredFor = storageManager.storage.instances.find(instance => instance.preferredFor?.includes(targetSoftware)); + if (preferredFor) redirect(preferredFor.origin); +} + +autoRedirect(); + +function setAutoRedirect(option: string) { + const instance = storageManager.storage.instances.find(e => e.origin === option); + if (!instance) throw new Error("Invalid argument"); + instance.preferredFor ??= []; + instance.preferredFor.push(getTargetSoftwareOrGroup()); + storageManager.save(); +} + +redirectAlwaysButton.addEventListener("click", e => { + // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default + const option = getSelectedOption()!; + setAutoRedirect(option); + redirect(option); +}); + +function redirect(to: string) { + const url = URL.parse(to); + if (url === null) throw new Error("Couldn't parse destination"); + url.pathname = getTargetPath(); location.href = url.toString(); } -redirectButton.addEventListener("click", e => redirect()); +redirectButton.addEventListener("click", e => { + // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default + redirect(getSelectedOption()!); +}); diff --git a/static/storage_manager.mts b/static/storage_manager.mts index dc89b95..7ab3957 100644 --- a/static/storage_manager.mts +++ b/static/storage_manager.mts @@ -25,6 +25,11 @@ export type Instance = { * Make sure to sanitize this! Could lead to XSS */ iconURL?: string, + /** + * The list of software names and groups the user prefers to autoredirect to this instance + * @example ["sharkey", "misskey-compliant"] + */ + preferredFor?: string[], } type LocalStorage = { -- 2.45.3 From 3a09f6c1f0eabcadc244ce4b39c9f248b4d48fdf Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Wed, 15 Jan 2025 07:05:47 +0100 Subject: [PATCH 05/10] Clean up a bit --- static/crossroad.mts | 59 +++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/static/crossroad.mts b/static/crossroad.mts index beb6e88..e7daae0 100644 --- a/static/crossroad.mts +++ b/static/crossroad.mts @@ -5,20 +5,42 @@ import storageManager from "./storage_manager.mjs"; const radioButtonName = "instanceSelect"; -export function getMainDialog(): HTMLDialogElement { - return document.getElementById('mainDialog') as HTMLDialogElement; -} - const detailsDialog = findDialogOrFail(document.body, "#instanceDetails"); const addDialog = findDialogOrFail(document.body, "#addInstance"); const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm"); const redirectButton = findButtonOrFail(document.body, "#redirect"); const redirectAlwaysButton = findButtonOrFail(document.body, "#redirectAlways"); +redirectButton.addEventListener("click", e => { + // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default + redirect(getSelectedOption()!); +}); + +redirectAlwaysButton.addEventListener("click", e => { + // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default + const option = getSelectedOption()!; + setAutoRedirect(option); + redirect(option); +}); + +export const getMainDialog = () => findDialogOrFail(document.body, "#mainDialog"); + export const { showAddInstanceDialog, hideAddInstanceDialog -} = initializeAddInstanceFlow(detailsDialog, addDialog); +} = ((): { + showAddInstanceDialog: () => void, + hideAddInstanceDialog: () => void +} => { + // Don't bother initializing if we're performing autoredirect + if (autoRedirect()) return { + showAddInstanceDialog: () => { }, + hideAddInstanceDialog: () => { } + } + createInstanceSelectOptions(); + storageManager.addSaveCallback(createInstanceSelectOptions); + return initializeAddInstanceFlow(detailsDialog, addDialog) +})(); function createInstanceSelectOptions() { instanceSelectForm.replaceChildren(); // Erase all child nodes @@ -53,15 +75,12 @@ function createInstanceSelectOptions() { setRedirectButtonState(firstInput !== null); } -createInstanceSelectOptions(); -storageManager.addSaveCallback(createInstanceSelectOptions); - function setRedirectButtonState(enabled: boolean) { redirectButton.disabled = !enabled; redirectAlwaysButton.disabled = !enabled; } -export function getTargetSoftwareOrGroup(): string { +function getTargetSoftwareOrGroup(): string { const currentURL = URL.parse(location.href)!; const target = currentURL.pathname.match(/\/+([^\/]*)\/?/)?.[1]; if (target == null) throw new Error("Crossroad was served on an invalid path (likely a backend routing mistake)"); @@ -85,14 +104,16 @@ function getSelectedOption(): string | null { } } -function autoRedirect() { +function autoRedirect(): boolean { const targetSoftware = getTargetSoftwareOrGroup(); const preferredFor = storageManager.storage.instances.find(instance => instance.preferredFor?.includes(targetSoftware)); - if (preferredFor) redirect(preferredFor.origin); + if (preferredFor) { + redirect(preferredFor.origin); + return true; + } + return false; } -autoRedirect(); - function setAutoRedirect(option: string) { const instance = storageManager.storage.instances.find(e => e.origin === option); if (!instance) throw new Error("Invalid argument"); @@ -101,21 +122,9 @@ function setAutoRedirect(option: string) { storageManager.save(); } -redirectAlwaysButton.addEventListener("click", e => { - // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default - const option = getSelectedOption()!; - setAutoRedirect(option); - redirect(option); -}); - function redirect(to: string) { const url = URL.parse(to); if (url === null) throw new Error("Couldn't parse destination"); url.pathname = getTargetPath(); location.href = url.toString(); } - -redirectButton.addEventListener("click", e => { - // Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default - redirect(getSelectedOption()!); -}); -- 2.45.3 From 358527f59e9e4baa83d4a3933fc1dcc233ccf62a Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Wed, 15 Jan 2025 07:05:55 +0100 Subject: [PATCH 06/10] Add some more aliases --- known-software.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/known-software.json b/known-software.json index 828ad18..eba5902 100644 --- a/known-software.json +++ b/known-software.json @@ -32,6 +32,7 @@ "name": "Akkoma", "nodeinfoName": "akkoma", "aliases": [ + "akkoma", "akko" ], "groups": [ @@ -93,6 +94,7 @@ "nodeinfoName": "mastodon", "buildMetadata": "glitch", "aliases": [ + "glitch-soc", "glitch" ], "groups": [ @@ -155,7 +157,8 @@ "name": "Iceshrimp.NET", "nodeinfoName": "Iceshrimp.NET", "aliases": [ - "iceshrimp-dotnet" + "iceshrimp-dotnet", + "iceshrimp.net" ], "groups": [ "misskey-compliant", -- 2.45.3 From 70c941cf0e06a9be0d6a3228d6e2f60ab90b863f Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Wed, 15 Jan 2025 07:58:48 +0100 Subject: [PATCH 07/10] Stylistic changes --- static/crossroad.css | 18 ++++++++++++++++++ static/crossroad.html | 9 +++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/static/crossroad.css b/static/crossroad.css index 89f0b37..544bc65 100644 --- a/static/crossroad.css +++ b/static/crossroad.css @@ -2,6 +2,7 @@ --red: #cb0b0b; --blue: #2081c3; --transparent-black: #0008; + --xl: 4em; --large: 2em; --medium: 1em; } @@ -53,6 +54,10 @@ abbr[title] { text-decoration-color: var(--blue); } +.align-start { + text-align: start; +} + .flex-vcenter { display: flex; flex-direction: column; @@ -79,6 +84,11 @@ abbr[title] { flex-direction: row-reverse; } +.flex-column { + display: flex; + flex-direction: column; +} + .flex-column-reverse { display: flex; flex-direction: column-reverse; @@ -91,6 +101,10 @@ abbr[title] { height: 100%; } +.wfit-content { + width: fit-content; +} + .half-width { min-width: 50%; } @@ -143,4 +157,8 @@ abbr[title] { .inlineIcon { height: var(--medium); vertical-align: text-top; +} + +.buttonPanel>* { + margin-top: min(var(--xl), 6vh); } \ No newline at end of file diff --git a/static/crossroad.html b/static/crossroad.html index 29e0141..9fe5c11 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -23,16 +23,17 @@
-
-
+
+

-
+
-
+
+ Manage instances
-- 2.45.3 From 97fc0eb60ad2b3a9ac43ec72d4bcb3ec09148027 Mon Sep 17 00:00:00 2001 From: Kio Date: Mon, 20 Jan 2025 10:55:45 -0500 Subject: [PATCH 08/10] Add redirects, and a dynamic "Add an instance please!" button. --- static/crossroad.css | 10 ++++++++++ static/crossroad.html | 4 ++++ static/crossroad.mts | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/static/crossroad.css b/static/crossroad.css index 544bc65..811fe80 100644 --- a/static/crossroad.css +++ b/static/crossroad.css @@ -58,6 +58,10 @@ abbr[title] { text-align: start; } +pre#path { + display: inline-block; +} + .flex-vcenter { display: flex; flex-direction: column; @@ -76,6 +80,8 @@ abbr[title] { .flex-row { display: flex; + justify-content: center; + align-items: center;; flex-direction: row; } @@ -161,4 +167,8 @@ abbr[title] { .buttonPanel>* { margin-top: min(var(--xl), 6vh); +} + +.hidden { + display: none; } \ No newline at end of file diff --git a/static/crossroad.html b/static/crossroad.html index 9fe5c11..570d751 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -24,6 +24,10 @@
+ You're about to go to
.
+ + +

diff --git a/static/crossroad.mts b/static/crossroad.mts index e7daae0..0cbf049 100644 --- a/static/crossroad.mts +++ b/static/crossroad.mts @@ -43,6 +43,9 @@ export const { })(); function createInstanceSelectOptions() { + if (storageManager.storage.instances.length > 0) { + document.querySelector("#no-instance")?.classList.add("hidden") + } instanceSelectForm.replaceChildren(); // Erase all child nodes for (const instance of storageManager.storage.instances) { const div = document.createElement("div"); @@ -128,3 +131,8 @@ function redirect(to: string) { url.pathname = getTargetPath(); location.href = url.toString(); } + +document.querySelector("#path")!.innerHTML = getTargetPath() +if (storageManager.storage.instances.length === 0) { + document.querySelector("#no-instance")?.classList.remove("hidden") +} \ No newline at end of file -- 2.45.3 From e86b79b26e7496a6b842e2695be776088531e80a Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Mon, 20 Jan 2025 19:36:38 +0100 Subject: [PATCH 09/10] Ship of theseus for commit 97fc0eb --- static/crossroad.css | 18 ++++++++++-------- static/crossroad.html | 22 ++++++++++++---------- static/crossroad.mts | 24 +++++++++++++++--------- static/dom.mts | 14 ++++++++++++++ static/down_arrow.svg | 1 + 5 files changed, 52 insertions(+), 27 deletions(-) create mode 100644 static/down_arrow.svg diff --git a/static/crossroad.css b/static/crossroad.css index 811fe80..86c25f2 100644 --- a/static/crossroad.css +++ b/static/crossroad.css @@ -58,10 +58,15 @@ abbr[title] { text-align: start; } -pre#path { +.inline-block { display: inline-block; } +.align-content-center { + justify-content: center; + align-items: center; +} + .flex-vcenter { display: flex; flex-direction: column; @@ -80,8 +85,6 @@ pre#path { .flex-row { display: flex; - justify-content: center; - align-items: center;; flex-direction: row; } @@ -123,6 +126,10 @@ pre#path { min-height: 100%; } +.medium-height { + height: var(--medium); +} + .separator-bottom { border-bottom: solid 1px var(--transparent-black); } @@ -161,14 +168,9 @@ pre#path { } .inlineIcon { - height: var(--medium); vertical-align: text-top; } .buttonPanel>* { margin-top: min(var(--xl), 6vh); -} - -.hidden { - display: none; } \ No newline at end of file diff --git a/static/crossroad.html b/static/crossroad.html index 570d751..0bbf31e 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -22,16 +22,18 @@
-
-
- You're about to go to
.
- - -
-
-
- -
+
+
+
+ You're about to go to +
.
+ +

You currently don't have any instances. You should add one!

+
+
+ +
+
diff --git a/static/crossroad.mts b/static/crossroad.mts index 0cbf049..2e6ee32 100644 --- a/static/crossroad.mts +++ b/static/crossroad.mts @@ -1,5 +1,5 @@ import { initializeAddInstanceFlow } from "./add_instance_flow.mjs"; -import { findButtonOrFail, findDialogOrFail, findFormOrFail, findInputOrFail } from "./dom.mjs"; +import { findButtonOrFail, findDialogOrFail, findFormOrFail, findInputOrFail, findParagraphOrFail, findPreOrFail } from "./dom.mjs"; import knownSoftware from "./known_software.mjs"; import storageManager from "./storage_manager.mjs"; @@ -39,13 +39,22 @@ export const { } createInstanceSelectOptions(); storageManager.addSaveCallback(createInstanceSelectOptions); + updateNoInstanceHint(); + storageManager.addSaveCallback(updateNoInstanceHint); + + findPreOrFail(document.body, "#path").innerText = getTargetPath(); + return initializeAddInstanceFlow(detailsDialog, addDialog) })(); +function updateNoInstanceHint() { + findParagraphOrFail(document.body, "#no-instance").style.display = + storageManager.storage.instances.length > 0 + ? "none" + : ""; +} + function createInstanceSelectOptions() { - if (storageManager.storage.instances.length > 0) { - document.querySelector("#no-instance")?.classList.add("hidden") - } instanceSelectForm.replaceChildren(); // Erase all child nodes for (const instance of storageManager.storage.instances) { const div = document.createElement("div"); @@ -62,7 +71,7 @@ function createInstanceSelectOptions() { const img = new Image(); img.src = instance.iconURL; img.alt = `${instance.name} icon`; - img.className = "inlineIcon"; + img.className = "inlineIcon medium-height"; label.append(img, " "); } const small = document.createElement("small"); @@ -132,7 +141,4 @@ function redirect(to: string) { location.href = url.toString(); } -document.querySelector("#path")!.innerHTML = getTargetPath() -if (storageManager.storage.instances.length === 0) { - document.querySelector("#no-instance")?.classList.remove("hidden") -} \ No newline at end of file +export { storageManager }; \ No newline at end of file diff --git a/static/dom.mts b/static/dom.mts index 7a7aff5..53d4c36 100644 --- a/static/dom.mts +++ b/static/dom.mts @@ -1,6 +1,20 @@ // I would've LOVED to use generics for this but unfortunately that's not possible. // Type safety, but at what cost... >~< thanks TypeScript +export function findPreOrFail(on: Element, selector: string): HTMLPreElement { + const element = on.querySelector(selector); + if (!(element instanceof HTMLPreElement)) + throw new Error(`${selector} isn't a pre`); + return element; +} + +export function findParagraphOrFail(on: Element, selector: string): HTMLParagraphElement { + const element = on.querySelector(selector); + if (!(element instanceof HTMLParagraphElement)) + throw new Error(`${selector} isn't a paragraph`); + return element; +} + export function findDialogOrFail(on: Element, selector: string): HTMLDialogElement { const element = on.querySelector(selector); if (!(element instanceof HTMLDialogElement)) diff --git a/static/down_arrow.svg b/static/down_arrow.svg new file mode 100644 index 0000000..875e948 --- /dev/null +++ b/static/down_arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file -- 2.45.3 From 8fe980c4bec155490af4cb34976eda2cf9bc86a4 Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Mon, 20 Jan 2025 20:09:41 +0100 Subject: [PATCH 10/10] rename main css file --- static/crossroad.html | 2 +- static/{crossroad.css => main.css} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename static/{crossroad.css => main.css} (100%) diff --git a/static/crossroad.html b/static/crossroad.html index 0bbf31e..4ed6abc 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -5,7 +5,7 @@ FeDirect - + diff --git a/static/crossroad.css b/static/main.css similarity index 100% rename from static/crossroad.css rename to static/main.css -- 2.45.3