Skip to content

Commit 4409048

Browse files
committed
Merge branch 'main' into feat/select-component
2 parents 82f72e5 + e359afa commit 4409048

File tree

22 files changed

+295
-35
lines changed

22 files changed

+295
-35
lines changed

apps/solid/src/App.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ import '@spuxx/browser-utils/themes';
44
import { For, type Component } from 'solid-js';
55
import './styles/index.css';
66
import { routes } from './routes/routes';
7+
import { AppLayout } from './layout/app.layout';
78

89
const App: Component = () => {
910
return (
10-
<main>
11+
<AppLayout>
1112
<Router>
1213
<For each={routes}>
1314
{(route) => <Route path={route.path} component={route.component} />}
1415
</For>
1516
</Router>
16-
</main>
17+
</AppLayout>
1718
);
1819
};
1920

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { AppBar, Button } from '@spuxx/solid';
2+
3+
export const BottomAppBar = () => {
4+
return (
5+
<AppBar position="bottom" tag="footer">
6+
<AppBar.Section>
7+
<a href="https://spuxx.dev">
8+
<Button variant="colored" color="text-default" rounded>
9+
Made with ❤️ by spuxx
10+
</Button>
11+
</a>
12+
</AppBar.Section>
13+
</AppBar>
14+
);
15+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { AppBar, Button } from '@spuxx/solid';
2+
3+
export const TopAppBar = () => {
4+
return (
5+
<AppBar>
6+
<AppBar.Section>
7+
<a href="/">
8+
<Button icon="mdi:menu" title="Menu" variant="colored" color="text-default" rounded />
9+
</a>
10+
</AppBar.Section>
11+
<AppBar.Section>
12+
<a href="/">
13+
<Button title="Home" variant="colored" color="text-default" rounded>
14+
@spuxx/solid
15+
</Button>
16+
</a>
17+
</AppBar.Section>
18+
<AppBar.Section>
19+
<a href="https://github.com/spuxx-dev/jslibs" target="_blank">
20+
<Button icon="mdi:github" title="GitHub" variant="colored" color="text-default" rounded />
21+
</a>
22+
</AppBar.Section>
23+
</AppBar>
24+
);
25+
};

apps/solid/src/layout/app.layout.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Component, ParentProps } from 'solid-js';
2+
import { TopAppBar } from './app-bars/top-app-bar.component';
3+
import { BottomAppBar } from './app-bars/bottom-app-bar.component';
4+
5+
export const AppLayout: Component<ParentProps> = (props) => {
6+
return (
7+
<>
8+
<TopAppBar />
9+
<main>{props.children}</main>
10+
<BottomAppBar />
11+
</>
12+
);
13+
};

apps/solid/src/routes/components/control/input.route.tsx

+13-16
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,12 @@ export const InputRoute: Component = () => {
8484
<For each={variants}>
8585
{(variant) => (
8686
<>
87-
<Input
88-
label="Username"
89-
class="m-1"
90-
icon="mdi:account"
91-
attrs={{ type: 'text' }}
92-
variant={variant}
93-
/>
87+
<Input label="Username" class="m-1" icon="mdi:account" variant={variant} />
9488
<Input
9589
label="Password"
9690
class="m-1"
9791
icon="mdi:lock"
98-
attrs={{ type: 'password' }}
92+
type="password"
9993
variant={variant}
10094
/>
10195
</>
@@ -108,24 +102,27 @@ export const InputRoute: Component = () => {
108102
<For each={variants}>
109103
{(variant) => (
110104
<>
111-
<Input
112-
label="Username"
113-
class="m-1"
114-
icon="mdi:account"
115-
attrs={{ type: 'text' }}
116-
variant={variant}
117-
/>
105+
<Input label="Username" class="m-1" icon="mdi:account" variant={variant} />
118106
<Input
119107
label="Password"
120108
class="m-1"
121109
icon="mdi:lock"
122-
attrs={{ type: 'password' }}
110+
type="password"
123111
variant={variant}
124112
/>
125113
</>
126114
)}
127115
</For>
128116
</Container>
117+
<Container variant="contained" color="surface">
118+
<Heading level={2}>On Surface</Heading>
119+
<Divider color="gradient" />
120+
<For each={variants}>
121+
{(variant) => (
122+
<Input label="Username" class="m-1" icon="mdi:account" variant={variant} />
123+
)}
124+
</For>
125+
</Container>
129126
</Container>
130127
</>
131128
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
title: 'App Bar'
3+
description: |
4+
The App Bar is a component that can be used to display content and actions related to the
5+
current screen.
6+
---
7+
8+
import TypeDoc from '@docs/solid/components/layout/app-bar.md';
9+
import { BaseColor } from '@packages/browser-utils';
10+
import { Interactive } from '@src/components/interactive';
11+
12+
The App Bar is a component that can be used to display content and actions related to the
13+
current screen.
14+
15+
<TypeDoc />

packages/browser-utils/src/styles.css

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
@import './styles/layout.css';
77
@import './styles/application.css';
8+
@import './styles/text.css';
89

910
@import './styles/components.css';
1011
@import './styles/modal.css';

packages/browser-utils/src/styles/application.css

+14-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ html.spx-app {
33
color: var(--spx-color-on-background);
44
height: 100svh;
55
width: 100svw;
6-
overflow-y: hidden;
6+
overflow-y: auto;
77
overflow-x: hidden;
88
font-family:
99
ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
@@ -20,6 +20,19 @@ html.spx-app {
2020
padding: 1rem;
2121
}
2222
}
23+
24+
&:has(.spx-app-bar[spx-position='top']) {
25+
scroll-margin: var(--spx-app-bar-height);
26+
> body {
27+
padding-top: var(--spx-app-bar-height);
28+
}
29+
}
30+
31+
&:has(.spx-app-bar[spx-position='bottom']) {
32+
> body {
33+
padding-bottom: var(--spx-app-bar-height);
34+
}
35+
}
2336
}
2437

2538
@media only screen and (max-width: 600px) {
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@import './components/control/button.css';
22
@import './components/control/input.css';
33
@import './components/control/select.css';
4+
@import './components/layout/app-bar.css';
45
@import './components/layout/divider.css';
56
@import './components/layout/container.css';
67
@import './components/typography/heading.css';

packages/browser-utils/src/styles/components/control/button.css

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
.spx-button:not(:has(.spx-button-content)) {
4343
padding: 0px;
4444
aspect-ratio: 1/1;
45+
font-size: larger;
4546
}
4647

4748
.spx-button[spx-rounded] {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.spx-app-bar {
2+
position: fixed;
3+
z-index: var(--spx-z-app-bar);
4+
height: var(--spx-app-bar-height);
5+
width: 100svw;
6+
display: flex;
7+
flex-direction: row;
8+
align-items: center;
9+
justify-content: space-between;
10+
box-sizing: border-box;
11+
background: var(--spx-color-app-bar);
12+
color: var(--spx-color-on-app-bar);
13+
padding: 4px;
14+
box-shadow: var(--spx-shadow-medium);
15+
16+
&[spx-position='top'] {
17+
top: 0;
18+
}
19+
20+
&[spx-position='bottom'] {
21+
bottom: 0;
22+
}
23+
24+
&:has(.spx-app-bar-section:only-child) {
25+
justify-content: center;
26+
}
27+
}

packages/browser-utils/src/styles/layout.css

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
:root {
22
--spx-z-modal: 85;
33
--spx-z-modal-overlay: 81;
4+
--spx-z-app-bar: 51;
45
}
56

67
.spx[spx-size='auto'] {

packages/browser-utils/src/styles/modal.css

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
border-radius: var(--spx-border-radius);
2020
width: fit-content;
2121
max-width: 80svw;
22+
box-shadow: var(--spx-shadow-medium);
2223
}
2324

2425
.spx-modal[data-open] {
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
html.spx-app {
2+
a:not(:has(.spx-button)) {
3+
text-decoration: none;
4+
5+
&:visited {
6+
color: var(--spx-color-text-link);
7+
}
8+
9+
&:hover {
10+
filter: var(--spx-filter-control-hover);
11+
}
12+
}
13+
}

packages/browser-utils/src/styles/variables.css

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
:root {
22
--spx-main-content-width: 1440px;
33

4+
--spx-app-bar-height: 48px;
45
--spx-control-height-default: 40px;
56
--spx-input-height-default: 48px;
67

packages/browser-utils/src/themes/default.theme.css

+14-7
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@ html *,
1010
--spx-color-text-default: #f5f5f5;
1111
--spx-color-text-subtle: #a1a1aa;
1212
--spx-color-text-highlighted: #ffffff;
13+
--spx-color-text-link: var(--spx-color-accent);
1314

1415
/* Base Colors */
15-
--spx-color-background: #18181b;
16+
--spx-color-background: #1a2327;
1617
--spx-color-on-background: var(--spx-color-text-default);
17-
--spx-color-surface: #3f3f46;
18+
--spx-color-surface: #303e46;
1819
--spx-color-on-surface: var(--spx-color-text-default);
19-
--spx-color-accent: #2dd4bf;
20+
--spx-color-accent: #00bfa5;
2021
--spx-color-on-accent: var(--spx-color-text-highlighted);
21-
--spx-color-primary: #0d9488;
22+
--spx-color-primary: #00796b;
2223
--spx-color-on-primary: var(--spx-color-text-highlighted);
23-
--spx-color-secondary: #3f3f46;
24+
--spx-color-secondary: #37474f;
2425
--spx-color-on-secondary: var(--spx-color-text-default);
25-
--spx-color-gradient: linear-gradient(45deg, var(--spx-color-primary), #a21caf);
26+
--spx-color-gradient: linear-gradient(45deg, var(--spx-color-accent), #aa00ff);
2627
--spx-color-on-gradient: var(--spx-color-text-highlighted);
28+
2729
/* Status Colors */
2830
--spx-color-info: var(--spx-color-surface);
2931
--spx-color-on-info: var(--spx-color-text-default);
@@ -44,7 +46,9 @@ html *,
4446
var(--spx-color-error) 66%
4547
);
4648

47-
/* Modal Dialog */
49+
/* App Layout Elements */
50+
--spx-color-app-bar: var(--spx-color-surface);
51+
--spx-color-on-app-bar: var(--spx-color-on-surface);
4852
--spx-color-modal: var(--spx-color-surface);
4953
--spx-color-on-modal: var(--spx-color-on-surface);
5054

@@ -53,6 +57,9 @@ html *,
5357
--spx-filter-control-hover-contained: brightness(0.8);
5458
--spx-filter-control-disabled: brightness(0.8) grayscale(0.6);
5559

60+
/* Shadows */
61+
--spx-shadow-medium: 0 0 10px rgba(0, 0, 0, 0.5);
62+
5663
/* Animations */
5764
transition:
5865
filter 100ms,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { render } from '@solidjs/testing-library';
2+
import { describe, it, expect } from 'vitest';
3+
import { AppBar } from './app-bar.component';
4+
5+
describe('AppBar', () => {
6+
it('should render with default values', () => {
7+
const { getByRole } = render(() => <AppBar />);
8+
const appBar = getByRole('banner');
9+
expect(appBar).toBeInTheDocument();
10+
expect(appBar.tagName).toBe('HEADER');
11+
expect(appBar).toHaveClass('spx', 'spx-app-bar');
12+
expect(appBar).toHaveAttribute('spx-position', 'top');
13+
expect(appBar.children).toHaveLength(0);
14+
});
15+
16+
it('should render with custom values', () => {
17+
const { getByRole } = render(() => <AppBar position="bottom" tag="nav" class="my-class" />);
18+
const appBar = getByRole('navigation');
19+
expect(appBar).toBeInTheDocument();
20+
expect(appBar.tagName).toBe('NAV');
21+
expect(appBar).toHaveClass('spx', 'spx-app-bar', 'my-class');
22+
expect(appBar).toHaveAttribute('spx-position', 'bottom');
23+
});
24+
25+
it('should render with children', () => {
26+
const { getByRole } = render(() => (
27+
<AppBar>
28+
<AppBar.Section>Left</AppBar.Section>
29+
<AppBar.Section>Center</AppBar.Section>
30+
<AppBar.Section>Right</AppBar.Section>
31+
</AppBar>
32+
));
33+
const appBar = getByRole('banner');
34+
expect(appBar).toBeInTheDocument();
35+
expect(appBar.children).toHaveLength(3);
36+
expect(appBar.children[0]).toHaveTextContent('Left');
37+
expect(appBar.children[1]).toHaveTextContent('Center');
38+
expect(appBar.children[2]).toHaveTextContent('Right');
39+
});
40+
});

0 commit comments

Comments
 (0)