diff --git a/packages/ui/src/components/remote-access-overlay.tsx b/packages/ui/src/components/remote-access-overlay.tsx index 04fd26fb..ec0ea522 100644 --- a/packages/ui/src/components/remote-access-overlay.tsx +++ b/packages/ui/src/components/remote-access-overlay.tsx @@ -2,7 +2,7 @@ import { Dialog } from "@kobalte/core/dialog" import { Switch } from "@kobalte/core/switch" import { For, Show, createEffect, createMemo, createSignal } from "solid-js" import { toDataURL } from "qrcode" -import { ExternalLink, Link2, Loader2, RefreshCw, Shield, Wifi } from "lucide-solid" +import { ChevronDown, ExternalLink, Link2, Loader2, RefreshCw, Shield, Wifi } from "lucide-solid" import type { NetworkAddress, ServerMeta } from "../../../server/src/api-types" import { serverApi } from "../lib/api-client" import { restartCli } from "../lib/native/cli" @@ -431,69 +431,79 @@ export function RemoteAccessOverlay(props: RemoteAccessOverlayProps) { 0}> - - setShowAllAddresses(!showAllAddresses())}> - {showAllAddresses() - ? t("remoteAccess.addresses.actions.hideOther") - : t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })} + + setShowAllAddresses(!showAllAddresses())} + aria-expanded={showAllAddresses()} + > + + {showAllAddresses() + ? t("remoteAccess.addresses.actions.hideOther") + : t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })} + + - - - - - {(address) => { - const url = address.remoteUrl - const expandedState = () => expandedUrl() === url - const qr = () => qrCodes()[url] - const scopeLabel = () => - address.scope === "external" - ? t("remoteAccess.address.scope.network") - : address.scope === "loopback" - ? t("remoteAccess.address.scope.loopback") - : t("remoteAccess.address.scope.internal") - return ( - - - - {url} - - {address.family.toUpperCase()} • {scopeLabel()} • {address.ip} - - - - handleOpenUrl(url)}> - - {t("remoteAccess.address.open")} - - void toggleExpanded(url)} - aria-expanded={expandedState()} - > - - {expandedState() ? t("remoteAccess.address.hideQr") : t("remoteAccess.address.showQr")} - - - - - - }> - {(dataUrl) => ( - - )} - - - + + + + {(address) => { + const url = address.remoteUrl + const expandedState = () => expandedUrl() === url + const qr = () => qrCodes()[url] + const scopeLabel = () => + address.scope === "external" + ? t("remoteAccess.address.scope.network") + : address.scope === "loopback" + ? t("remoteAccess.address.scope.loopback") + : t("remoteAccess.address.scope.internal") + return ( + + + + {url} + + {address.family.toUpperCase()} • {scopeLabel()} • {address.ip} + + + + handleOpenUrl(url)}> + + {t("remoteAccess.address.open")} + + void toggleExpanded(url)} + aria-expanded={expandedState()} + > + + {expandedState() ? t("remoteAccess.address.hideQr") : t("remoteAccess.address.showQr")} + + + + + + }> + {(dataUrl) => ( + + )} + + + + + ) + }} + - ) - }} - + + diff --git a/packages/ui/src/components/settings/remote-access-settings-section.tsx b/packages/ui/src/components/settings/remote-access-settings-section.tsx index a4a61a0f..a91d8318 100644 --- a/packages/ui/src/components/settings/remote-access-settings-section.tsx +++ b/packages/ui/src/components/settings/remote-access-settings-section.tsx @@ -1,7 +1,7 @@ import { Switch } from "@kobalte/core/switch" import { For, Show, createMemo, createSignal, type Component, onMount } from "solid-js" import { toDataURL } from "qrcode" -import { ExternalLink, Link2, Loader2, RefreshCw, Shield, Wifi } from "lucide-solid" +import { ChevronDown, ExternalLink, Link2, Loader2, RefreshCw, Shield, Wifi } from "lucide-solid" import type { NetworkAddress, ServerMeta } from "../../../../server/src/api-types" import { serverApi } from "../../lib/api-client" import { restartCli } from "../../lib/native/cli" @@ -401,66 +401,76 @@ export const RemoteAccessSettingsSection: Component = () => { 0}> - - setShowAllAddresses(!showAllAddresses())}> - {showAllAddresses() - ? t("remoteAccess.addresses.actions.hideOther") - : t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })} + + setShowAllAddresses(!showAllAddresses())} + aria-expanded={showAllAddresses()} + > + + {showAllAddresses() + ? t("remoteAccess.addresses.actions.hideOther") + : t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })} + + - - - - - {(address) => { - const url = address.remoteUrl - const expandedState = () => expandedUrl() === url - const qr = () => qrCodes()[url] - const scopeLabel = () => - address.scope === "external" - ? t("remoteAccess.address.scope.network") - : address.scope === "loopback" - ? t("remoteAccess.address.scope.loopback") - : t("remoteAccess.address.scope.internal") + + + + {(address) => { + const url = address.remoteUrl + const expandedState = () => expandedUrl() === url + const qr = () => qrCodes()[url] + const scopeLabel = () => + address.scope === "external" + ? t("remoteAccess.address.scope.network") + : address.scope === "loopback" + ? t("remoteAccess.address.scope.loopback") + : t("remoteAccess.address.scope.internal") - return ( - - - - {url} - - {address.family.toUpperCase()} - {scopeLabel()} - {address.ip} - - - - handleOpenUrl(url)}> - - {t("remoteAccess.address.open")} - - void toggleExpanded(url)} - aria-expanded={expandedState()} - > - - {expandedState() ? t("remoteAccess.address.hideQr") : t("remoteAccess.address.showQr")} - - - - - - }> - {(dataUrl) => ( - - )} - - - + return ( + + + + {url} + + {address.family.toUpperCase()} - {scopeLabel()} - {address.ip} + + + + handleOpenUrl(url)}> + + {t("remoteAccess.address.open")} + + void toggleExpanded(url)} + aria-expanded={expandedState()} + > + + {expandedState() ? t("remoteAccess.address.hideQr") : t("remoteAccess.address.showQr")} + + + + + + }> + {(dataUrl) => ( + + )} + + + + + ) + }} + - ) - }} - + + diff --git a/packages/ui/src/styles/components/remote-access.css b/packages/ui/src/styles/components/remote-access.css index feee3fbc..be7b8ad0 100644 --- a/packages/ui/src/styles/components/remote-access.css +++ b/packages/ui/src/styles/components/remote-access.css @@ -256,6 +256,55 @@ cursor: pointer; } +.remote-address-disclosure { + border: 1px solid var(--border-base); + border-radius: 12px; + background: var(--surface-primary); + overflow: hidden; +} + +.remote-address-disclosure-trigger { + width: 100%; + min-height: 40px; + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; + padding: 8px 12px; + border: 0; + background: transparent; + color: var(--text-primary); + cursor: pointer; +} + +.remote-address-disclosure-label { + grid-column: 2; + justify-self: center; + text-align: center; + font-size: 13px; + font-weight: 600; +} + +.remote-address-disclosure-chevron { + grid-column: 3; + justify-self: end; + width: 16px; + height: 16px; + color: var(--text-secondary); + transition: transform 0.2s ease; +} + +.remote-address-disclosure-chevron.is-expanded { + transform: rotate(180deg); +} + +.remote-address-disclosure-content { + display: flex; + flex-direction: column; + gap: 10px; + padding: 0 10px 10px; + border-top: 1px solid var(--border-base); +} + .remote-qr { margin-top: 12px; display: flex;
{url}
- {address.family.toUpperCase()} • {scopeLabel()} • {address.ip} -
+ {address.family.toUpperCase()} • {scopeLabel()} • {address.ip} +
- {address.family.toUpperCase()} - {scopeLabel()} - {address.ip} -
+ {address.family.toUpperCase()} - {scopeLabel()} - {address.ip} +