Skip to content

Commit 75d36c9

Browse files
committed
sketch: mobile-first ui
1 parent ec88b63 commit 75d36c9

File tree

14 files changed

+354
-24
lines changed

14 files changed

+354
-24
lines changed

package-lock.json

Lines changed: 4 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"@e280/renraku": "^0.5.0",
3333
"@e280/sly": "^0.2.0-16",
3434
"@e280/strata": "^0.2.0-13",
35-
"@e280/stz": "^0.2.5"
35+
"@e280/stz": "^0.2.5",
36+
"lit": "^3.3.1"
3637
},
3738
"devDependencies": {
3839
"@e280/science": "^0.1.2",

s/index.html.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,18 @@ export default ssg.page(import.meta.url, async orb => ({
2525
<link rel="preconnect" href="https://fonts.googleapis.com">
2626
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
2727
<link href="https://fonts.googleapis.com/css2?family=Alan+Sans:[email protected]&display=swap" rel="stylesheet">
28+
<meta content="app-version" value="${orb.packageVersion()}"/>
2829
`,
2930

3031
body: html`
31-
<img class=logo src="/assets/olive.png" alt=""/>
32-
<h1>Olive Support</h1>
33-
<p>Cheap, good, customer support.</p>
34-
<p class=version>v${orb.packageVersion()}</p>
32+
<olive-app>
33+
<section>
34+
<img class=logo src="/assets/olive.png" alt=""/>
35+
<h1>Olive Support</h1>
36+
<p>Simple secure customer support.</p>
37+
<p class=version>v${orb.packageVersion()}</p>
38+
</section>
39+
</olive-app>
3540
`,
3641
}))
3742

s/main.bundle.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11

2-
console.log("Olive")
2+
import {dom} from "@e280/sly"
3+
import {OliveApp} from "./ui/app/component.js"
4+
5+
dom.register({OliveApp})
36

s/main.css

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
color-scheme: dark;
77
--link: cyan;
88
--prime: #A1C33F;
9-
--bg: #35391C;
9+
--special: yellow;
1010
--bg: #313422;
1111
}
1212
}
@@ -43,13 +43,13 @@
4343
}
4444

4545
@layer basics {
46-
html { height: 100%; }
47-
body { min-height: 100%; }
46+
html, body { height: 100%; }
4847
html {
4948
font-family: "Alan Sans", sans-serif;
50-
font-size: 16px;
49+
font-size: 12px;
5150
color: var(--prime);
5251
background: var(--bg);
52+
text-shadow: 0.1em 0.1em 0.2em #0008;
5353
}
5454
}
5555

@@ -58,11 +58,38 @@
5858
display: flex;
5959
flex-direction: column;
6060
align-items: center;
61-
max-width: 32em;
62-
margin: auto;
63-
padding: 2em 0;
64-
gap: 1em;
65-
text-shadow: 0.1em 0.1em 0.2em #0008;
61+
padding: clamp(0em, calc(5vw - 3em), 4em);
62+
}
63+
64+
olive-app {
65+
width: 50em;
66+
height: 80em;
67+
max-width: 100%;
68+
max-height: 100%;
69+
70+
background: #0002;
71+
border-bottom: 1px solid #fff2;
72+
border-radius: clamp(0em, calc(5vw - 3em), 2em);
73+
box-shadow:
74+
inset 0.1em 0.2em 3em #0004,
75+
0.1em 0.2em 2em #0002;
76+
77+
section {
78+
display: flex;
79+
flex-direction: column;
80+
justify-content: center;
81+
align-items: center;
82+
gap: 1em;
83+
height: 100%;
84+
&::before, &::after {
85+
content: "";
86+
display: block;
87+
flex: 1 1 auto;
88+
}
89+
&::after {
90+
flex-grow: 3;
91+
}
92+
}
6693
}
6794

6895
.logo {

s/ui/app/component.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
import {html} from "lit"
3+
import {view} from "@e280/sly"
4+
5+
import {Router} from "../router.js"
6+
import styleCss from "./style.css.js"
7+
import {Context} from "../context.js"
8+
import themeCss from "../theme.css.js"
9+
import menu2Svg from "../icons/tabler/menu-2.svg.js"
10+
import {DashboardView} from "../pages/dashboard/view.js"
11+
12+
export class OliveApp extends (view.component(use => {
13+
use.css(themeCss, styleCss)
14+
15+
const context = use.once(() => new Context())
16+
const router = use.once(() => new Router(
17+
[/^$/, () => DashboardView.props(context).children(html`<slot></slot>`).render()],
18+
[/^#\/a\/$/, () => html`account`],
19+
[/^#\/o\/$/, () => html`orglist`],
20+
[/^#\/o\/(\w+)$/, orgId => html`org ${orgId}`],
21+
[/^#\/c\/$/, () => html`chatlist`],
22+
[/^#\/c\/(\w+)$/, chatId => html`chat ${chatId}`],
23+
[/.*/, () => html`404 not found`],
24+
))
25+
26+
const {hash} = router
27+
const $navOpen = use.signal(false)
28+
29+
const toggleNav = () => $navOpen(!$navOpen())
30+
const closeNav = () => $navOpen(false)
31+
32+
const renderLink = (label: string, url: string, isActive: boolean) => html`
33+
<a
34+
href="${url}"
35+
?data-active="${isActive}"
36+
@click="${closeNav}">
37+
${label}
38+
</a>
39+
`
40+
41+
return html`
42+
<nav ?data-open="${$navOpen()}">
43+
<button theme=icon @click="${toggleNav}">${menu2Svg}</button>
44+
<div class=navplate ?inert="${!$navOpen()}">
45+
<header>
46+
<img alt="" src="/assets/olive.png"/>
47+
<div>
48+
<h1>Olive Support <small>v${context.version}</small></h1>
49+
<p>Simple secure customer support.</p>
50+
</div>
51+
</header>
52+
<div class=links>
53+
${renderLink("Dashboard", "#/", hash === "")}
54+
${renderLink("Account", "#/a/", hash.startsWith("#/a/"))}
55+
${renderLink("Orgs", "#/o/", hash.startsWith("#/a/"))}
56+
${renderLink("Chats", "#/c/", hash.startsWith("#/c/"))}
57+
</div>
58+
</div>
59+
</nav>
60+
61+
<main>${router.$content()}</main>
62+
63+
<div class=blanket
64+
?inert="${!$navOpen()}"
65+
?data-active="${$navOpen()}"
66+
@click="${closeNav}">
67+
</div>
68+
`
69+
})) {}
70+

s/ui/app/style.css.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
2+
import {css} from "lit"
3+
export default css`
4+
5+
:host {
6+
display: block;
7+
position: relative;
8+
overflow: hidden;
9+
--anim: 250ms;
10+
}
11+
12+
nav { z-index: 2; }
13+
.blanket { z-index: 1; }
14+
15+
nav {
16+
position: absolute;
17+
left: 0;
18+
width: 85%;
19+
user-select: none;
20+
21+
will-change: transform;
22+
transform: translateX(0);
23+
transition: transform var(--anim) ease;
24+
25+
> button {
26+
position: absolute;
27+
z-index: 1;
28+
left: 100%;
29+
top: 0;
30+
padding: 0.2em;
31+
color: inherit;
32+
svg {
33+
width: 3em;
34+
height: 3em;
35+
}
36+
}
37+
38+
> .navplate {
39+
font-size: 1.5em;
40+
background: #0004;
41+
border-bottom-right-radius: 1em;
42+
overflow: hidden;
43+
44+
header {
45+
display: flex;
46+
align-items: center;
47+
gap: 1em;
48+
padding: 1em;
49+
background: #fff4;
50+
51+
img {
52+
width: 4em;
53+
max-width: 20%;
54+
height: auto;
55+
}
56+
57+
small {
58+
position: relative;
59+
bottom: 0.2em;
60+
font-weight: normal;
61+
font-size: 0.5em;
62+
color: var(--special);
63+
}
64+
}
65+
66+
.links {
67+
display: flex;
68+
flex-direction: column;
69+
align-items: start;
70+
gap: 1em;
71+
padding: 1em 20%;
72+
}
73+
}
74+
75+
&:not([data-open]) {
76+
transform: translateX(-100%);
77+
}
78+
}
79+
80+
main {
81+
padding-top: 4em;
82+
height: 100%;
83+
}
84+
85+
.blanket {
86+
pointer-events: none;
87+
position: absolute;
88+
inset: 0;
89+
90+
will-change: background, backdrop-filter;
91+
transition:
92+
background var(--anim) linear,
93+
backdrop-filter var(--anim) linear;
94+
95+
96+
&[data-active] {
97+
pointer-events: all;
98+
backdrop-filter: blur(1em);
99+
background: #0004;
100+
}
101+
}
102+
103+
`
104+

s/ui/context.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
export class Context {
3+
readonly version = document.head
4+
.querySelector(`meta[content="app-version"]`)!
5+
.getAttribute("value")!
6+
}
7+

s/ui/icons/tabler/LICENSE

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
MIT License
3+
4+
Copyright (c) 2020-2025 Paweł Kuna
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
23+

s/ui/icons/tabler/menu-2.svg.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
import {svg} from "lit"
3+
4+
export default svg`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-menu-2"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 6l16 0" /><path d="M4 12l16 0" /><path d="M4 18l16 0" /></svg>`
5+

0 commit comments

Comments
 (0)