ui: use css modules for Typography and SidebarBody
Extra changes: - Add missing transition to according triggers in SidebarBody - More sensible tag for each Typography hierarchy
This commit is contained in:
@@ -125,10 +125,6 @@
|
||||
&.loading {
|
||||
@apply cursor-wait;
|
||||
}
|
||||
|
||||
& > .typography {
|
||||
@apply max-w-full overflow-hidden whitespace-nowrap text-ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.button.in-HostFileInput-horizontal {
|
||||
|
||||
@@ -90,12 +90,11 @@ export const Button = (props: ButtonProps) => {
|
||||
|
||||
{local.children && (
|
||||
<Typography
|
||||
class={styles.typography}
|
||||
hierarchy="label"
|
||||
size={local.size}
|
||||
inverted={local.hierarchy === "primary"}
|
||||
weight="bold"
|
||||
tag="span"
|
||||
in="Button"
|
||||
>
|
||||
{local.children}
|
||||
</Typography>
|
||||
|
||||
@@ -30,3 +30,9 @@
|
||||
.icon.in-ConfigureRole {
|
||||
@apply ml-auto;
|
||||
}
|
||||
.icon.in-SidebarBody-AccordionTrigger {
|
||||
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
}
|
||||
[data-expanded] > .icon.in-SidebarBody-AccordionTrigger {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,8 @@ type In =
|
||||
| "MachineTags-s"
|
||||
| "ConfigureRole"
|
||||
// TODO: better name
|
||||
| "WorkflowPanelTitle";
|
||||
| "WorkflowPanelTitle"
|
||||
| "SidebarBody-AccordionTrigger";
|
||||
export interface IconProps extends JSX.SvgSVGAttributes<SVGElement> {
|
||||
icon: IconVariant;
|
||||
size?: number | string;
|
||||
@@ -153,8 +154,8 @@ const Icon: Component<IconProps> = (props) => {
|
||||
component={component()}
|
||||
class={cx(
|
||||
styles.icon,
|
||||
colorsStyles[local.color],
|
||||
getInClasses(styles, local.in),
|
||||
colorsStyles[local.color],
|
||||
{
|
||||
[colorsStyles.inverted]: local.inverted,
|
||||
},
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
border-bottom: solid 1px theme(colors.border.def.2);
|
||||
}
|
||||
|
||||
.modal_title {
|
||||
@apply mx-auto;
|
||||
}
|
||||
|
||||
.modal_body {
|
||||
overflow-y: auto;
|
||||
@apply rounded-b-md p-4 pt-4 bg-def-1 flex-grow;
|
||||
|
||||
@@ -67,10 +67,10 @@ export const Modal = (props: ModalProps) => {
|
||||
<>
|
||||
<div class={styles.modal_header}>
|
||||
<Typography
|
||||
class={styles.modal_title}
|
||||
hierarchy="label"
|
||||
family="mono"
|
||||
size="xs"
|
||||
in="Modal-title"
|
||||
>
|
||||
{props.title}
|
||||
</Typography>
|
||||
|
||||
@@ -75,6 +75,7 @@ export const Default: Story = {
|
||||
height: "14.5rem",
|
||||
// Test with lots of modules
|
||||
options: generateModules(1000),
|
||||
// FIXME: replace with a component
|
||||
renderItem: (item: Module) => {
|
||||
return (
|
||||
<div class="flex items-center justify-between gap-2 rounded-md px-2 py-1 pr-4">
|
||||
@@ -93,7 +94,6 @@ export const Default: Story = {
|
||||
weight="normal"
|
||||
color="quaternary"
|
||||
inverted
|
||||
class="flex justify-between"
|
||||
>
|
||||
<span class="inline-block max-w-72 truncate align-middle">
|
||||
{item.description}
|
||||
|
||||
@@ -29,10 +29,11 @@ export function TagSelect<T extends { value: unknown }>(
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
weight="medium"
|
||||
class="flex gap-2 uppercase"
|
||||
size="xs"
|
||||
inverted
|
||||
color="secondary"
|
||||
transform="uppercase"
|
||||
in="TagSelect-label"
|
||||
>
|
||||
{props.label}
|
||||
</Typography>
|
||||
|
||||
@@ -113,7 +113,7 @@ export const Select = (props: SelectProps) => {
|
||||
size="s"
|
||||
weight="bold"
|
||||
family="condensed"
|
||||
class="flex w-full items-center"
|
||||
in="Select-item-label"
|
||||
>
|
||||
{props.item.rawValue.label}
|
||||
</Typography>
|
||||
@@ -129,8 +129,8 @@ export const Select = (props: SelectProps) => {
|
||||
size="s"
|
||||
weight="bold"
|
||||
family="condensed"
|
||||
class="flex w-full items-center"
|
||||
color="secondary"
|
||||
in="Select-item-label"
|
||||
>
|
||||
Loading...
|
||||
</Typography>
|
||||
@@ -144,8 +144,8 @@ export const Select = (props: SelectProps) => {
|
||||
size="s"
|
||||
weight="normal"
|
||||
family="condensed"
|
||||
class="flex w-full items-center"
|
||||
color="secondary"
|
||||
in="Select-item-label"
|
||||
>
|
||||
{props.noOptionsText || "No options available"}
|
||||
</Typography>
|
||||
@@ -157,7 +157,7 @@ export const Select = (props: SelectProps) => {
|
||||
size="s"
|
||||
weight="bold"
|
||||
family="condensed"
|
||||
class="flex w-full items-center"
|
||||
in="Select-item-label"
|
||||
>
|
||||
{props.placeholder}
|
||||
</Typography>
|
||||
@@ -186,7 +186,7 @@ export const Select = (props: SelectProps) => {
|
||||
size="s"
|
||||
weight="bold"
|
||||
family="condensed"
|
||||
class="flex w-full items-center"
|
||||
in="Select-item-label"
|
||||
>
|
||||
{state.selectedOption().label}
|
||||
</Typography>
|
||||
@@ -219,7 +219,7 @@ export const Select = (props: SelectProps) => {
|
||||
hierarchy="body"
|
||||
size="xs"
|
||||
weight="bold"
|
||||
class="flex w-full items-center"
|
||||
in="Select-item-label"
|
||||
>
|
||||
{state.selectedOption().label}
|
||||
</Typography>
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
div.sidebar-body {
|
||||
@apply py-4 px-2;
|
||||
/* full - (y padding) */
|
||||
height: calc(100% - 2rem);
|
||||
|
||||
@apply border border-inv-3 rounded-bl-md rounded-br-md;
|
||||
|
||||
/* TODO: This is weird, we shouldn't disable native browser features, a11y impacts incomming */
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
background:
|
||||
linear-gradient(0deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%),
|
||||
linear-gradient(
|
||||
180deg,
|
||||
theme(colors.bg.inv.1) 0%,
|
||||
theme(colors.bg.inv.3) 100%
|
||||
);
|
||||
|
||||
@apply backdrop-blur-sm;
|
||||
|
||||
.accordion {
|
||||
@apply w-full mb-4 h-full flex flex-col justify-start gap-4;
|
||||
|
||||
&:last-child {
|
||||
@apply mb-0;
|
||||
}
|
||||
|
||||
& > .item {
|
||||
max-height: 50%;
|
||||
&:last-child {
|
||||
@apply mb-0;
|
||||
}
|
||||
|
||||
& > .header {
|
||||
@apply flex mb-2 px-2;
|
||||
|
||||
& > .trigger {
|
||||
@apply inline-flex items-center justify-between w-full;
|
||||
|
||||
&:focus-visible {
|
||||
@apply z-10;
|
||||
outline: 2px solid hsl(200 98% 39%);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
& > .icon {
|
||||
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
}
|
||||
|
||||
&[data-expanded] > .icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
@apply uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .content {
|
||||
@apply flex flex-col;
|
||||
@apply py-3 px-1.5 bg-inv-4 rounded-md mb-4;
|
||||
|
||||
max-height: calc(100% - 24px);
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none;
|
||||
|
||||
animation: slideAccordionUp 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
|
||||
&[data-expanded] {
|
||||
animation: slideAccordionDown 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
}
|
||||
|
||||
nav * {
|
||||
@apply outline-none;
|
||||
}
|
||||
|
||||
nav > a {
|
||||
@apply block w-full px-2 py-1.5 min-h-7 my-2 rounded-md;
|
||||
|
||||
&:first-child {
|
||||
@apply mt-0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@apply mb-0;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
theme(colors.secondary.900),
|
||||
60%,
|
||||
theme(colors.secondary.600) 100%
|
||||
);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply bg-inv-acc-2;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply bg-inv-acc-3;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply bg-inv-acc-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideAccordionDown {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: var(--kb-accordion-content-height);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideAccordionUp {
|
||||
from {
|
||||
height: var(--kb-accordion-content-height);
|
||||
}
|
||||
to {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
115
pkgs/clan-app/ui/src/components/Sidebar/SidebarBody.module.css
Normal file
115
pkgs/clan-app/ui/src/components/Sidebar/SidebarBody.module.css
Normal file
@@ -0,0 +1,115 @@
|
||||
.sidebarBody {
|
||||
@apply py-4 px-2;
|
||||
/* full - (y padding) */
|
||||
height: calc(100% - 2rem);
|
||||
|
||||
@apply border border-inv-3 rounded-bl-md rounded-br-md;
|
||||
|
||||
/* TODO: This is weird, we shouldn't disable native browser features, a11y impacts incomming */
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
background:
|
||||
linear-gradient(0deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%),
|
||||
linear-gradient(
|
||||
180deg,
|
||||
theme(colors.bg.inv.1) 0%,
|
||||
theme(colors.bg.inv.3) 100%
|
||||
);
|
||||
|
||||
@apply backdrop-blur-sm;
|
||||
}
|
||||
|
||||
.accordion {
|
||||
@apply w-full mb-4 h-full flex flex-col justify-start gap-4;
|
||||
|
||||
&:last-child {
|
||||
@apply mb-0;
|
||||
}
|
||||
}
|
||||
.accordionItem {
|
||||
max-height: 50%;
|
||||
&:last-child {
|
||||
@apply mb-0;
|
||||
}
|
||||
}
|
||||
.accordionHeader {
|
||||
@apply flex mb-2 px-2;
|
||||
}
|
||||
|
||||
.accordionTrigger {
|
||||
@apply inline-flex items-center justify-between w-full;
|
||||
|
||||
&:focus-visible {
|
||||
@apply z-10;
|
||||
outline: 2px solid hsl(200 98% 39%);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.accordionContent {
|
||||
@apply flex flex-col;
|
||||
@apply py-3 px-1.5 bg-inv-4 rounded-md mb-4;
|
||||
|
||||
max-height: calc(100% - 24px);
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none;
|
||||
|
||||
animation: slideAccordionUp 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
|
||||
&[data-expanded] {
|
||||
animation: slideAccordionDown 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||
}
|
||||
|
||||
nav * {
|
||||
@apply outline-none;
|
||||
}
|
||||
|
||||
nav > a {
|
||||
@apply block w-full px-2 py-1.5 min-h-7 my-2 rounded-md;
|
||||
|
||||
&:first-child {
|
||||
@apply mt-0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@apply mb-0;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
theme(colors.secondary.900),
|
||||
60%,
|
||||
theme(colors.secondary.600) 100%
|
||||
);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply bg-inv-acc-2;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply bg-inv-acc-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideAccordionDown {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: var(--kb-accordion-content-height);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideAccordionUp {
|
||||
from {
|
||||
height: var(--kb-accordion-content-height);
|
||||
}
|
||||
to {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import "./SidebarBody.css";
|
||||
import styles from "./SidebarBody.module.css";
|
||||
import { A } from "@solidjs/router";
|
||||
import { Accordion } from "@kobalte/core/accordion";
|
||||
import Icon from "../Icon/Icon";
|
||||
@@ -75,23 +75,29 @@ const Machines = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Accordion.Item class="item" value="machines">
|
||||
<Accordion.Header class="header">
|
||||
<Accordion.Trigger class="trigger">
|
||||
<Accordion.Item class={styles.accordionItem} value="machines">
|
||||
<Accordion.Header class={styles.accordionHeader}>
|
||||
<Accordion.Trigger class={styles.accordionTrigger}>
|
||||
<Typography
|
||||
class="section-title"
|
||||
hierarchy="label"
|
||||
family="mono"
|
||||
size="xs"
|
||||
inverted
|
||||
color="tertiary"
|
||||
transform="uppercase"
|
||||
>
|
||||
Your Machines
|
||||
</Typography>
|
||||
<Icon icon="CaretDown" color="tertiary" inverted size="0.75rem" />
|
||||
<Icon
|
||||
icon="CaretDown"
|
||||
color="tertiary"
|
||||
inverted
|
||||
size="0.75rem"
|
||||
in="SidebarBody-AccordionTrigger"
|
||||
/>
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content class="content">
|
||||
<Accordion.Content class={styles.accordionContent}>
|
||||
<Show
|
||||
when={machines()}
|
||||
fallback={
|
||||
@@ -198,23 +204,29 @@ const Services = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Accordion.Item class="item" value="services">
|
||||
<Accordion.Header class="header">
|
||||
<Accordion.Trigger class="trigger">
|
||||
<Accordion.Item class={styles.accordionItem} value="services">
|
||||
<Accordion.Header class={styles.accordionHeader}>
|
||||
<Accordion.Trigger class={styles.accordionTrigger}>
|
||||
<Typography
|
||||
class="section-title"
|
||||
hierarchy="label"
|
||||
family="mono"
|
||||
size="xs"
|
||||
inverted
|
||||
color="tertiary"
|
||||
transform="uppercase"
|
||||
>
|
||||
Services
|
||||
</Typography>
|
||||
<Icon icon="CaretDown" color="tertiary" inverted size="0.75rem" />
|
||||
<Icon
|
||||
icon="CaretDown"
|
||||
color="tertiary"
|
||||
inverted
|
||||
size="0.75rem"
|
||||
in="SidebarBody-AccordionTrigger"
|
||||
/>
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content class="content">
|
||||
<Accordion.Content class={styles.accordionContent}>
|
||||
<nav>
|
||||
<For each={serviceInstances()}>
|
||||
{(mapped) => (
|
||||
@@ -242,9 +254,9 @@ export const SidebarBody = (props: SidebarProps) => {
|
||||
const defaultAccordionValues = ["machines", "services", ...sectionLabels];
|
||||
|
||||
return (
|
||||
<div class="sidebar-body">
|
||||
<div class={styles.sidebarBody}>
|
||||
<Accordion
|
||||
class="accordion"
|
||||
class={styles.accordion}
|
||||
multiple
|
||||
defaultValue={defaultAccordionValues}
|
||||
>
|
||||
@@ -253,16 +265,16 @@ export const SidebarBody = (props: SidebarProps) => {
|
||||
|
||||
<For each={props.staticSections}>
|
||||
{(section) => (
|
||||
<Accordion.Item class="item" value={section.title}>
|
||||
<Accordion.Header class="header">
|
||||
<Accordion.Trigger class="trigger">
|
||||
<Accordion.Item class={styles.accordionItem} value={section.title}>
|
||||
<Accordion.Header class={styles.accordionHeader}>
|
||||
<Accordion.Trigger class={styles.accordionTrigger}>
|
||||
<Typography
|
||||
class="section-title"
|
||||
hierarchy="label"
|
||||
family="mono"
|
||||
size="xs"
|
||||
inverted
|
||||
color="tertiary"
|
||||
transform="uppercase"
|
||||
>
|
||||
{section.title}
|
||||
</Typography>
|
||||
@@ -271,10 +283,11 @@ export const SidebarBody = (props: SidebarProps) => {
|
||||
color="tertiary"
|
||||
inverted
|
||||
size="0.75rem"
|
||||
in="SidebarBody-AccordionTrigger"
|
||||
/>
|
||||
</Accordion.Trigger>
|
||||
</Accordion.Header>
|
||||
<Accordion.Content class="content">
|
||||
<Accordion.Content class={styles.accordionContent}>
|
||||
<nav>
|
||||
<For each={section.links || []}>
|
||||
{(link) => (
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
}
|
||||
|
||||
&.body {
|
||||
font-size: 1rem;
|
||||
line-height: 1.32;
|
||||
letter-spacing: 0.005rem;
|
||||
|
||||
&.family-regular {
|
||||
font-family: "Archivo", sans-serif;
|
||||
}
|
||||
@@ -21,12 +25,6 @@
|
||||
font-family: "Archivo SemiCondensed", sans-serif;
|
||||
}
|
||||
|
||||
&.size-default {
|
||||
font-size: 1rem;
|
||||
line-height: 1.32;
|
||||
letter-spacing: 0.005rem;
|
||||
}
|
||||
|
||||
&.size-s {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.32;
|
||||
@@ -50,11 +48,9 @@
|
||||
&.family-condensed {
|
||||
font-family: "Archivo SemiCondensed", sans-serif;
|
||||
|
||||
&.size-default {
|
||||
font-size: 1rem;
|
||||
line-height: normal;
|
||||
letter-spacing: 0.02rem;
|
||||
}
|
||||
font-size: 1rem;
|
||||
line-height: normal;
|
||||
letter-spacing: 0.02rem;
|
||||
|
||||
&.size-s {
|
||||
font-size: 0.875rem;
|
||||
@@ -78,11 +74,9 @@
|
||||
&.family-mono {
|
||||
font-family: "Commit Mono", monospace;
|
||||
|
||||
&.size-default {
|
||||
font-size: 1rem;
|
||||
line-height: normal;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
font-size: 1rem;
|
||||
line-height: normal;
|
||||
letter-spacing: normal;
|
||||
|
||||
&.size-s {
|
||||
font-size: 0.875rem;
|
||||
@@ -104,16 +98,14 @@
|
||||
}
|
||||
|
||||
&.title {
|
||||
font-size: 1.125rem;
|
||||
line-height: 124%;
|
||||
letter-spacing: 0.03375rem;
|
||||
|
||||
&.family-regular {
|
||||
font-family: "Archivo", sans-serif;
|
||||
}
|
||||
|
||||
&.size-default {
|
||||
font-size: 1.125rem;
|
||||
line-height: 124%;
|
||||
letter-spacing: 0.03375rem;
|
||||
}
|
||||
|
||||
&.size-m {
|
||||
font-size: 1.25rem;
|
||||
line-height: 124%;
|
||||
@@ -128,16 +120,14 @@
|
||||
}
|
||||
|
||||
&.headline {
|
||||
font-size: 1.5rem;
|
||||
line-height: 116%;
|
||||
letter-spacing: 0.015rem;
|
||||
|
||||
&.family-regular {
|
||||
font-family: "Archivo", sans-serif;
|
||||
}
|
||||
|
||||
&.size-default {
|
||||
font-size: 1.5rem;
|
||||
line-height: 116%;
|
||||
letter-spacing: 0.015rem;
|
||||
}
|
||||
|
||||
&.size-m {
|
||||
font-size: 1.75rem;
|
||||
line-height: 116%;
|
||||
@@ -164,15 +154,13 @@
|
||||
}
|
||||
|
||||
&.teaser {
|
||||
font-size: 3rem;
|
||||
line-height: normal;
|
||||
letter-spacing: -0.06rem;
|
||||
|
||||
&.family-regular {
|
||||
font-family: "Archivo", sans-serif;
|
||||
}
|
||||
|
||||
&.size-default {
|
||||
font-size: 3rem;
|
||||
line-height: normal;
|
||||
letter-spacing: -0.06rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.align-left {
|
||||
@@ -186,4 +174,31 @@
|
||||
&.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
&.lowercase {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
&.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
|
||||
.typography.in-Button {
|
||||
@apply max-w-full overflow-hidden whitespace-nowrap text-ellipsis;
|
||||
}
|
||||
|
||||
.typography.in-Modal-title {
|
||||
@apply mx-auto;
|
||||
}
|
||||
.typography.in-TagSelect-label {
|
||||
@apply flex gap-2;
|
||||
}
|
||||
.typography.in-Select-item-label {
|
||||
@apply flex w-full items-center;
|
||||
}
|
||||
.typography.in-SelectService-item-description {
|
||||
@apply flex justify-between;
|
||||
}
|
||||
@@ -37,7 +37,6 @@ const TypographyExamples: Component<TypographyExamplesProps> = (props) => (
|
||||
<Show when={!props.colors}>
|
||||
<Typography
|
||||
hierarchy={props.hierarchy}
|
||||
//@ts-expect-error: difficult to generify for the story
|
||||
size={size}
|
||||
weight={weight}
|
||||
family={props.family}
|
||||
@@ -51,7 +50,6 @@ const TypographyExamples: Component<TypographyExamplesProps> = (props) => (
|
||||
<>
|
||||
<Typography
|
||||
hierarchy={props.hierarchy}
|
||||
//@ts-expect-error: difficult to generify for the story
|
||||
size={size}
|
||||
weight={weight}
|
||||
color={color}
|
||||
|
||||
@@ -1,135 +1,99 @@
|
||||
import { type JSX } from "solid-js";
|
||||
import { mergeProps, type ValidComponent, type JSX } from "solid-js";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
import cx from "classnames";
|
||||
import "./Typography.css";
|
||||
import { Color, fgClass } from "@/src/components/colors";
|
||||
import styles from "./Typography.module.css";
|
||||
import { Color } from "@/src/components/colors";
|
||||
import colorsStyles from "../colors.module.css";
|
||||
import { getInClasses } from "@/src/util";
|
||||
|
||||
export type Tag = "span" | "p" | "h1" | "h2" | "h3" | "h4" | "div";
|
||||
export type Hierarchy = "body" | "title" | "headline" | "label" | "teaser";
|
||||
export type Weight = "normal" | "medium" | "bold";
|
||||
export type Family = "regular" | "condensed" | "mono";
|
||||
export type Transform = "uppercase" | "lowercase" | "capitalize";
|
||||
|
||||
// type Size = "default" | "xs" | "s" | "m" | "l";
|
||||
interface SizeForHierarchy {
|
||||
body: {
|
||||
default: string;
|
||||
s: string;
|
||||
xs: string;
|
||||
xxs: string;
|
||||
};
|
||||
label: {
|
||||
default: string;
|
||||
s: string;
|
||||
xs: string;
|
||||
xxs: string;
|
||||
};
|
||||
headline: {
|
||||
default: string;
|
||||
m: string;
|
||||
l: string;
|
||||
xl: string;
|
||||
xxl: string;
|
||||
};
|
||||
title: {
|
||||
default: string;
|
||||
m: string;
|
||||
l: string;
|
||||
};
|
||||
teaser: {
|
||||
default: string;
|
||||
};
|
||||
export interface SizeForHierarchy {
|
||||
body: "default" | "s" | "xs" | "xxs";
|
||||
headline: "default" | "m" | "l" | "xl" | "xxl";
|
||||
title: "default" | "m" | "l";
|
||||
label: "default" | "s" | "xs" | "xxs";
|
||||
teaser: "default";
|
||||
}
|
||||
export interface TagForHierarchy {
|
||||
body: "span" | "p" | "div";
|
||||
headline: "h1" | "h2" | "h3" | "h4";
|
||||
title: "h1" | "h2" | "h3" | "h4";
|
||||
label: "span" | "div";
|
||||
teaser: "h1" | "h2" | "h3" | "h4";
|
||||
}
|
||||
|
||||
export type AllowedSizes<H extends Hierarchy> = keyof SizeForHierarchy[H];
|
||||
|
||||
const sizeHierarchyMap: SizeForHierarchy = {
|
||||
body: {
|
||||
default: cx("size-default"),
|
||||
s: cx("size-s"),
|
||||
xs: cx("size-xs"),
|
||||
xxs: cx("size-xxs"),
|
||||
},
|
||||
headline: {
|
||||
default: cx("size-default"),
|
||||
m: cx("size-m"),
|
||||
l: cx("size-l"),
|
||||
xl: cx("size-xl"),
|
||||
xxl: cx("size-xxl"),
|
||||
},
|
||||
title: {
|
||||
default: cx("size-default"),
|
||||
// xs: cx("size-xs"),
|
||||
// s: cx("size-s"),
|
||||
m: cx("size-m"),
|
||||
l: cx("size-l"),
|
||||
},
|
||||
label: {
|
||||
default: cx("size-default"),
|
||||
s: cx("size-s"),
|
||||
xs: cx("size-xs"),
|
||||
xxs: cx("size-xxs"),
|
||||
},
|
||||
teaser: {
|
||||
default: cx("size-default"),
|
||||
},
|
||||
};
|
||||
|
||||
const defaultFamilyMap: Record<Hierarchy, Family> = {
|
||||
const defaultFamilyMap = {
|
||||
body: "condensed",
|
||||
label: "condensed",
|
||||
title: "regular",
|
||||
headline: "regular",
|
||||
title: "regular",
|
||||
label: "condensed",
|
||||
teaser: "regular",
|
||||
};
|
||||
} as const;
|
||||
|
||||
const weightMap: Record<Weight, string> = {
|
||||
normal: "weight-normal",
|
||||
medium: "weight-medium",
|
||||
bold: "weight-bold",
|
||||
};
|
||||
|
||||
interface _TypographyProps<H extends Hierarchy> {
|
||||
const defaultTagMap = {
|
||||
body: "p",
|
||||
headline: "h1",
|
||||
title: "h2",
|
||||
label: "span",
|
||||
teaser: "h3",
|
||||
} as const;
|
||||
export interface TypographyProps<H extends Hierarchy> {
|
||||
hierarchy: H;
|
||||
size: AllowedSizes<H>;
|
||||
color?: Color;
|
||||
children: JSX.Element;
|
||||
size?: SizeForHierarchy[H];
|
||||
color?: Color;
|
||||
weight?: Weight;
|
||||
family?: Family;
|
||||
inverted?: boolean;
|
||||
tag?: Tag;
|
||||
class?: string;
|
||||
tag?: TagForHierarchy[H];
|
||||
transform?: Transform;
|
||||
align?: "left" | "center" | "right";
|
||||
in?:
|
||||
| "Button"
|
||||
| "Modal-title"
|
||||
| "TagSelect-label"
|
||||
| "Select-item-label"
|
||||
| "SelectService-item-description";
|
||||
}
|
||||
|
||||
export const Typography = <H extends Hierarchy>(props: _TypographyProps<H>) => {
|
||||
const family = () =>
|
||||
`family-${props.family || defaultFamilyMap[props.hierarchy]}`;
|
||||
const hierarchy = () => props.hierarchy || "body";
|
||||
const size = () => sizeHierarchyMap[props.hierarchy][props.size] as string;
|
||||
const weight = () => weightMap[props.weight || "normal"];
|
||||
const color = () => fgClass(props.color, props.inverted);
|
||||
const align = () => `align-${props.align || "left"}`;
|
||||
export const Typography = <H extends Hierarchy>(props: TypographyProps<H>) => {
|
||||
const local = mergeProps(
|
||||
{
|
||||
size: "default",
|
||||
color: "primary",
|
||||
weight: "normal",
|
||||
family: defaultFamilyMap[props.hierarchy],
|
||||
align: "left",
|
||||
tag: defaultTagMap[props.hierarchy],
|
||||
} as const,
|
||||
props,
|
||||
);
|
||||
|
||||
return (
|
||||
<Dynamic
|
||||
component={local.tag as ValidComponent}
|
||||
class={cx(
|
||||
"typography",
|
||||
hierarchy(),
|
||||
family(),
|
||||
weight(),
|
||||
size(),
|
||||
color(),
|
||||
align(),
|
||||
props.transform,
|
||||
props.class,
|
||||
styles.typography,
|
||||
styles[local.hierarchy],
|
||||
styles[`family-${local.family}`],
|
||||
styles[`weight-${local.weight}`],
|
||||
local.size != "default" &&
|
||||
styles[
|
||||
`size-${local.size as Exclude<SizeForHierarchy[H], "default">}`
|
||||
],
|
||||
styles[`align-${local.align}`],
|
||||
local.transform && styles[local.transform],
|
||||
colorsStyles[local.color],
|
||||
{
|
||||
[colorsStyles.inverted]: local.inverted,
|
||||
},
|
||||
getInClasses(styles, local.in),
|
||||
)}
|
||||
component={props.tag || "span"}
|
||||
>
|
||||
{props.children}
|
||||
{local.children}
|
||||
</Dynamic>
|
||||
);
|
||||
};
|
||||
|
||||
export type TypographyProps = _TypographyProps<Hierarchy>;
|
||||
|
||||
@@ -138,22 +138,11 @@ const UpdateProgress = () => {
|
||||
<div class="relative flex size-full flex-col items-center justify-end bg-inv-4">
|
||||
<img src={usbLogo} alt="usb logo" class="absolute top-2 z-0" />
|
||||
<div class="z-10 mb-6 flex w-full max-w-md flex-col items-center gap-2 fg-inv-1">
|
||||
<Typography
|
||||
hierarchy="title"
|
||||
size="default"
|
||||
weight="bold"
|
||||
color="inherit"
|
||||
>
|
||||
<Typography hierarchy="title" weight="bold" color="inherit">
|
||||
Machine is being updated
|
||||
</Typography>
|
||||
<LoadingBar />
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
size="default"
|
||||
class=""
|
||||
color="secondary"
|
||||
inverted
|
||||
>
|
||||
<Typography hierarchy="label" color="secondary" inverted>
|
||||
Update {updateState()?.topic}...
|
||||
</Typography>
|
||||
<Button
|
||||
|
||||
@@ -38,17 +38,13 @@ const Prose = () => (
|
||||
>
|
||||
Local Setup
|
||||
</Typography>
|
||||
<Typography
|
||||
hierarchy="headline"
|
||||
size="default"
|
||||
weight="bold"
|
||||
color="inherit"
|
||||
class="text-balance"
|
||||
>
|
||||
Here's what you
|
||||
<br />
|
||||
need to do
|
||||
</Typography>
|
||||
<div class="text-balance">
|
||||
<Typography hierarchy="headline" weight="bold" color="inherit">
|
||||
Here's what you
|
||||
<br />
|
||||
need to do
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 px-4">
|
||||
|
||||
@@ -841,13 +841,7 @@ const InstallProgress = () => {
|
||||
Machine is being installed
|
||||
</Typography>
|
||||
<LoadingBar />
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
size="default"
|
||||
class=""
|
||||
color="secondary"
|
||||
inverted
|
||||
>
|
||||
<Typography hierarchy="label" color="secondary" inverted>
|
||||
<Switch fallback={"Waiting for preparation to start..."}>
|
||||
<Match when={store.install.prepareStep === "disk"}>
|
||||
Configuring disk schema ...
|
||||
|
||||
@@ -98,7 +98,7 @@ export const SelectService = (props: FlyoutProps) => {
|
||||
weight="normal"
|
||||
color="quaternary"
|
||||
inverted
|
||||
class="flex justify-between"
|
||||
in="SelectService-item-description"
|
||||
>
|
||||
<span class="inline-block max-w-80 truncate align-middle">
|
||||
{item.raw.info.manifest.description}
|
||||
|
||||
@@ -380,7 +380,7 @@ const ConfigureRole = () => {
|
||||
size="s"
|
||||
weight="medium"
|
||||
inverted
|
||||
class="capitalize"
|
||||
transform="capitalize"
|
||||
>
|
||||
Select {store.currentRole}
|
||||
</Typography>
|
||||
|
||||
Reference in New Issue
Block a user