From 431e45cc3a1e88cc6d789a05b6e57f16b94ac7d1 Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Fri, 22 Aug 2025 15:58:14 +0100 Subject: [PATCH 1/2] feat(ui): support editing basic metadata for a Clan --- .../ui/src/components/Modal/Modal.tsx | 81 +++++---- .../src/components/Sidebar/SidebarHeader.tsx | 31 ++-- pkgs/clan-app/ui/src/hooks/queries.ts | 84 ++++++--- .../ClanSettingsModal.module.css | 7 + .../ClanSettingsModal.stories.tsx | 38 ++++ .../ClanSettingsModal/ClanSettingsModal.tsx | 170 ++++++++++++++++++ .../modals/ListClansModal/ListClansModal.tsx | 4 +- pkgs/clan-app/ui/src/routes/Clan/Clan.tsx | 18 +- pkgs/clan-cli/clan_lib/clan/get.py | 31 ++++ 9 files changed, 388 insertions(+), 76 deletions(-) create mode 100644 pkgs/clan-app/ui/src/modals/ClanSettingsModal/ClanSettingsModal.module.css create mode 100644 pkgs/clan-app/ui/src/modals/ClanSettingsModal/ClanSettingsModal.stories.tsx create mode 100644 pkgs/clan-app/ui/src/modals/ClanSettingsModal/ClanSettingsModal.tsx diff --git a/pkgs/clan-app/ui/src/components/Modal/Modal.tsx b/pkgs/clan-app/ui/src/components/Modal/Modal.tsx index e69089fb1..12c54a133 100644 --- a/pkgs/clan-app/ui/src/components/Modal/Modal.tsx +++ b/pkgs/clan-app/ui/src/components/Modal/Modal.tsx @@ -5,6 +5,7 @@ import { createContext, createSignal, useContext, + ParentComponent, } from "solid-js"; import { Dialog as KDialog } from "@kobalte/core/dialog"; import styles from "./Modal.module.css"; @@ -27,6 +28,10 @@ export const useModalContext = () => { return context as ModalContextType; }; +const defaultContentWrapper: ParentComponent = (props): JSX.Element => ( + <>{props.children} +); + export interface ModalProps { id?: string; title: string; @@ -35,12 +40,18 @@ export interface ModalProps { mount?: Node; class?: string; metaHeader?: Component; + wrapContent?: ParentComponent; disablePadding?: boolean; open: boolean; } export const Modal = (props: ModalProps) => { const [portalRef, setPortalRef] = createSignal(); + + // allows wrapping the dialog content in a component + // useful with forms where the submit button is in the header + const contentWrapper: Component = props.wrapContent || defaultContentWrapper; + return ( @@ -48,40 +59,48 @@ export const Modal = (props: ModalProps) => {
-
- - {props.title} - - - - - - -
- - {(metaHeader) => ( + {contentWrapper({ + children: ( <> -
- +
+ + {props.title} + + + + + + +
+ + {(metaHeader) => ( + <> +
+ +
+
+ + )} + +
+ + {props.children} +
-
- )} - -
- - {props.children} - -
+ ), + })}
diff --git a/pkgs/clan-app/ui/src/components/Sidebar/SidebarHeader.tsx b/pkgs/clan-app/ui/src/components/Sidebar/SidebarHeader.tsx index 8d757d1b8..99a287c75 100644 --- a/pkgs/clan-app/ui/src/components/Sidebar/SidebarHeader.tsx +++ b/pkgs/clan-app/ui/src/components/Sidebar/SidebarHeader.tsx @@ -3,20 +3,18 @@ import Icon from "@/src/components/Icon/Icon"; import { DropdownMenu } from "@kobalte/core/dropdown-menu"; import { useNavigate } from "@solidjs/router"; import { Typography } from "../Typography/Typography"; -import { createSignal, For, Suspense, useContext } from "solid-js"; -import { - navigateToClan, - navigateToOnboarding, - useClanURI, -} from "@/src/hooks/clan"; +import { createSignal, For, Show, Suspense, useContext } from "solid-js"; +import { navigateToOnboarding } from "@/src/hooks/clan"; import { setActiveClanURI } from "@/src/stores/clan"; import { Button } from "../Button/Button"; import { ClanContext } from "@/src/routes/Clan/Clan"; +import { ClanSettingsModal } from "@/src/modals/ClanSettingsModal/ClanSettingsModal"; export const SidebarHeader = () => { const navigate = useNavigate(); const [open, setOpen] = createSignal(false); + const [showSettings, setShowSettings] = createSignal(false); // get information about the current active clan const ctx = useContext(ClanContext); @@ -25,20 +23,27 @@ export const SidebarHeader = () => { throw new Error("SidebarContext not found"); } - const clanURI = useClanURI(); - const clanChar = () => - ctx?.activeClanQuery?.data?.name.charAt(0).toUpperCase(); - const clanName = () => ctx?.activeClanQuery?.data?.name; + ctx?.activeClanQuery?.data?.details.name.charAt(0).toUpperCase(); + const clanName = () => ctx?.activeClanQuery?.data?.details.name; const clanList = () => ctx.allClansQueries .filter((it) => it.isSuccess) .map((it) => it.data!) - .sort((a, b) => a.name.localeCompare(b.name)); + .sort((a, b) => a.details.name.localeCompare(b.details.name)); return (