refactor(ui): group extra remote addresses behind disclosure

Replace the standalone show/hide button with a full-width collapsible disclosure container in both remote access surfaces. This keeps the hidden address list visually grouped, makes the header easier to scan and click, and centers the label so it reads as structure rather than an unrelated action button.

Keep the first recommended remote address visible by default while preserving access to the full list behind the compact disclosure header.
This commit is contained in:
VooDisss
2026-04-01 17:04:20 +03:00
parent b0b0a55e14
commit 61e06ef883
3 changed files with 187 additions and 118 deletions

View File

@@ -2,7 +2,7 @@ import { Dialog } from "@kobalte/core/dialog"
import { Switch } from "@kobalte/core/switch" import { Switch } from "@kobalte/core/switch"
import { For, Show, createEffect, createMemo, createSignal } from "solid-js" import { For, Show, createEffect, createMemo, createSignal } from "solid-js"
import { toDataURL } from "qrcode" 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 type { NetworkAddress, ServerMeta } from "../../../server/src/api-types"
import { serverApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
import { restartCli } from "../lib/native/cli" import { restartCli } from "../lib/native/cli"
@@ -431,16 +431,23 @@ export function RemoteAccessOverlay(props: RemoteAccessOverlayProps) {
</Show> </Show>
<Show when={displayAddresses().hidden.length > 0}> <Show when={displayAddresses().hidden.length > 0}>
<div class="remote-actions" style={{ "justify-content": "flex-start" }}> <div class="remote-address-disclosure" data-expanded={showAllAddresses()}>
<button class="remote-pill" type="button" onClick={() => setShowAllAddresses(!showAllAddresses())}> <button
class="remote-address-disclosure-trigger"
type="button"
onClick={() => setShowAllAddresses(!showAllAddresses())}
aria-expanded={showAllAddresses()}
>
<span class="remote-address-disclosure-label">
{showAllAddresses() {showAllAddresses()
? t("remoteAccess.addresses.actions.hideOther") ? t("remoteAccess.addresses.actions.hideOther")
: t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })} : t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })}
</span>
<ChevronDown class={`remote-address-disclosure-chevron ${showAllAddresses() ? "is-expanded" : ""}`} />
</button> </button>
</div>
</Show>
<Show when={showAllAddresses()}> <Show when={showAllAddresses()}>
<div class="remote-address-disclosure-content">
<For each={displayAddresses().hidden}> <For each={displayAddresses().hidden}>
{(address) => { {(address) => {
const url = address.remoteUrl const url = address.remoteUrl
@@ -494,6 +501,9 @@ export function RemoteAccessOverlay(props: RemoteAccessOverlayProps) {
) )
}} }}
</For> </For>
</div>
</Show>
</div>
</Show> </Show>
</div> </div>
</Show> </Show>

View File

@@ -1,7 +1,7 @@
import { Switch } from "@kobalte/core/switch" import { Switch } from "@kobalte/core/switch"
import { For, Show, createMemo, createSignal, type Component, onMount } from "solid-js" import { For, Show, createMemo, createSignal, type Component, onMount } from "solid-js"
import { toDataURL } from "qrcode" 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 type { NetworkAddress, ServerMeta } from "../../../../server/src/api-types"
import { serverApi } from "../../lib/api-client" import { serverApi } from "../../lib/api-client"
import { restartCli } from "../../lib/native/cli" import { restartCli } from "../../lib/native/cli"
@@ -401,16 +401,23 @@ export const RemoteAccessSettingsSection: Component = () => {
</Show> </Show>
<Show when={displayAddresses().hidden.length > 0}> <Show when={displayAddresses().hidden.length > 0}>
<div class="remote-actions" style={{ "justify-content": "flex-start" }}> <div class="remote-address-disclosure" data-expanded={showAllAddresses()}>
<button class="remote-pill" type="button" onClick={() => setShowAllAddresses(!showAllAddresses())}> <button
class="remote-address-disclosure-trigger"
type="button"
onClick={() => setShowAllAddresses(!showAllAddresses())}
aria-expanded={showAllAddresses()}
>
<span class="remote-address-disclosure-label">
{showAllAddresses() {showAllAddresses()
? t("remoteAccess.addresses.actions.hideOther") ? t("remoteAccess.addresses.actions.hideOther")
: t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })} : t("remoteAccess.addresses.actions.showOther", { count: String(displayAddresses().hidden.length) })}
</span>
<ChevronDown class={`remote-address-disclosure-chevron ${showAllAddresses() ? "is-expanded" : ""}`} />
</button> </button>
</div>
</Show>
<Show when={showAllAddresses()}> <Show when={showAllAddresses()}>
<div class="remote-address-disclosure-content">
<For each={displayAddresses().hidden}> <For each={displayAddresses().hidden}>
{(address) => { {(address) => {
const url = address.remoteUrl const url = address.remoteUrl
@@ -461,6 +468,9 @@ export const RemoteAccessSettingsSection: Component = () => {
) )
}} }}
</For> </For>
</div>
</Show>
</div>
</Show> </Show>
</div> </div>
</Show> </Show>

View File

@@ -256,6 +256,55 @@
cursor: pointer; 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 { .remote-qr {
margin-top: 12px; margin-top: 12px;
display: flex; display: flex;