+
(
{props.error && (
- {props.error}
+
+ {props.error}
+
)}
);
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/SidebarFlyout/index.tsx b/pkgs/webview-ui/app/src/components/Sidebar/SidebarFlyout/index.tsx
new file mode 100644
index 000000000..6646db8f9
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/SidebarFlyout/index.tsx
@@ -0,0 +1,14 @@
+import { List } from "@/src/components/Helpers";
+import { SidebarListItem } from "../SidebarListItem";
+
+export const SidebarFlyout = () => {
+ return (
+
+ );
+};
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/SidebarHeader.tsx b/pkgs/webview-ui/app/src/components/Sidebar/SidebarHeader.tsx
new file mode 100644
index 000000000..b44d9fc90
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/SidebarHeader.tsx
@@ -0,0 +1,60 @@
+import { createSignal, Show } from "solid-js";
+
+import { Typography } from "@/src/components/Typography";
+import { SidebarFlyout } from "./SidebarFlyout";
+
+interface SidebarHeader {
+ clanName: string;
+}
+
+export const SidebarHeader = (props: SidebarHeader) => {
+ const { clanName } = props;
+
+ const [showFlyout, toggleFlyout] = createSignal(false);
+
+ function handleClick() {
+ toggleFlyout(!showFlyout());
+ }
+
+ const renderClanProfile = () => (
+
+ );
+
+ const renderClanTitle = () => (
+
+ {clanName}
+
+ );
+
+ return (
+
+ );
+};
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/SidebarListItem.tsx b/pkgs/webview-ui/app/src/components/Sidebar/SidebarListItem.tsx
new file mode 100644
index 000000000..189b5cffe
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/SidebarListItem.tsx
@@ -0,0 +1,30 @@
+import { A } from "@solidjs/router";
+
+import { Typography } from "@/src/components/Typography";
+
+interface SidebarListItem {
+ title: string;
+ href: string;
+}
+
+export const SidebarListItem = (props: SidebarListItem) => {
+ const { title, href } = props;
+
+ return (
+
+ );
+};
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-flyout.css b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-flyout.css
new file mode 100644
index 000000000..5090c238d
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-flyout.css
@@ -0,0 +1,20 @@
+.sidebar__flyout {
+ top: 0;
+ position: absolute;
+ z-index: theme(zIndex.30);
+
+ padding: theme(padding[1]);
+ width: 100%;
+ height: auto;
+}
+
+.sidebar__flyout__inner {
+ position: relative;
+ width: inherit;
+ height: inherit;
+
+ padding: theme(padding.12) theme(padding.3) theme(padding.3);
+ background-color: rgba(var(--clr-bg-inv-4) / 0.95);
+ border: 1px solid rgb(var(--clr-border-inv-4));
+ border-radius: theme(borderRadius.lg);
+}
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-header.css b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-header.css
new file mode 100644
index 000000000..39efedf1c
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-header.css
@@ -0,0 +1,30 @@
+.sidebar__header {
+ position: relative;
+ padding: 1px 1px 0;
+ cursor: pointer;
+
+ &:after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+
+ width: 100%;
+ height: 100%;
+ background: rgb(var(--clr-bg-inv-3));
+
+ border-bottom: 1px solid var(--clr-border-inv-3);
+ border-top-left-radius: theme(borderRadius.xl);
+ border-top-right-radius: theme(borderRadius.xl);
+ }
+}
+
+.sidebar__header__inner {
+ position: relative;
+ z-index: theme(zIndex.40);
+ display: flex;
+ align-items: center;
+ gap: 0 theme(gap.3);
+
+ padding: theme(padding.3) theme(padding.3);
+}
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-list-item.css b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-list-item.css
new file mode 100644
index 000000000..c883518fc
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-list-item.css
@@ -0,0 +1,46 @@
+.sidebar__list__item {
+ position: relative;
+ cursor: theme(cursor.pointer);
+
+ &:after {
+ content: "";
+ position: absolute;
+ z-index: theme(zIndex.10);
+ top: 0;
+ left: 0;
+
+ width: 100%;
+ height: 100%;
+ border-radius: theme(borderRadius.md);
+ transform: scale(0.98);
+ transition: transform 0.24s ease-in-out;
+ }
+
+ &:hover:after {
+ background: rgb(var(--clr-bg-inv-acc-2));
+ transform: scale(theme(scale.100));
+ transition: transform 0.24s ease-in-out;
+ }
+
+ &:active {
+ transform: scale(0.99);
+ transition: transform 0.08s ease-in-out;
+ }
+
+ &:active:after {
+ background: rgb(var(--clr-bg-inv-acc-3));
+ transform: scale(theme(scale.100));
+ }
+}
+
+.sidebar__list__link {
+ position: relative;
+ z-index: 20;
+ display: block;
+ padding: theme(padding.3);
+}
+
+.sidebar__list__content {
+ position: relative;
+ z-index: 20;
+}
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-profile.css b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-profile.css
new file mode 100644
index 000000000..05169862f
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar-profile.css
@@ -0,0 +1,19 @@
+.sidebar__profile {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ width: theme(width.8);
+ height: theme(height.8);
+
+ background: rgb(var(--clr-bg-inv-4));
+ border-radius: 50%;
+}
+
+.sidebar__profile--flyout {
+ background: rgb(var(--clr-bg-def-2));
+}
+
+.sidebar__profile--flyout > .sidebar__profile__character {
+ color: rgb(var(--clr-fg-def-1)) !important;
+}
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar.css b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar.css
new file mode 100644
index 000000000..649ca70df
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/css/sidebar.css
@@ -0,0 +1,29 @@
+/* Sidebar Elements */
+
+@import "./sidebar-header";
+@import "./sidebar-flyout";
+@import "./sidebar-list-item";
+@import "./sidebar-profile";
+
+/* Sidebar Structure */
+
+.sidebar {
+ min-width: theme(width.72);
+ height: 100%;
+ background-color: rgb(var(--clr-bg-inv-2));
+ border: 1px solid rgb(var(--clr-border-inv-2));
+ border-radius: theme(borderRadius.xl);
+}
+
+.sidebar__body {
+ display: flex;
+ flex-direction: column;
+ gap: theme(padding.2);
+ padding: theme(padding.4) theme(padding.2);
+}
+
+.sidebar__section {
+ padding: theme(padding.2);
+ background-color: rgba(var(--clr-bg-inv-3) / 0.9);
+ border-radius: theme(borderRadius.md);
+}
diff --git a/pkgs/webview-ui/app/src/components/Sidebar/index.tsx b/pkgs/webview-ui/app/src/components/Sidebar/index.tsx
new file mode 100644
index 000000000..8ba262499
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Sidebar/index.tsx
@@ -0,0 +1,93 @@
+import { For, createEffect, Show, type JSX, children } from "solid-js";
+import { A, RouteSectionProps } from "@solidjs/router";
+import { activeURI } from "@/src/App";
+import { createQuery } from "@tanstack/solid-query";
+import { callApi } from "@/src/api";
+import { AppRoute, routes } from "@/src/index";
+
+import { List } from "../Helpers";
+import { SidebarHeader } from "./SidebarHeader";
+
+import { SidebarListItem } from "./SidebarListItem";
+import "./css/sidebar.css";
+import { Typography } from "../Typography";
+
+export const SidebarSection = (props: {
+ title: string;
+ children: JSX.Element;
+}) => {
+ const { title, children } = props;
+
+ return (
+
+ );
+};
+
+export const Sidebar = (props: RouteSectionProps) => {
+ createEffect(() => {
+ console.log("machines");
+ console.log(routes);
+ });
+
+ const query = createQuery(() => ({
+ queryKey: [activeURI(), "meta"],
+ queryFn: async () => {
+ const curr = activeURI();
+ if (curr) {
+ const result = await callApi("show_clan_meta", { uri: curr });
+
+ if (result.status === "error") throw new Error("Failed to fetch data");
+
+ return result.data;
+ }
+ },
+ }));
+
+ return (
+
+ );
+};
diff --git a/pkgs/webview-ui/app/src/components/TextInput.tsx b/pkgs/webview-ui/app/src/components/TextInput.tsx
index 32637e2b6..43f24c861 100644
--- a/pkgs/webview-ui/app/src/components/TextInput.tsx
+++ b/pkgs/webview-ui/app/src/components/TextInput.tsx
@@ -63,7 +63,9 @@ export function TextInput(
{props.error && (
-
{props.error}
+
+ {props.error}
+
)}
);
diff --git a/pkgs/webview-ui/app/src/components/Typography/css/typography-color.css b/pkgs/webview-ui/app/src/components/Typography/css/typography-color.css
new file mode 100644
index 000000000..6f0952945
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Typography/css/typography-color.css
@@ -0,0 +1,23 @@
+.fnt-clr-primary {
+ color: (rgb(--clr-fg-def-1));
+}
+
+.fnt-clr-secondary {
+ color: rgb(var(--clr-fg-def-2));
+}
+
+.fnt-clr-tertiary {
+ color: rgb(var(--clr-fg-def-3));
+}
+
+.fnt-clr-primary.fnt-clr--inverted {
+ color: rgb(var(--clr-fg-inv-1));
+}
+
+.fnt-clr-secondary.fnt-clr--inverted {
+ color: rgb(var(--clr-fg-inv-2));
+}
+
+.fnt-clr-tertiary.fnt-clr--inverted {
+ color: rgb(var(--clr-fg-inv-3));
+}
diff --git a/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/index.css b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/index.css
new file mode 100644
index 000000000..2394559ef
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/index.css
@@ -0,0 +1,3 @@
+@import "./typography-body.css";
+@import "./typography-title.css";
+@import "./typography-headline.css";
diff --git a/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-body.css b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-body.css
new file mode 100644
index 000000000..57a3e18f3
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-body.css
@@ -0,0 +1,17 @@
+.fnt-body-default {
+ font-size: 1rem;
+ line-height: 132%;
+ letter-spacing: 3%;
+}
+
+.fnt-body-s {
+ font-size: 0.925rem;
+ line-height: 132%;
+ letter-spacing: 3%;
+}
+
+.fnt-body-xs {
+ font-size: 0.875rem;
+ line-height: 132%;
+ letter-spacing: 3%;
+}
diff --git a/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-headline.css b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-headline.css
new file mode 100644
index 000000000..7527f335f
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-headline.css
@@ -0,0 +1,17 @@
+.fnt-headline-default {
+ font-size: 1.5rem;
+ line-height: 116%;
+ letter-spacing: 1%;
+}
+
+.fnt-headline-m {
+ font-size: 1.75rem;
+ line-height: 116%;
+ letter-spacing: 1%;
+}
+
+.fnt-headline-l {
+ font-size: 2rem;
+ line-height: 116%;
+ letter-spacing: 1%;
+}
diff --git a/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-title.css b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-title.css
new file mode 100644
index 000000000..65a7d820b
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Typography/css/typography-hierarchy/typography-title.css
@@ -0,0 +1,17 @@
+.fnt-title-default {
+ font-size: 1.125rem;
+ line-height: 124%;
+ letter-spacing: 3%;
+}
+
+.fnt-title-m {
+ font-size: 1.25rem;
+ line-height: 124%;
+ letter-spacing: 3%;
+}
+
+.fnt-title-l {
+ font-size: 1.375rem;
+ line-height: 124%;
+ letter-spacing: 3%;
+}
diff --git a/pkgs/webview-ui/app/src/components/Typography/css/typography.css b/pkgs/webview-ui/app/src/components/Typography/css/typography.css
new file mode 100644
index 000000000..e0d1b4075
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Typography/css/typography.css
@@ -0,0 +1,26 @@
+@import "./typography-hierarchy/";
+@import "./typography-color.css";
+
+.fnt-weight-normal {
+ font-weight: normal;
+}
+
+.fnt-weight-medium {
+ font-weight: medium;
+}
+
+.fnt-weight-bold {
+ font-weight: bold;
+}
+
+.fnt-weight-normal.fnt-clr--inverted {
+ font-weight: light;
+}
+
+.fnt-weight-medium.fnt-clr--inverted {
+ font-weight: normal;
+}
+
+.fnt-weight-bold.fnt-clr--inverted {
+ font-weight: 600;
+}
diff --git a/pkgs/webview-ui/app/src/components/Typography/index.tsx b/pkgs/webview-ui/app/src/components/Typography/index.tsx
new file mode 100644
index 000000000..528607bf5
--- /dev/null
+++ b/pkgs/webview-ui/app/src/components/Typography/index.tsx
@@ -0,0 +1,96 @@
+import { type JSX } from "solid-js";
+import { Dynamic } from "solid-js/web";
+import cx from "classnames";
+import "./css/typography.css";
+
+type Hierarchy = "body" | "title" | "headline";
+type Color = "primary" | "secondary" | "tertiary";
+type Weight = "normal" | "medium" | "bold";
+type Tag = "span" | "p" | "h1" | "h2" | "h3" | "h4";
+
+const colorMap: Record
= {
+ primary: cx("fnt-clr-primary"),
+ secondary: cx("fnt-clr-secondary"),
+ tertiary: cx("fnt-clr-tertiary"),
+};
+
+// type Size = "default" | "xs" | "s" | "m" | "l";
+interface SizeForHierarchy {
+ body: {
+ default: string;
+ xs: string;
+ s: string;
+ };
+ headline: {
+ default: string;
+ m: string;
+ l: string;
+ };
+ title: {
+ default: string;
+ m: string;
+ l: string;
+ };
+}
+
+type AllowedSizes = keyof SizeForHierarchy[H];
+
+const sizeHierarchyMap: SizeForHierarchy = {
+ body: {
+ default: cx("fnt-body-default"),
+ xs: cx("fnt-body-xs"),
+ s: cx("fnt-body-s"),
+ // m: cx("fnt-body-m"),
+ // l: cx("fnt-body-l"),
+ },
+ headline: {
+ default: cx("fnt-headline-default"),
+ // xs: cx("fnt-headline-xs"),
+ // s: cx("fnt-headline-s"),
+ m: cx("fnt-headline-m"),
+ l: cx("fnt-headline-l"),
+ },
+ title: {
+ default: cx("fnt-title-default"),
+ // xs: cx("fnt-title-xs"),
+ // s: cx("fnt-title-s"),
+ m: cx("fnt-title-m"),
+ l: cx("fnt-title-l"),
+ },
+};
+
+const weightMap: Record = {
+ normal: cx("fnt-weight-normal"),
+ medium: cx("fnt-weight-medium"),
+ bold: cx("fnt-weight-bold"),
+};
+
+interface TypographyProps {
+ hierarchy: H;
+ weight: Weight;
+ color: Color;
+ inverted: boolean;
+ size: AllowedSizes;
+ tag: Tag;
+ children: JSX.Element;
+ classes?: string;
+}
+export const Typography = (props: TypographyProps) => {
+ const { size, color, inverted, hierarchy, weight, tag, children, classes } =
+ props;
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/pkgs/webview-ui/app/src/index.css b/pkgs/webview-ui/app/src/index.css
index facc03672..59acbd744 100644
--- a/pkgs/webview-ui/app/src/index.css
+++ b/pkgs/webview-ui/app/src/index.css
@@ -1,5 +1,6 @@
@import "material-icons/iconfont/filled.css";
/* List of icons: https://marella.me/material-icons/demo/ */
+/* @import url(./components/Typography/css/typography.css); */
@tailwind base;
@tailwind components;
@@ -21,8 +22,67 @@
src: url(../.fonts/Archiv0-Bold.otf) format("opentype");
}
+:root {
+ --clr-bg-def-1: theme(colors.white);
+ --clr-bg-def-2: theme(colors.secondary.50);
+ --clr-bg-def-3: theme(colors.secondary.100);
+ --clr-bg-def-4: theme(colors.secondary.200);
+ --clr-bg-def-5: theme(colors.secondary.300);
+
+ --clr-border-def-1: theme(colors.secondary.50);
+ --clr-border-def-2: theme(colors.secondary.100);
+ --clr-border-def-3: theme(colors.secondary.200);
+ --clr-border-def-4: theme(colors.secondary.300);
+ --clr-border-def-5: theme(colors.secondary.400);
+
+ --clr-bg-inv-1: theme(colors.primary.600);
+ --clr-bg-inv-2: theme(colors.primary.700);
+ --clr-bg-inv-3: theme(colors.primary.800);
+ --clr-bg-inv-4: theme(colors.primary.900);
+ --clr-bg-inv-5: theme(colors.primary.950);
+
+ --clr-border-inv-1: theme(colors.secondary.800);
+ --clr-border-inv-2: theme(colors.secondary.900);
+ --clr-border-inv-3: theme(colors.secondary.900);
+ --clr-border-inv-4: theme(colors.secondary.950);
+ --clr-border-inv-5: theme(colors.black);
+
+ --clr-bg-inv-acc-1: theme(colors.secondary.500);
+ --clr-bg-inv-acc-2: theme(colors.secondary.600);
+ --clr-bg-inv-acc-3: theme(colors.secondary.700);
+
+ --clr-fg-def-1: theme(colors.secondary.950);
+ --clr-fg-def-2: theme(colors.secondary.900);
+ --clr-fg-def-3: theme(colors.secondary.700);
+ --clr-fg-def-4: theme(colors.secondary.500);
+
+ --clr-fg-inv-1: theme(colors.white);
+ --clr-fg-inv-2: theme(colors.secondary.100);
+ --clr-fg-inv-3: theme(colors.secondary.300);
+ --clr-fg-inv-4: theme(colors.secondary.400);
+}
+
html {
@apply font-sans;
overflow-x: hidden;
overflow-y: scroll;
}
+
+.accordeon {
+ display: flex;
+ flex-direction: column;
+ gap: theme(gap.3);
+}
+
+.accordeon__header {
+ padding: theme(padding.2) theme(padding[1.5]);
+ cursor: pointer;
+}
+
+.accordeon__header::-webkit-details-marker {
+ display: none;
+}
+
+.accordeon__body {
+ padding: theme(padding.2) 0 theme(padding.1);
+}
diff --git a/pkgs/webview-ui/app/src/layout/header.tsx b/pkgs/webview-ui/app/src/layout/header.tsx
index a46ebfa6d..5c042deed 100644
--- a/pkgs/webview-ui/app/src/layout/header.tsx
+++ b/pkgs/webview-ui/app/src/layout/header.tsx
@@ -59,7 +59,7 @@ export const Header = (props: HeaderProps) => {
{(meta) => [
- {meta().name},
+ {meta().name},
{meta()?.description},
]}
diff --git a/pkgs/webview-ui/app/src/layout/layout.tsx b/pkgs/webview-ui/app/src/layout/layout.tsx
index 17160c61b..8fee28058 100644
--- a/pkgs/webview-ui/app/src/layout/layout.tsx
+++ b/pkgs/webview-ui/app/src/layout/layout.tsx
@@ -1,8 +1,8 @@
import { Component, createEffect, Show } from "solid-js";
import { Header } from "./header";
-import { Sidebar } from "../Sidebar";
+import { Sidebar } from "@/src/components/Sidebar";
import { activeURI, clanList } from "../App";
-import { redirect, RouteSectionProps, useNavigate } from "@solidjs/router";
+import { RouteSectionProps, useNavigate } from "@solidjs/router";
export const Layout: Component = (props) => {
const navigate = useNavigate();
@@ -16,9 +16,10 @@ export const Layout: Component = (props) => {
navigate("/welcome");
}
});
+
return (
-
+
{
{(field, props) => (