Merge pull request 'ui: use css modules for sidebar components' (#5217) from hgl into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5217 Reviewed-by: brianmcgee <brian@bmcgee.ie>
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import "./Divider.css";
|
||||
import styles from "./Divider.module.css";
|
||||
import cx from "classnames";
|
||||
import { Separator, SeparatorRootProps } from "@kobalte/core/separator";
|
||||
|
||||
export interface DividerProps extends Pick<SeparatorRootProps, "orientation"> {
|
||||
inverted?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export const Divider = (props: DividerProps) => {
|
||||
@@ -12,7 +11,7 @@ export const Divider = (props: DividerProps) => {
|
||||
|
||||
return (
|
||||
<Separator
|
||||
class={cx({ inverted: inverted }, props?.class)}
|
||||
class={cx({ [styles.inverted]: inverted })}
|
||||
orientation={props.orientation}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
div.sidebar-header {
|
||||
@apply flex items-center justify-center w-full px-1 py-1;
|
||||
@apply border border-inv-3 rounded-md rounded-bl-none rounded-br-none;
|
||||
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
theme(colors.bg.inv.2) 0%,
|
||||
theme(colors.bg.inv.3) 0%
|
||||
);
|
||||
|
||||
& > .dropdown-trigger {
|
||||
@apply flex items-center justify-between flex-grow px-1 py-1;
|
||||
@apply rounded-tl-md rounded-tr-md;
|
||||
@apply border border-transparent border-b-0;
|
||||
|
||||
transition: all 250ms ease-in-out;
|
||||
|
||||
div.clan-label {
|
||||
@apply flex items-center gap-2 justify-start;
|
||||
|
||||
& > .clan-icon {
|
||||
@apply flex justify-center items-center;
|
||||
@apply rounded-full bg-inv-4 w-7 h-7;
|
||||
}
|
||||
}
|
||||
|
||||
.icon[data-icon-name="CaretDown"] {
|
||||
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
}
|
||||
|
||||
&[data-expanded] {
|
||||
@apply bg-def-1 border-def-2;
|
||||
|
||||
.icon[data-icon-name="CaretDown"] {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-dropdown-content {
|
||||
@apply flex flex-col w-full px-2 py-1.5 z-10 gap-3;
|
||||
@apply bg-def-1 rounded-bl-md rounded-br-md;
|
||||
@apply border border-def-2;
|
||||
|
||||
animation: sidebarNavContentHide 250ms ease-in forwards;
|
||||
|
||||
.dropdown-item {
|
||||
@apply flex items-center justify-start w-full px-1.5 py-2 gap-2 rounded;
|
||||
|
||||
&:hover {
|
||||
@apply bg-def-acc-2 cursor-pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-group {
|
||||
@apply flex flex-col gap-2;
|
||||
@apply px-1;
|
||||
|
||||
.dropdown-group-label {
|
||||
@apply flex items-baseline justify-between w-full;
|
||||
}
|
||||
|
||||
.dropdown-group-items {
|
||||
@apply rounded px-1 py-1.5 bg-def-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-dropdown-content[data-expanded] {
|
||||
animation: sidebarNavContentShow 250ms ease-out;
|
||||
}
|
||||
|
||||
@keyframes sidebarNavContentShow {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@keyframes sidebarNavContentHide {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
.sidebarHeader {
|
||||
@apply flex items-center justify-center w-full px-1 py-1;
|
||||
@apply border border-inv-3 rounded-md rounded-bl-none rounded-br-none;
|
||||
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
theme(colors.bg.inv.2) 0%,
|
||||
theme(colors.bg.inv.3) 0%
|
||||
);
|
||||
}
|
||||
|
||||
.dropDownTrigger {
|
||||
@apply flex items-center justify-between flex-grow px-1 py-1;
|
||||
@apply rounded-tl-md rounded-tr-md;
|
||||
@apply border border-transparent border-b-0;
|
||||
|
||||
transition: all 250ms ease-in-out;
|
||||
|
||||
.icon[data-icon-name="CaretDown"] {
|
||||
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
}
|
||||
|
||||
&[data-expanded] {
|
||||
@apply bg-def-1 border-def-2;
|
||||
|
||||
.icon[data-icon-name="CaretDown"] {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.clanLabel {
|
||||
@apply flex items-center gap-2 justify-start;
|
||||
}
|
||||
.clanIcon {
|
||||
@apply flex justify-center items-center;
|
||||
@apply rounded-full bg-inv-4 w-7 h-7;
|
||||
}
|
||||
|
||||
.dropDownContent {
|
||||
@apply flex flex-col w-full px-2 py-1.5 z-10 gap-3;
|
||||
@apply bg-def-1 rounded-bl-md rounded-br-md;
|
||||
@apply border border-def-2;
|
||||
|
||||
animation: sidebarNavContentHide 250ms ease-in forwards;
|
||||
}
|
||||
.dropDownContent[data-expanded] {
|
||||
animation: sidebarNavContentShow 250ms ease-out;
|
||||
}
|
||||
|
||||
.dropdownItem {
|
||||
@apply flex items-center justify-start w-full px-1.5 py-2 gap-2 rounded;
|
||||
|
||||
&:hover {
|
||||
@apply bg-def-acc-2 cursor-pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdownGroup {
|
||||
@apply flex flex-col gap-2;
|
||||
@apply px-1;
|
||||
}
|
||||
.dropdownGroupLabel {
|
||||
@apply flex items-baseline justify-between w-full;
|
||||
}
|
||||
.dropdownGroupItems {
|
||||
@apply rounded px-1 py-1.5 bg-def-2;
|
||||
}
|
||||
|
||||
@keyframes sidebarNavContentShow {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@keyframes sidebarNavContentHide {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import "./SidebarHeader.css";
|
||||
import styles from "./SidebarHeader.module.css";
|
||||
import Icon from "@/src/components/Icon/Icon";
|
||||
import { DropdownMenu } from "@kobalte/core/dropdown-menu";
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
@@ -30,7 +30,7 @@ export const SidebarHeader = () => {
|
||||
.sort((a, b) => a.details.name.localeCompare(b.details.name));
|
||||
|
||||
return (
|
||||
<div class="sidebar-header">
|
||||
<div class={styles.sidebarHeader}>
|
||||
<Show when={ctx.activeClanQuery.isSuccess && showSettings()}>
|
||||
<ClanSettingsModal
|
||||
model={ctx.activeClanQuery.data!}
|
||||
@@ -42,9 +42,9 @@ export const SidebarHeader = () => {
|
||||
</Show>
|
||||
<Suspense fallback={"Loading..."}>
|
||||
<DropdownMenu open={open()} onOpenChange={setOpen} sameWidth={true}>
|
||||
<DropdownMenu.Trigger class="dropdown-trigger">
|
||||
<div class="clan-label">
|
||||
<div class="clan-icon">
|
||||
<DropdownMenu.Trigger class={styles.dropDownTrigger}>
|
||||
<div class={styles.clanLabel}>
|
||||
<div class={styles.clanIcon}>
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
size="s"
|
||||
@@ -68,9 +68,9 @@ export const SidebarHeader = () => {
|
||||
</DropdownMenu.Icon>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content class="sidebar-dropdown-content">
|
||||
<DropdownMenu.Content class={styles.dropDownContent}>
|
||||
<DropdownMenu.Item
|
||||
class="dropdown-item"
|
||||
class={styles.dropdownItem}
|
||||
onSelect={() => setShowSettings(true)}
|
||||
>
|
||||
<Icon
|
||||
@@ -83,8 +83,8 @@ export const SidebarHeader = () => {
|
||||
Settings
|
||||
</Typography>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Group class="dropdown-group">
|
||||
<DropdownMenu.GroupLabel class="dropdown-group-label">
|
||||
<DropdownMenu.Group class={styles.dropdownGroup}>
|
||||
<DropdownMenu.GroupLabel class={styles.dropdownGroupLabel}>
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
family="mono"
|
||||
@@ -104,12 +104,12 @@ export const SidebarHeader = () => {
|
||||
Add
|
||||
</Button>
|
||||
</DropdownMenu.GroupLabel>
|
||||
<div class="dropdown-group-items">
|
||||
<div class={styles.dropdownGroupItems}>
|
||||
<For each={clanList()}>
|
||||
{(clan) => (
|
||||
<Suspense fallback={"Loading..."}>
|
||||
<DropdownMenu.Item
|
||||
class="dropdown-item"
|
||||
class={styles.dropdownItem}
|
||||
onSelect={() => {
|
||||
setActiveClanURI(clan.uri);
|
||||
}}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
div.sidebar-pane {
|
||||
@apply flex flex-col border-none z-20 h-full;
|
||||
|
||||
animation: sidebarPaneShow 250ms ease-in forwards;
|
||||
|
||||
&.open {
|
||||
@apply w-72;
|
||||
}
|
||||
|
||||
&.closing {
|
||||
animation: sidebarPaneHide 250ms ease-out 300ms forwards;
|
||||
|
||||
& > div.header > *,
|
||||
& > div.sub-header > *,
|
||||
& > div.body > * {
|
||||
animation: sidebarFadeOut 250ms ease-out forwards;
|
||||
}
|
||||
}
|
||||
|
||||
& > div.header {
|
||||
@apply flex items-center justify-between px-3 py-2 rounded-t-[0.5rem];
|
||||
@apply border-t-[1px] border-t-bg-inv-3
|
||||
border-r-[1px] border-r-bg-inv-3
|
||||
border-b-2 border-b-bg-inv-4
|
||||
border-l-[1px] border-l-bg-inv-3;
|
||||
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
theme(colors.bg.inv.3) 0%,
|
||||
theme(colors.bg.inv.4) 100%
|
||||
);
|
||||
|
||||
& > * {
|
||||
@apply opacity-0;
|
||||
animation: sidebarFadeIn 250ms ease-in 250ms forwards;
|
||||
}
|
||||
}
|
||||
|
||||
& > div.sub-header {
|
||||
@apply px-3 py-1;
|
||||
@apply border-b-[1px] border-b-bg-inv-4;
|
||||
@apply border-r-[1px] border-r-bg-inv-3 border-l-[1px] border-l-bg-inv-3;
|
||||
|
||||
background:
|
||||
linear-gradient(0deg, rgba(0, 0, 0, 0.08) 0%, rgba(0, 0, 0, 0.08) 100%),
|
||||
linear-gradient(
|
||||
90deg,
|
||||
theme(colors.bg.inv.3) 0%,
|
||||
theme(colors.bg.inv.4) 100%
|
||||
);
|
||||
|
||||
& > * {
|
||||
@apply opacity-0;
|
||||
animation: sidebarFadeIn 250ms ease-in 250ms forwards;
|
||||
}
|
||||
}
|
||||
|
||||
& > div.body {
|
||||
@apply flex flex-col gap-4 px-2 pt-4 pb-3 w-full h-full;
|
||||
@apply backdrop-blur-md;
|
||||
@apply rounded-b-[0.5rem]
|
||||
border-r-[1px] border-r-bg-inv-3
|
||||
border-b-2 border-b-bg-inv-4
|
||||
border-l-[1px] border-l-bg-inv-3;
|
||||
|
||||
background:
|
||||
linear-gradient(0deg, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%),
|
||||
linear-gradient(
|
||||
180deg,
|
||||
theme(colors.bg.inv.2) 0%,
|
||||
theme(colors.bg.inv.3) 100%
|
||||
);
|
||||
|
||||
& > * {
|
||||
@apply opacity-0;
|
||||
animation: sidebarFadeIn 250ms ease-in 350ms forwards;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarPaneShow {
|
||||
0% {
|
||||
@apply w-0;
|
||||
@apply opacity-0;
|
||||
}
|
||||
10% {
|
||||
@apply w-8;
|
||||
}
|
||||
30% {
|
||||
@apply opacity-100;
|
||||
}
|
||||
100% {
|
||||
@apply w-72;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarPaneHide {
|
||||
90% {
|
||||
@apply w-8;
|
||||
}
|
||||
100% {
|
||||
@apply w-0;
|
||||
@apply opacity-0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarFadeOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
120
pkgs/clan-app/ui/src/components/Sidebar/SidebarPane.module.css
Normal file
120
pkgs/clan-app/ui/src/components/Sidebar/SidebarPane.module.css
Normal file
@@ -0,0 +1,120 @@
|
||||
.sidebarPane {
|
||||
@apply flex flex-col border-none z-20 h-full;
|
||||
@apply w-72;
|
||||
|
||||
animation: sidebarPaneShow 250ms ease-in forwards;
|
||||
|
||||
&.closing {
|
||||
animation: sidebarPaneHide 250ms ease-out 300ms forwards;
|
||||
|
||||
& > .header > *,
|
||||
& > .subHeader > *,
|
||||
& > .body > * {
|
||||
animation: sidebarFadeOut 250ms ease-out forwards;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply flex items-center justify-between px-3 py-2 rounded-t-[0.5rem];
|
||||
@apply border-t-[1px] border-t-bg-inv-3
|
||||
border-r-[1px] border-r-bg-inv-3
|
||||
border-b-2 border-b-bg-inv-4
|
||||
border-l-[1px] border-l-bg-inv-3;
|
||||
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
theme(colors.bg.inv.3) 0%,
|
||||
theme(colors.bg.inv.4) 100%
|
||||
);
|
||||
|
||||
& > * {
|
||||
@apply opacity-0;
|
||||
animation: sidebarFadeIn 250ms ease-in 250ms forwards;
|
||||
}
|
||||
}
|
||||
|
||||
.subHeader {
|
||||
@apply px-3 py-1;
|
||||
@apply border-b-[1px] border-b-bg-inv-4;
|
||||
@apply border-r-[1px] border-r-bg-inv-3 border-l-[1px] border-l-bg-inv-3;
|
||||
|
||||
background:
|
||||
linear-gradient(0deg, rgba(0, 0, 0, 0.08) 0%, rgba(0, 0, 0, 0.08) 100%),
|
||||
linear-gradient(
|
||||
90deg,
|
||||
theme(colors.bg.inv.3) 0%,
|
||||
theme(colors.bg.inv.4) 100%
|
||||
);
|
||||
|
||||
& > * {
|
||||
@apply opacity-0;
|
||||
animation: sidebarFadeIn 250ms ease-in 250ms forwards;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
@apply flex flex-col gap-4 px-2 pt-4 pb-3 w-full h-full;
|
||||
@apply backdrop-blur-md;
|
||||
@apply rounded-b-[0.5rem]
|
||||
border-r-[1px] border-r-bg-inv-3
|
||||
border-b-2 border-b-bg-inv-4
|
||||
border-l-[1px] border-l-bg-inv-3;
|
||||
|
||||
background:
|
||||
linear-gradient(0deg, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%),
|
||||
linear-gradient(
|
||||
180deg,
|
||||
theme(colors.bg.inv.2) 0%,
|
||||
theme(colors.bg.inv.3) 100%
|
||||
);
|
||||
|
||||
& > * {
|
||||
@apply opacity-0;
|
||||
animation: sidebarFadeIn 250ms ease-in 350ms forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarPaneShow {
|
||||
0% {
|
||||
@apply w-0;
|
||||
@apply opacity-0;
|
||||
}
|
||||
10% {
|
||||
@apply w-8;
|
||||
}
|
||||
30% {
|
||||
@apply opacity-100;
|
||||
}
|
||||
100% {
|
||||
@apply w-72;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarPaneHide {
|
||||
90% {
|
||||
@apply w-8;
|
||||
}
|
||||
100% {
|
||||
@apply w-0;
|
||||
@apply opacity-0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sidebarFadeOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ export const Default: Story = {
|
||||
</Field>
|
||||
)}
|
||||
</SidebarSectionForm>
|
||||
<SidebarSection title="Simple" class="flex flex-col">
|
||||
<SidebarSection title="Simple">
|
||||
<Typography tag="h2" hierarchy="title" size="m" inverted>
|
||||
Static Content
|
||||
</Typography>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { createSignal, JSX, onMount, Show } from "solid-js";
|
||||
import "./SidebarPane.css";
|
||||
import { createSignal, JSX, Show } from "solid-js";
|
||||
import styles from "./SidebarPane.module.css";
|
||||
import { Typography } from "@/src/components/Typography/Typography";
|
||||
import Icon from "../Icon/Icon";
|
||||
import { Button as KButton } from "@kobalte/core/button";
|
||||
import cx from "classnames";
|
||||
|
||||
export interface SidebarPaneProps {
|
||||
class?: string;
|
||||
title: string;
|
||||
onClose: () => void;
|
||||
subHeader?: JSX.Element;
|
||||
@@ -15,26 +14,20 @@ export interface SidebarPaneProps {
|
||||
|
||||
export const SidebarPane = (props: SidebarPaneProps) => {
|
||||
const [closing, setClosing] = createSignal(false);
|
||||
const [open, setOpened] = createSignal(true);
|
||||
|
||||
// FIXME: use animationend event instead of setTimeout
|
||||
const onClose = () => {
|
||||
setClosing(true);
|
||||
setTimeout(() => props.onClose(), 550);
|
||||
};
|
||||
onMount(() => {
|
||||
setTimeout(() => {
|
||||
setOpened(true);
|
||||
}, 250);
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
class={cx("sidebar-pane", props.class, {
|
||||
closing: closing(),
|
||||
open: open(),
|
||||
class={cx(styles.sidebarPane, {
|
||||
[styles.closing]: closing(),
|
||||
})}
|
||||
>
|
||||
<div class="header">
|
||||
<div class={styles.header}>
|
||||
<Typography hierarchy="body" size="s" weight="bold" inverted={true}>
|
||||
{props.title}
|
||||
</Typography>
|
||||
@@ -43,9 +36,9 @@ export const SidebarPane = (props: SidebarPaneProps) => {
|
||||
</KButton>
|
||||
</div>
|
||||
<Show when={props.subHeader}>
|
||||
<div class="sub-header">{props.subHeader}</div>
|
||||
<div class={styles.subHeader}>{props.subHeader}</div>
|
||||
</Show>
|
||||
<div class="body">{props.children}</div>
|
||||
<div class={styles.body}>{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
div.sidebar-section {
|
||||
@apply flex flex-col gap-2 w-full h-full;
|
||||
|
||||
& > div.header {
|
||||
@apply flex items-center justify-between px-1.5;
|
||||
|
||||
& > div.controls {
|
||||
@apply flex items-center justify-end;
|
||||
}
|
||||
}
|
||||
|
||||
& > div.content {
|
||||
@apply w-full h-fit px-1.5 py-3 rounded-md bg-inv-4;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
.sidebarSection {
|
||||
@apply flex flex-col gap-2 w-full h-full;
|
||||
}
|
||||
.header {
|
||||
@apply flex items-center justify-between px-1.5;
|
||||
}
|
||||
.controls {
|
||||
@apply flex items-center justify-end h-4;
|
||||
}
|
||||
.content {
|
||||
@apply w-full h-fit px-1.5 py-3 rounded-md bg-inv-4;
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
import { JSX } from "solid-js";
|
||||
import "./SidebarSection.css";
|
||||
import { JSX, Show } from "solid-js";
|
||||
import styles from "./SidebarSection.module.css";
|
||||
import { Typography } from "@/src/components/Typography/Typography";
|
||||
import cx from "classnames";
|
||||
|
||||
export interface SidebarSectionProps {
|
||||
title: string;
|
||||
class?: string;
|
||||
controls?: JSX.Element;
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
export const SidebarSection = (props: SidebarSectionProps) => {
|
||||
return (
|
||||
<div class={cx("sidebar-section", props.class)}>
|
||||
<div class="header">
|
||||
<div class={styles.sidebarSection}>
|
||||
<div class={styles.header}>
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
size="xs"
|
||||
@@ -23,8 +22,11 @@ export const SidebarSection = (props: SidebarSectionProps) => {
|
||||
>
|
||||
{props.title}
|
||||
</Typography>
|
||||
<Show when={props.controls}>
|
||||
<div class={styles.controls}>{props.controls}</div>
|
||||
</Show>
|
||||
</div>
|
||||
<div class="content">{props.children}</div>
|
||||
<div class={styles.content}>{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,8 +15,8 @@ import { GenericSchema, GenericSchemaAsync } from "valibot";
|
||||
import { Typography } from "@/src/components/Typography/Typography";
|
||||
import { Button } from "@/src/components/Button/Button";
|
||||
|
||||
import "./SidebarSection.css";
|
||||
import { Loader } from "../../components/Loader/Loader";
|
||||
import { SidebarSection } from "./SidebarSection";
|
||||
|
||||
export interface SidebarSectionFormProps<FormValues extends FieldValues> {
|
||||
title: string;
|
||||
@@ -71,31 +71,24 @@ export function SidebarSectionForm<
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<div class="sidebar-section">
|
||||
<div class="header">
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
size="xs"
|
||||
family="mono"
|
||||
transform="uppercase"
|
||||
color="tertiary"
|
||||
inverted
|
||||
>
|
||||
{props.title}
|
||||
</Typography>
|
||||
<div class="controls h-4">
|
||||
{editing() && !formStore.submitting && (
|
||||
<Button
|
||||
hierarchy="primary"
|
||||
size="xs"
|
||||
icon="Checkmark"
|
||||
ghost
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
{editing() && formStore.submitting && <Loader />}
|
||||
<SidebarSection
|
||||
title={props.title}
|
||||
controls={
|
||||
<>
|
||||
{editing() &&
|
||||
(formStore.submitting ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<Button
|
||||
hierarchy="primary"
|
||||
size="xs"
|
||||
icon="Checkmark"
|
||||
ghost
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
hierarchy="primary"
|
||||
ghost
|
||||
@@ -103,19 +96,18 @@ export function SidebarSectionForm<
|
||||
icon={editing() ? "Close" : "Edit"}
|
||||
onClick={editOrClose}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Show when={editing() && formStore.dirty && errorMessage()}>
|
||||
<div class="mb-2.5" role="alert" aria-live="assertive">
|
||||
<Typography hierarchy="body" size="xs" inverted color="error">
|
||||
{errorMessage()}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<Show when={editing() && formStore.dirty && errorMessage()}>
|
||||
<div class="mb-2.5" role="alert" aria-live="assertive">
|
||||
<Typography hierarchy="body" size="xs" inverted color="error">
|
||||
{errorMessage()}
|
||||
</Typography>
|
||||
</div>
|
||||
</Show>
|
||||
{props.children({ editing: editing(), Field, formStore })}
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
{props.children({ editing: editing(), Field, formStore })}
|
||||
</SidebarSection>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user