From 9581b793b5ed0eee41267a60ce2b57044897cfa1 Mon Sep 17 00:00:00 2001 From: SethBurkart123 Date: Wed, 18 Mar 2026 08:44:20 +1100 Subject: [PATCH] feat: render floating popup at extension root --- .gitignore | 1 + package.json | 1 + .../components/ConnectMobileApp.svelte | 28 ++++++++----------- src/interface/pages/settings/general.svelte | 4 +-- src/interface/utils/portal.ts | 22 +++++++++++++++ 5 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 src/interface/utils/portal.ts diff --git a/.gitignore b/.gitignore index 3f892496..73db358a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ package-lock.json bun.lockb pnpm-lock.yaml yarn.lock +bun.lock .parcel-cache .env diff --git a/package.json b/package.json index c87befb9..63503923 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "@types/color": "^4.2.0", "@types/lodash": "^4.17.16", "@types/node": "^24.3.0", + "@types/qrcode": "^1.5.6", "@types/sortablejs": "^1.15.8", "@types/uuid": "^10.0.0", "@types/webextension-polyfill": "^0.12.3", diff --git a/src/interface/components/ConnectMobileApp.svelte b/src/interface/components/ConnectMobileApp.svelte index 7daaf60e..4c7372a0 100644 --- a/src/interface/components/ConnectMobileApp.svelte +++ b/src/interface/components/ConnectMobileApp.svelte @@ -2,8 +2,8 @@ import { fade } from "svelte/transition"; import browser from "webextension-polyfill"; import QRCode from "qrcode"; + import { portal } from "../utils/portal"; - const DESQTA_DOWNLOAD_URL = "https://betterseqta.org/desqta"; const DEEPLINK_PREFIX = "desqta://connect/"; let showQrModal = $state(false); @@ -109,29 +109,23 @@ } -
- - Download - +
{#if errorMessage} -

{errorMessage}

+

{errorMessage}

{/if}
{#if showQrModal && qrDataUrl}
{ @@ -151,31 +145,31 @@
-
+
DesQTA QR Code
-

+

Or scan this QR code with DesQTA on your phone.

diff --git a/src/interface/pages/settings/general.svelte b/src/interface/pages/settings/general.svelte index da8ccd76..e16c793d 100644 --- a/src/interface/pages/settings/general.svelte +++ b/src/interface/pages/settings/general.svelte @@ -115,7 +115,7 @@ {#each [ { title: "Connect Mobile App", - description: "Link your SEQTA session to DesQTA — the modern desktop and mobile app for SEQTA Learn. Scan the QR code with DesQTA to sign in instantly.", + description: "Link your SEQTA session to DesQTA — the modern desktop and mobile app for SEQTA Learn.", id: 0, Component: ConnectMobileApp, props: {} @@ -225,7 +225,7 @@ {@render Setting(option)} {/each} -
+

Adaptive Theme Colour

diff --git a/src/interface/utils/portal.ts b/src/interface/utils/portal.ts new file mode 100644 index 00000000..d634d3be --- /dev/null +++ b/src/interface/utils/portal.ts @@ -0,0 +1,22 @@ +import type { Action } from "svelte/action"; + +/** + * Svelte action that moves the element to a different DOM target. + * Defaults to the nearest ShadowRoot so styles remain intact when the app + * is rendered inside a shadow DOM. Falls back to document.body otherwise. + * Keeps all Svelte reactivity/events intact while escaping ancestor stacking contexts. + */ +export const portal: Action = (node, target) => { + const root = node.getRootNode(); + const dest = target ?? (root instanceof ShadowRoot ? root : document.body); + dest.appendChild(node); + + return { + update(newTarget) { + (newTarget ?? dest).appendChild(node); + }, + destroy() { + node.remove(); + }, + }; +};