From 4c62ea53c5ac870a4269aaa72f50ede5f7f113ee Mon Sep 17 00:00:00 2001 From: Timo Date: Wed, 30 Apr 2025 15:15:15 +0200 Subject: [PATCH 01/10] sidebar component: removes pseudo marker --- pkgs/webview-ui/app/src/index.css | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkgs/webview-ui/app/src/index.css b/pkgs/webview-ui/app/src/index.css index d19164796..56279bebd 100644 --- a/pkgs/webview-ui/app/src/index.css +++ b/pkgs/webview-ui/app/src/index.css @@ -96,7 +96,15 @@ html { cursor: pointer; } -.accordeon__header::-webkit-details-marker { +summary { + list-style: none; +} + +summary::-webkit-details-marker { + display: none; +} + +summary::marker { display: none; } From 8f2794993ddabbfd394ed1dec326db420019f598 Mon Sep 17 00:00:00 2001 From: Timo Date: Wed, 30 Apr 2025 15:40:58 +0200 Subject: [PATCH 02/10] button component: introduces button-ghost dedicated styles --- .../app/src/components/button/css/button-ghost.css | 11 +++++++++++ .../app/src/components/button/css/index.css | 1 + pkgs/webview-ui/app/src/components/button/index.tsx | 7 +++---- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 pkgs/webview-ui/app/src/components/button/css/button-ghost.css diff --git a/pkgs/webview-ui/app/src/components/button/css/button-ghost.css b/pkgs/webview-ui/app/src/components/button/css/button-ghost.css new file mode 100644 index 000000000..cee0cdb14 --- /dev/null +++ b/pkgs/webview-ui/app/src/components/button/css/button-ghost.css @@ -0,0 +1,11 @@ +.button--ghost-hover:hover { + @apply hover:bg-secondary-100 hover:text-secondary-900; +} + +.button--ghost-focus:focus { + @apply focus:bg-secondary-200 focus:text-secondary-900; +} + +.button--ghost-active:active { + @apply active:bg-secondary-200 active:text-secondary-900 active:shadow-inner-primary-active; +} diff --git a/pkgs/webview-ui/app/src/components/button/css/index.css b/pkgs/webview-ui/app/src/components/button/css/index.css index 33f69a263..56cdc308b 100644 --- a/pkgs/webview-ui/app/src/components/button/css/index.css +++ b/pkgs/webview-ui/app/src/components/button/css/index.css @@ -1,5 +1,6 @@ @import "./button-light.css"; @import "./button-dark.css"; +@import "./button-ghost.css"; .button { @apply inline-flex items-center flex-shrink gap-1 justify-center p-4 font-semibold; diff --git a/pkgs/webview-ui/app/src/components/button/index.tsx b/pkgs/webview-ui/app/src/components/button/index.tsx index 87756ad47..675197984 100644 --- a/pkgs/webview-ui/app/src/components/button/index.tsx +++ b/pkgs/webview-ui/app/src/components/button/index.tsx @@ -26,10 +26,9 @@ const variantColors: ( !disabled && "button--light-active", // Active state ), ghost: cx( - // "shadow-inner-secondary", - !disabled && "hover:bg-secondary-200 hover:text-secondary-900", // Hover state - !disabled && "focus:bg-secondary-200 focus:text-secondary-900", // Focus state - !disabled && "button--light-active", // Active state + !disabled && "button--ghost-hover", // Hover state + !disabled && "button--ghost-focus", // Focus state + !disabled && "button--ghost-active", // Active state ), }); From 9c0937580562421443e243be245edd837af3c788 Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 6 May 2025 07:51:27 +0200 Subject: [PATCH 03/10] machine-item: updates design and unifies --- .../app/src/components/MachineListItem.tsx | 224 ------------------ .../app/src/components/Typography/index.tsx | 1 - .../machine-list-item/css/index.css | 77 ++++++ .../components/machine-list-item/index.tsx | 135 +++++++++++ .../app/src/routes/machines/list.tsx | 19 +- .../app/src/routes/modules/list.tsx | 2 +- 6 files changed, 217 insertions(+), 241 deletions(-) delete mode 100644 pkgs/webview-ui/app/src/components/MachineListItem.tsx create mode 100644 pkgs/webview-ui/app/src/components/machine-list-item/css/index.css create mode 100644 pkgs/webview-ui/app/src/components/machine-list-item/index.tsx diff --git a/pkgs/webview-ui/app/src/components/MachineListItem.tsx b/pkgs/webview-ui/app/src/components/MachineListItem.tsx deleted file mode 100644 index c4f67a3b7..000000000 --- a/pkgs/webview-ui/app/src/components/MachineListItem.tsx +++ /dev/null @@ -1,224 +0,0 @@ -import { createSignal, For, Setter, Show } from "solid-js"; -import { callApi, SuccessQuery } from "../api"; -import { Menu } from "./Menu"; -import { activeURI } from "../App"; -import toast from "solid-toast"; -import { A, useNavigate } from "@solidjs/router"; -import { RndThumbnail } from "./noiseThumbnail"; -import Icon from "./icon"; -import { Filter } from "../routes/machines"; -import { Typography } from "./Typography"; -import { Button } from "./button"; - -type MachineDetails = SuccessQuery<"list_machines">["data"][string]; - -interface MachineListItemProps { - name: string; - info?: MachineDetails; - nixOnly?: boolean; - setFilter: Setter; -} - -export const MachineListItem = (props: MachineListItemProps) => { - const { name, info, nixOnly } = props; - - // Bootstrapping - const [installing, setInstalling] = createSignal(false); - - // Later only updates - const [updating, setUpdating] = createSignal(false); - - const navigate = useNavigate(); - - const handleInstall = async () => { - if (!info?.deploy?.targetHost || installing()) { - return; - } - - const active_clan = activeURI(); - if (!active_clan) { - toast.error("No active clan selected"); - return; - } - if (!info?.deploy?.targetHost) { - toast.error( - "Machine does not have a target host. Specify where the machine should be deployed.", - ); - return; - } - setInstalling(true); - await toast.promise( - callApi("install_machine", { - opts: { - machine: { - name: name, - flake: { - identifier: active_clan, - }, - override_target_host: info?.deploy.targetHost, - }, - no_reboot: true, - debug: true, - nix_options: [], - password: null, - }, - }), - { - loading: "Installing...", - success: "Installed", - error: "Failed to install", - }, - ); - setInstalling(false); - }; - - const handleUpdate = async () => { - if (!info?.deploy?.targetHost || installing()) { - return; - } - - const active_clan = activeURI(); - if (!active_clan) { - toast.error("No active clan selected"); - return; - } - if (!info?.deploy.targetHost) { - toast.error( - "Machine does not have a target host. Specify where the machine should be deployed.", - ); - return; - } - setUpdating(true); - await toast.promise( - callApi("update_machines", { - base_path: active_clan, - machines: [ - { - name: name, - deploy: { - targetHost: info?.deploy.targetHost, - }, - }, - ], - }), - { - loading: "Updating...", - success: "Updated", - error: "Failed to update", - }, - ); - setUpdating(false); - }; - return ( -
-
- -
-
-
- - - {name} - - -
-
- - - - - - {(d) => d()?.description || "no description"} - - -
- -
- } - > -
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
- {/*
- - {(d) => ( - <> - - {(tags) => ( - - - {(tag) => ( - - )} - - - )} - - {d()?.deploy?.targetHost} - - )} - -
*/} -
-
-
- ); -}; diff --git a/pkgs/webview-ui/app/src/components/Typography/index.tsx b/pkgs/webview-ui/app/src/components/Typography/index.tsx index fcc829ab0..e55991473 100644 --- a/pkgs/webview-ui/app/src/components/Typography/index.tsx +++ b/pkgs/webview-ui/app/src/components/Typography/index.tsx @@ -84,7 +84,6 @@ interface _TypographyProps { inverted?: boolean; tag?: Tag; class?: string; - classList?: Record; } export const Typography = (props: _TypographyProps) => { diff --git a/pkgs/webview-ui/app/src/components/machine-list-item/css/index.css b/pkgs/webview-ui/app/src/components/machine-list-item/css/index.css new file mode 100644 index 000000000..341b601cf --- /dev/null +++ b/pkgs/webview-ui/app/src/components/machine-list-item/css/index.css @@ -0,0 +1,77 @@ +.machine-item { + @apply col-span-1 flex flex-col items-center; + + position: relative; + padding: theme(padding.2); + + cursor: pointer; +} + +.machine-item__thumb-wrapper { + position: relative; + padding: theme(padding.4); + + border-radius: theme(borderRadius.md); + overflow: hidden; +} + +.machine-item__thumb { + @apply rounded-md bg-secondary-100; + + position: relative; + z-index: 20; + overflow: hidden; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); + + transition: transform 0.24s ease-in-out; +} + +.machine-item__header { + @apply flex flex-col justify-center items-center; + + position: relative; + z-index: 20; + + transition: transform 0.18s 0.04s ease-in-out; +} + +.machine-item__pseudo { + @apply bg-secondary-50; + + position: absolute; + z-index: 10; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 1px solid theme(borderColor.secondary.100); + border-radius: theme(borderRadius.md); + + transition: + transform 0.16s ease-in-out, + opacity 0.08s ease-in-out; +} + +.machine-item:hover { + & .machine-item__pseudo { + transform: scale(1); + opacity: 1; + } + + & .machine-item__thumb { + transform: scale(1.02); + box-shadow: + 0 4px 6px rgba(0, 0, 0, 0.1), + 0 8px 20px rgba(0, 0, 0, 0.15), + 0 12px 40px rgba(0, 0, 0, 0.08); + } + + & .machine-item__header { + transform: translateY(4px); + } +} + +.machine-item:not(:hover) .machine-item__pseudo { + transform: scale(0.94); + opacity: 0; +} diff --git a/pkgs/webview-ui/app/src/components/machine-list-item/index.tsx b/pkgs/webview-ui/app/src/components/machine-list-item/index.tsx new file mode 100644 index 000000000..38b1d122c --- /dev/null +++ b/pkgs/webview-ui/app/src/components/machine-list-item/index.tsx @@ -0,0 +1,135 @@ +import { createSignal, For, Setter, Show } from "solid-js"; +import { callApi, SuccessQuery } from "../../api"; + +import { activeURI } from "../../App"; +import toast from "solid-toast"; +import { A, useNavigate } from "@solidjs/router"; +import { RndThumbnail } from "../noiseThumbnail"; + +import { Filter } from "../../routes/machines"; +import { Typography } from "../Typography"; +import "./css/index.css"; + +type MachineDetails = SuccessQuery<"list_machines">["data"][string]; + +interface MachineListItemProps { + name: string; + info?: MachineDetails; + nixOnly?: boolean; + setFilter: Setter; +} + +export const MachineListItem = (props: MachineListItemProps) => { + const { name, info, nixOnly } = props; + + // Bootstrapping + const [installing, setInstalling] = createSignal(false); + + // Later only updates + const [updating, setUpdating] = createSignal(false); + + const navigate = useNavigate(); + + const handleInstall = async () => { + if (!info?.deploy?.targetHost || installing()) { + return; + } + + const active_clan = activeURI(); + if (!active_clan) { + toast.error("No active clan selected"); + return; + } + if (!info?.deploy?.targetHost) { + toast.error( + "Machine does not have a target host. Specify where the machine should be deployed.", + ); + return; + } + setInstalling(true); + await toast.promise( + callApi("install_machine", { + opts: { + machine: { + name: name, + flake: { + identifier: active_clan, + }, + override_target_host: info?.deploy.targetHost, + }, + no_reboot: true, + debug: true, + nix_options: [], + password: null, + }, + }), + { + loading: "Installing...", + success: "Installed", + error: "Failed to install", + }, + ); + setInstalling(false); + }; + + const handleUpdate = async () => { + if (!info?.deploy?.targetHost || installing()) { + return; + } + + const active_clan = activeURI(); + if (!active_clan) { + toast.error("No active clan selected"); + return; + } + if (!info?.deploy.targetHost) { + toast.error( + "Machine does not have a target host. Specify where the machine should be deployed.", + ); + return; + } + setUpdating(true); + await toast.promise( + callApi("update_machines", { + base_path: active_clan, + machines: [ + { + name: name, + deploy: { + targetHost: info?.deploy.targetHost, + }, + }, + ], + }), + { + loading: "Updating...", + success: "Updated", + error: "Failed to update", + }, + ); + setUpdating(false); + }; + return ( +
+ + + ); +}; diff --git a/pkgs/webview-ui/app/src/routes/machines/list.tsx b/pkgs/webview-ui/app/src/routes/machines/list.tsx index 903954fd0..3d211003b 100644 --- a/pkgs/webview-ui/app/src/routes/machines/list.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/list.tsx @@ -9,7 +9,7 @@ import { import { activeURI } from "@/src/App"; import { callApi, OperationResponse } from "@/src/api"; import toast from "solid-toast"; -import { MachineListItem } from "@/src/components/MachineListItem"; +import { MachineListItem } from "@/src/components/machine-list-item"; import { createQuery, useQueryClient } from "@tanstack/solid-query"; import { useNavigate } from "@solidjs/router"; import { Button } from "@/src/components/button"; @@ -114,16 +114,6 @@ export const MachineListView: Component = () => { />
-
-
- -
-
{(tag) => (
- {/* */} {/* Loading skeleton */} @@ -180,10 +169,10 @@ export const MachineListView: Component = () => {
diff --git a/pkgs/webview-ui/app/src/routes/modules/list.tsx b/pkgs/webview-ui/app/src/routes/modules/list.tsx index 9bf0c035f..ddb627810 100644 --- a/pkgs/webview-ui/app/src/routes/modules/list.tsx +++ b/pkgs/webview-ui/app/src/routes/modules/list.tsx @@ -121,7 +121,7 @@ export const ModuleList = () => { return ( <>
*/} +
+ {/* + Installs the system for the first time. Used to bootstrap the + remote device. + */} +
+
+
+ + +
+
+ {/* + Update the system if changes should be synced after the + installation process. + */} +
+
+
+ + + + +
+ {(field, props) => ( { /> )} -
- + + {(field, props) => ( + + )} + + + {(field, props) => ( +
+ + Tags{" "} + + + {(tag) => ( + + + {tag} + + + )} + +
+ )} +
+ - { -
+
+ + {(field, props) => ( + Hardware Configuration} + field={{field.value || "None"}} + /> + )} + + + {(field, props) => ( + <> + Disk schema} + field={{field.value || "None"}} + /> + + )} + + +
+ +
Connection Settings
+
+ + {(field, props) => ( + + )} + +
+
+
+ +
-
- } - - - -
-
- - Actions -
- - Installs the system for the first time. Used to bootstrap the remote - device. - -
- -
- - setInstallModalOpen(false)} - class="min-w-[600px]" - > - - - - - Update the system if changes should be synced after the installation - process. - -
- -
+ +
+ + setInstallModalOpen(false)} + class="min-w-[600px]" + > + + ); }; From 067e5936cc37152f3a1676eb43d58cae4dd8bdfe Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 6 May 2025 12:40:22 +0200 Subject: [PATCH 06/10] tailwind: updates color values --- .../app/src/routes/machines/details.tsx | 18 ++++++++------- pkgs/webview-ui/app/tailwind/core-plugin.ts | 22 +++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/pkgs/webview-ui/app/src/routes/machines/details.tsx b/pkgs/webview-ui/app/src/routes/machines/details.tsx index 2e5786c0e..2143e4355 100644 --- a/pkgs/webview-ui/app/src/routes/machines/details.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/details.tsx @@ -667,14 +667,16 @@ const MachineForm = (props: MachineDetailsProps) => { -
- -
+ { +
+ +
+ } diff --git a/pkgs/webview-ui/app/tailwind/core-plugin.ts b/pkgs/webview-ui/app/tailwind/core-plugin.ts index 9965d8935..d61d283fb 100644 --- a/pkgs/webview-ui/app/tailwind/core-plugin.ts +++ b/pkgs/webview-ui/app/tailwind/core-plugin.ts @@ -240,17 +240,17 @@ export default plugin.withOptions( 950: toRGB("#162324"), }, secondary: { - 50: toRGB("#f7f9f9"), - 100: toRGB("#e7f2f4"), - 200: toRGB("#d7e8ea"), - 300: toRGB("#afc6ca"), - 400: toRGB("#8fb2b6"), - 500: toRGB("#7b9a9e"), - 600: toRGB("#4f747a"), - 700: toRGB("#415e63"), - 800: toRGB("#445f64"), - 900: toRGB("#2b4347"), - 950: toRGB("#0d1415"), + 50: toRGB("#F7F9FA"), + 100: toRGB("#E7F2F4"), + 200: toRGB("#D8E8EB"), + 300: toRGB("#AFC6CA"), + 400: toRGB("#90B2B7"), + 500: toRGB("#7B9B9F"), + 600: toRGB("#4F747A"), + 700: toRGB("#415E63"), + 800: toRGB("#446065"), + 900: toRGB("#2C4347"), + 950: toRGB("#0D1416"), }, info: { 50: toRGB("#eff9ff"), From 69d61abc916a6bc9a5f58bb413ee628ca1056297 Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 6 May 2025 14:33:38 +0200 Subject: [PATCH 07/10] flash install: fixes form layout --- .../webview-ui/app/src/Form/fields/Select.tsx | 154 +++++++------- .../webview-ui/app/src/Form/fields/layout.tsx | 2 +- .../app/src/components/accordion/index.tsx | 4 +- pkgs/webview-ui/app/src/routes/flash/view.tsx | 197 ++++++------------ .../app/src/routes/machines/create.tsx | 1 - .../app/src/routes/machines/details.tsx | 52 ++--- 6 files changed, 169 insertions(+), 241 deletions(-) diff --git a/pkgs/webview-ui/app/src/Form/fields/Select.tsx b/pkgs/webview-ui/app/src/Form/fields/Select.tsx index dc8a5339e..fe09de191 100644 --- a/pkgs/webview-ui/app/src/Form/fields/Select.tsx +++ b/pkgs/webview-ui/app/src/Form/fields/Select.tsx @@ -142,91 +142,87 @@ export function SelectInput(props: SelectInputpProps) { } field={ - <> - { - const popover = document.getElementById(_id); - if (popover) { - popover.togglePopover(); // Show or hide the popover - } - }} - type="button" - class="flex w-full items-center gap-2" - formnovalidate - // TODO: Use native popover once Webkit supports it within
- // popovertarget={_id} - // popovertargetaction="toggle" + { + const popover = document.getElementById(_id); + if (popover) { + popover.togglePopover(); // Show or hide the popover + } + }} + type="button" + class="flex w-full items-center gap-2" + formnovalidate + // TODO: Use native popover once Webkit supports it within + // popovertarget={_id} + // popovertargetaction="toggle" + > + + {props.adornment?.content} + + {props.inlineLabel} +
- {props.adornment?.content} + + {(item) => ( +
+ {item} + + + +
+ )} +
- {props.inlineLabel} -
- - - {(item) => ( -
- {item} - - - -
- )} -
-
-
- - {props.adornment?.content} - - - - } - /> - +
+ + {props.adornment?.content} + + + + } + /> } /> diff --git a/pkgs/webview-ui/app/src/Form/fields/layout.tsx b/pkgs/webview-ui/app/src/Form/fields/layout.tsx index 1a30e3f57..32d4a8888 100644 --- a/pkgs/webview-ui/app/src/Form/fields/layout.tsx +++ b/pkgs/webview-ui/app/src/Form/fields/layout.tsx @@ -18,7 +18,7 @@ export const FieldLayout = (props: LayoutProps) => { class={cx("grid grid-cols-10 items-center", intern.class)} {...divProps} > - +
{props.label}
{props.field}
{props.error && {props.error}} diff --git a/pkgs/webview-ui/app/src/components/accordion/index.tsx b/pkgs/webview-ui/app/src/components/accordion/index.tsx index ddfd445bb..8d4ba9bb1 100644 --- a/pkgs/webview-ui/app/src/components/accordion/index.tsx +++ b/pkgs/webview-ui/app/src/components/accordion/index.tsx @@ -21,7 +21,7 @@ export default function Accordion(props: AccordionProps) { fallback={ - + } /> - - {(network, index) => ( -
-
- - {(field, props) => ( - - )} - - - {(field, props) => ( - - // togglePasswordVisibility(index()) - // } - // startIcon={ - // passwordVisibility()[index()] ? ( - // - // ) : ( - // - // ) - // } - // > - // ), - // }} - required - /> - )} - -
- -
- )} -
- + -
- -
- Advanced -
-
+ +
{ )} -
-
- -
+ +
@@ -559,7 +560,7 @@ const MachineForm = (props: MachineDetailsProps) => { class="w-full" size="s" onClick={() => handleUpdate()} - endIcon={} + endIcon={} > Update @@ -636,6 +637,7 @@ const MachineForm = (props: MachineDetailsProps) => { /> )} +
{(field, props) => ( <> @@ -646,27 +648,25 @@ const MachineForm = (props: MachineDetailsProps) => { )} - -
- -
Connection Settings
-
- - {(field, props) => ( - - )} - -
-
+ +
+ + {(field, props) => ( + + )} + +
+
+ {
-
+