summaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/ArrowButton.css9
-rw-r--r--src/components/ArrowButton.tsx12
-rw-r--r--src/components/Button.css54
-rw-r--r--src/components/Button.tsx19
-rw-r--r--src/components/ContainedList.css21
-rw-r--r--src/components/ContainedList.tsx16
-rw-r--r--src/components/Content.css5
-rw-r--r--src/components/Content.tsx16
-rw-r--r--src/components/Form.css8
-rw-r--r--src/components/Form.tsx17
-rw-r--r--src/components/FormLabel.css8
-rw-r--r--src/components/FormLabel.tsx16
-rw-r--r--src/components/Header.css21
-rw-r--r--src/components/Header.tsx22
-rw-r--r--src/components/TextInput.css17
-rw-r--r--src/components/TextInput.tsx26
-rw-r--r--src/components/index.ts8
17 files changed, 295 insertions, 0 deletions
diff --git a/src/components/ArrowButton.css b/src/components/ArrowButton.css
new file mode 100644
index 0000000..a39f44a
--- /dev/null
+++ b/src/components/ArrowButton.css
@@ -0,0 +1,9 @@
+@scope (.__ArrowButton) {
+ :scope {
+ margin-top: 1rem;
+ padding: 0 1rem;
+ background-image: url('../icons/arrow-right.svg');
+ background-position: right 1rem center;
+ background-repeat: no-repeat;
+ }
+} \ No newline at end of file
diff --git a/src/components/ArrowButton.tsx b/src/components/ArrowButton.tsx
new file mode 100644
index 0000000..ce0c898
--- /dev/null
+++ b/src/components/ArrowButton.tsx
@@ -0,0 +1,12 @@
+import Button, { ButtonProps } from './Button.tsx';
+import './ArrowButton.css';
+
+const ArrowButton = ({ children, ...props }: ButtonProps) => {
+ return (
+ <Button {...props} class={(props.class || '') + ' __ArrowButton'}>
+ {children}
+ </Button>
+ );
+};
+
+export default ArrowButton; \ No newline at end of file
diff --git a/src/components/Button.css b/src/components/Button.css
new file mode 100644
index 0000000..210d131
--- /dev/null
+++ b/src/components/Button.css
@@ -0,0 +1,54 @@
+@scope (.__Button) {
+ :scope {
+ width: 100%;
+ min-width: fit-content;
+ height: 3rem;
+ padding: 0 1rem;
+
+ /* Necessary for <a> */
+ display: flex;
+ align-items: center;
+
+ font-size: 1rem;
+ text-align: start;
+ text-decoration: none;
+
+ cursor: pointer;
+
+ border: 1px solid var(--button-border, var(--button-base));
+ background-color: var(--button-base);
+ color: var(--button-text);
+
+ &:hover {
+ background-color: var(--button-hover);
+ color: var(--button-hover-text, var(--button-text));
+ }
+
+ &:focus {
+ outline: 2px solid var(--primary);
+ border-color: var(--base);
+ background-color: var(--button-focus, var(--button-base));
+ color: var(--button-focus-text, var(--button-text));
+ }
+
+ &.primary {
+ --button-base: var(--primary);
+ --button-text: var(--text);
+ --button-hover: color-mix(in srgb, var(--text) 10%, var(--button-base));
+ }
+ &.outline {
+ --button-base: transparent;
+ --button-text: var(--primary);
+ --button-border: var(--primary);
+ --button-hover: var(--primary);
+ --button-hover-text: var(--text);
+ --button-focus: var(--button-hover);
+ --button-focus-text: var(--button-hover-text);
+ }
+ &.ghost {
+ --button-base: transprent;
+ --button-text: var(--text);
+ --button-hover: var(--surface);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/components/Button.tsx b/src/components/Button.tsx
new file mode 100644
index 0000000..60f42c7
--- /dev/null
+++ b/src/components/Button.tsx
@@ -0,0 +1,19 @@
+import type { ComponentChildren } from 'preact';
+import './Button.css';
+
+export interface ButtonProps {
+ children: ComponentChildren;
+ kind?: 'primary' | 'outline' | 'ghost';
+ props: Record<string, any>;
+}
+
+const Button = ({ children, kind = 'primary', ...props }: ButtonProps) => {
+ const Elem = props.href ? 'a' : 'button';
+ return (
+ <Elem {...props} class={(props.class || '') + ' __Button ' + kind}>
+ {children}
+ </Elem>
+ );
+};
+
+export default Button; \ No newline at end of file
diff --git a/src/components/ContainedList.css b/src/components/ContainedList.css
new file mode 100644
index 0000000..97c98cc
--- /dev/null
+++ b/src/components/ContainedList.css
@@ -0,0 +1,21 @@
+@scope (.__ContainedList) {
+ :scope {
+ list-style: none;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+
+ li {
+ --border: 2px solid var(--surface);
+ border-top: var(--border);
+ &:last-child {
+ border-bottom: var(--border);
+ }
+ height: 3rem;
+ display: flex;
+ > * {
+ flex-grow: 1;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/components/ContainedList.tsx b/src/components/ContainedList.tsx
new file mode 100644
index 0000000..e514e54
--- /dev/null
+++ b/src/components/ContainedList.tsx
@@ -0,0 +1,16 @@
+import type { ComponentChildren } from 'preact';
+import './ContainedList.css';
+
+export interface ContainedListProps {
+ children: ComponentChildren;
+}
+
+const ContainedList = ({ children }: ContainedListProps) => {
+ return (
+ <ul class="__ContainedList">
+ {children}
+ </ul>
+ );
+};
+
+export default ContainedList; \ No newline at end of file
diff --git a/src/components/Content.css b/src/components/Content.css
new file mode 100644
index 0000000..ec3836b
--- /dev/null
+++ b/src/components/Content.css
@@ -0,0 +1,5 @@
+@scope (.__Content) {
+ :scope {
+ padding: 2rem;
+ }
+} \ No newline at end of file
diff --git a/src/components/Content.tsx b/src/components/Content.tsx
new file mode 100644
index 0000000..6beb82b
--- /dev/null
+++ b/src/components/Content.tsx
@@ -0,0 +1,16 @@
+import { ComponentChildren } from 'preact';
+import './Content.css';
+
+export interface ContentProps {
+ children: ComponentChildren;
+}
+
+const Content = ({ children }: ContentProps) => {
+ return (
+ <main class="__Content">
+ {children}
+ </main>
+ );
+};
+
+export default Content; \ No newline at end of file
diff --git a/src/components/Form.css b/src/components/Form.css
new file mode 100644
index 0000000..f47b737
--- /dev/null
+++ b/src/components/Form.css
@@ -0,0 +1,8 @@
+@scope (.__Form) {
+ :scope {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ max-width: 26rem;
+ }
+} \ No newline at end of file
diff --git a/src/components/Form.tsx b/src/components/Form.tsx
new file mode 100644
index 0000000..595e323
--- /dev/null
+++ b/src/components/Form.tsx
@@ -0,0 +1,17 @@
+import { ComponentChildren } from 'preact';
+import './Form.css';
+
+export interface FormProps {
+ children: ComponentChildren;
+ onSubmit?: (event: SubmitEvent) => void;
+}
+
+const Form = ({ onSubmit, children }: FormProps) => {
+ return (
+ <form class="__Form" onSubmit={onSubmit}>
+ {children}
+ </form>
+ );
+};
+
+export default Form; \ No newline at end of file
diff --git a/src/components/FormLabel.css b/src/components/FormLabel.css
new file mode 100644
index 0000000..32f9c9b
--- /dev/null
+++ b/src/components/FormLabel.css
@@ -0,0 +1,8 @@
+@scope (.__FormLabel) {
+ :scope {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ color: var(--subtext);
+ }
+} \ No newline at end of file
diff --git a/src/components/FormLabel.tsx b/src/components/FormLabel.tsx
new file mode 100644
index 0000000..951bb61
--- /dev/null
+++ b/src/components/FormLabel.tsx
@@ -0,0 +1,16 @@
+import { ComponentChildren } from 'preact';
+import './FormLabel.css';
+
+export interface FormLabelProps {
+ children: ComponentChildren;
+}
+
+const FormLabel = ({ children }: FormLabelProps) => {
+ return (
+ <label class="__FormLabel">
+ {children}
+ </label>
+ );
+};
+
+export default FormLabel; \ No newline at end of file
diff --git a/src/components/Header.css b/src/components/Header.css
new file mode 100644
index 0000000..ef1dd60
--- /dev/null
+++ b/src/components/Header.css
@@ -0,0 +1,21 @@
+@scope (.__Header) {
+ :scope {
+ height: 3rem;
+ border-bottom: 1px solid var(--overlay);
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ > .title {
+ font-weight: 500;
+ width: fit-content;
+ }
+
+ nav {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
new file mode 100644
index 0000000..32fbce2
--- /dev/null
+++ b/src/components/Header.tsx
@@ -0,0 +1,22 @@
+import { ComponentChildren } from 'preact';
+import Button from './Button.tsx';
+import './Header.css';
+
+export interface HeaderProps {
+ children: ComponentChildren;
+}
+
+const Header = ({ children }: HeaderProps) => {
+ return (
+ <header class="__Header">
+ <div class="title">
+ <Button kind="ghost" href="/">DataNodes</Button>
+ </div>
+ <nav>
+ {children}
+ </nav>
+ </header>
+ );
+};
+
+export default Header; \ No newline at end of file
diff --git a/src/components/TextInput.css b/src/components/TextInput.css
new file mode 100644
index 0000000..bb04415
--- /dev/null
+++ b/src/components/TextInput.css
@@ -0,0 +1,17 @@
+@scope (.__TextInput) {
+ :scope {
+ background-color: var(--surface);
+ color: var(--text);
+ height: 2.5rem;
+ padding: 0 0.5rem;
+ border: none;
+ border-bottom: 2px solid color-mix(in srgb, white 20%, var(--surface));
+ font-size: 1rem;
+
+ &:focus {
+ outline: 2px solid var(--primary);
+ border-bottom: none;
+ margin-bottom: 2px;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/components/TextInput.tsx b/src/components/TextInput.tsx
new file mode 100644
index 0000000..026b062
--- /dev/null
+++ b/src/components/TextInput.tsx
@@ -0,0 +1,26 @@
+import { useCallback } from 'preact/hooks';
+import type { Signal } from '@preact/signals';
+import './TextInput.css';
+
+export interface TextInputProps {
+ signal?: Signal<string>;
+ props: Record<string, any>;
+}
+
+const TextInput = ({ signal, ...props }: TextInputProps) => {
+ const onInputSignal = useCallback((event: InputEvent) => {
+ signal.value = event.target.value;
+ }, [signal]);
+
+ return (
+ <input
+ type="text"
+ {...props}
+ class={(props.class || '') + ' __TextInput'}
+ value={signal || props.value}
+ onInput={signal ? onInputSignal : props.onInput}
+ />
+ );
+};
+
+export default TextInput; \ No newline at end of file
diff --git a/src/components/index.ts b/src/components/index.ts
new file mode 100644
index 0000000..1beca4d
--- /dev/null
+++ b/src/components/index.ts
@@ -0,0 +1,8 @@
+export { default as Header } from './Header.tsx';
+export { default as TextInput } from './TextInput.tsx';
+export { default as Button } from './Button.tsx';
+export { default as ArrowButton } from './ArrowButton.tsx';
+export { default as ContainedList } from './ContainedList.tsx';
+export { default as FormLabel } from './FormLabel.tsx';
+export { default as Content } from './Content.tsx';
+export { default as Form } from './Form.tsx'; \ No newline at end of file