Messing around
This commit is contained in:
parent
0b4889763e
commit
a5a39844a3
36 changed files with 2001 additions and 1 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
dist
|
10
README.md
10
README.md
|
@ -1,3 +1,11 @@
|
||||||
# frontend-web
|
# frontend-web
|
||||||
|
|
||||||
todo
|
work in progress, todo: write readme.md
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pnpm install
|
||||||
|
$ pnpm run dev # for development
|
||||||
|
$ pnpm run build # for production
|
||||||
|
```
|
||||||
|
|
8
config.md
Normal file
8
config.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# config/interactions
|
||||||
|
|
||||||
|
detailing the degrees of freedom
|
||||||
|
|
||||||
|
## threads
|
||||||
|
|
||||||
|
- show/hide unread threads
|
||||||
|
- show/hide ignored threads
|
19
design.md
Normal file
19
design.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# design notes
|
||||||
|
|
||||||
|
## colors
|
||||||
|
|
||||||
|
- text:
|
||||||
|
- text dim:
|
||||||
|
- text bright:
|
||||||
|
- background:
|
||||||
|
- background-dim:
|
||||||
|
- background-dim-2:
|
||||||
|
- background-dim-3:
|
||||||
|
- accent:
|
||||||
|
- link:
|
||||||
|
|
||||||
|
## fonts
|
||||||
|
|
||||||
|
- main: Atkinson Hyperlegible
|
||||||
|
- display:
|
||||||
|
- monospace:
|
13
index.html
Normal file
13
index.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>jackwagon</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
20
package.json
Normal file
20
package.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"name": "frontend-sdk",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"sdk": "git+https://git.celery.eu.org/jackwagon/sdk-ts",
|
||||||
|
"solid-js": "^1.8.7"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"sass": "^1.69.5",
|
||||||
|
"typescript": "^5.3.2",
|
||||||
|
"vite": "^5.0.5",
|
||||||
|
"vite-plugin-solid": "^2.7.2"
|
||||||
|
}
|
||||||
|
}
|
1230
pnpm-lock.yaml
Normal file
1230
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
1
public/vite.svg
Normal file
1
public/vite.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
222
src/App.scss
Normal file
222
src/App.scss
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
#root {
|
||||||
|
display: grid;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
grid-template-areas: "nav-spaces header header header"
|
||||||
|
"nav-spaces nav-rooms main sidebar"
|
||||||
|
"status status main sidebar";
|
||||||
|
grid-template-columns: 64px 256px 1fr 256px;
|
||||||
|
grid-template-rows: 64px 1fr 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
background: var(--background-3);
|
||||||
|
grid-area: header;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
background: var(--background-1);
|
||||||
|
grid-area: main;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
& > .timeline {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .actions {
|
||||||
|
height: 72px;
|
||||||
|
background: var(--background-2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 8px;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
& > .create-thread {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 2px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
padding: 4px;
|
||||||
|
background: #46c;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav-rooms {
|
||||||
|
background: var(--background-2);
|
||||||
|
grid-area: nav-rooms;
|
||||||
|
|
||||||
|
& > ul {
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
& > li {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px 8px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffffff33;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav-spaces {
|
||||||
|
background: var(--background-4);
|
||||||
|
grid-area: nav-spaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
background: var(--background-2);
|
||||||
|
grid-area: sidebar;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
background: var(--background-3);
|
||||||
|
grid-area: status;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline-thread {
|
||||||
|
--title-font-size: calc(1rem * 1.2);
|
||||||
|
--info-font-size: calc(1rem * 1);
|
||||||
|
display: grid;
|
||||||
|
padding: 4px;
|
||||||
|
gap: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
grid-template-columns: var(--title-font-size) 1fr;
|
||||||
|
grid-template-rows: var(--title-font-size) var(--info-font-size);
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #00000022;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .icon {
|
||||||
|
background: #34363b;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .title {
|
||||||
|
font-size: var(--title-font-size);
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .info {
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
font-size: var(--info-font-size);
|
||||||
|
color: var(--foreground-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
padding: 4px;
|
||||||
|
background: #555;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
contain: content;
|
||||||
|
// padding: 4px;
|
||||||
|
|
||||||
|
&.compact {
|
||||||
|
--name-width: 144px;
|
||||||
|
|
||||||
|
&.title {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .name {
|
||||||
|
position: absolute;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 8px;
|
||||||
|
max-width: var(--name-width);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .content {
|
||||||
|
margin-left: calc(var(--name-width) + 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .avatar, & .space {
|
||||||
|
margin-left: 8px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cozy {
|
||||||
|
&.title {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .name {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .content {
|
||||||
|
margin-left: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .avatar, & .space {
|
||||||
|
margin-left: 8px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .avatar, & .space {
|
||||||
|
height: 36px;
|
||||||
|
width: 36px;
|
||||||
|
|
||||||
|
&.avatar {
|
||||||
|
background: #822eba;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& a {
|
||||||
|
color: #822eba;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #00000022;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
height: 72px;
|
||||||
|
background: var(--background-2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 8px;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
& > textarea {
|
||||||
|
background: var(--background-1);
|
||||||
|
border: solid var(--background-4) 1px;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 100%;
|
||||||
|
height: 3rem;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
}
|
147
src/App.tsx
Normal file
147
src/App.tsx
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
import { VoidProps, createSignal, onCleanup } from "solid-js";
|
||||||
|
import "./App.scss";
|
||||||
|
import { Client, Room, Timeline } from "sdk";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const client = new Client({
|
||||||
|
baseUrl: "http://localhost:6167",
|
||||||
|
deviceId: "PFXhfDYmCc",
|
||||||
|
token: "Ebh15YkyCBJSFjP11oimVEtAdqL9ZXcl",
|
||||||
|
userId: "@user:localhost",
|
||||||
|
});
|
||||||
|
|
||||||
|
const [rooms, setRooms] = createSignal({ count: 0, rooms: [] as Array<Room> });
|
||||||
|
const [room, setRoom] = createSignal(null as null | Room);
|
||||||
|
const [asdf, setAsdf] = createSignal(true);
|
||||||
|
|
||||||
|
Object.assign(globalThis, { client });
|
||||||
|
|
||||||
|
client.lists.subscribe("rooms", {
|
||||||
|
ranges: [[0, 120]],
|
||||||
|
required_state: [["m.room.name", ""],["m.room.topic", ""]],
|
||||||
|
// timeline_limit: 3,
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
client.on("list", (name, list) => {
|
||||||
|
if (name === "rooms") setRooms({ ...list });
|
||||||
|
});
|
||||||
|
|
||||||
|
client.start();
|
||||||
|
onCleanup(() => client.stop());
|
||||||
|
|
||||||
|
const [offset, setOffset] = createSignal(0);
|
||||||
|
const interval = setInterval(() => setOffset(offset() + 1), 100);
|
||||||
|
onCleanup(() => clearInterval(interval));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<header id="header" onClick={() => setAsdf(!asdf())}>
|
||||||
|
{room()?.id} {room()?.getState("m.room.name")?.content.name}
|
||||||
|
</header>
|
||||||
|
<main id="main">{asdf() ? <>
|
||||||
|
<Threads />
|
||||||
|
<div class="actions">
|
||||||
|
<TimelineActions />
|
||||||
|
</div>
|
||||||
|
</> : <>
|
||||||
|
<EventTimeline timeline={room()?.timelines.live || undefined} />
|
||||||
|
<div class="input">
|
||||||
|
<textarea placeholder="input text here"></textarea>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</main>
|
||||||
|
<nav id="nav-rooms">
|
||||||
|
<ul>
|
||||||
|
<li onClick={() => setRoom(null)}>home</li>
|
||||||
|
{rooms().rooms.map(i => <li onClick={() => setRoom(i)}>{i.getState("m.room.name")?.content.name}</li>)}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<nav id="nav-spaces"></nav>
|
||||||
|
<div id="sidebar">
|
||||||
|
<EventTimeline timeline={room()?.timelines.live} />
|
||||||
|
<div class="input">
|
||||||
|
<textarea placeholder="input text here"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer id="status"></footer>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Threads() {
|
||||||
|
return (
|
||||||
|
<div class="timeline">
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
<ThreadsItem />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EventTimeline(props: VoidProps<{ timeline: Timeline | undefined }>) {
|
||||||
|
return (
|
||||||
|
<div class="timeline">
|
||||||
|
{props.timeline?.events.map(i => <Message event={i} />)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Message(props: VoidProps<{ event: any }>) {
|
||||||
|
const title = Math.random() > .5;
|
||||||
|
const compact = false;
|
||||||
|
|
||||||
|
return <div class="message" classList={{ title, [compact ? "compact" : "cozy"]: true }}>
|
||||||
|
{title && !compact && <div class="avatar"></div>}
|
||||||
|
{title && compact && <div class="name">{props.event.sender}</div>}
|
||||||
|
<div class="content">
|
||||||
|
{title && !compact && <div class="name">{props.event.sender}</div>}
|
||||||
|
<div class="body">{props.event.content.body || `event: (${props.event.type})`}</div>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ThreadsItem() {
|
||||||
|
return <div class="timeline-thread">
|
||||||
|
<div class="icon"></div>
|
||||||
|
<div class="title">Thread title</div>
|
||||||
|
<div class="info">Info here, date created, other options</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TimelineActions() {
|
||||||
|
return <>
|
||||||
|
<Toggle enabled="[x] Include ignored" disabled="[ ] Include ignored" initial={false} />
|
||||||
|
<Toggle enabled="[x] Unread" disabled="[ ] Unread" initial={false} />
|
||||||
|
<Toggle enabled="[x] Watching" disabled="[ ] Watching" initial={false} />
|
||||||
|
<div class="create-thread">
|
||||||
|
<div>New thread</div>
|
||||||
|
<div>+</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Toggle(props: { enabled: string, disabled: string, initial: boolean }) {
|
||||||
|
const [disabled, setDisabled] = createSignal(props.initial);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class="toggle"
|
||||||
|
classList={{ disabled: disabled() }}
|
||||||
|
onClick={() => setDisabled(!disabled())}
|
||||||
|
>{disabled() ? props.enabled : props.disabled}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
93
src/assets/fonts/atkinson-hyperlegible/OFL.txt
Normal file
93
src/assets/fonts/atkinson-hyperlegible/OFL.txt
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2020 Braille Institute of America, Inc.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold-extended-italic.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold-extended-italic.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold-extended.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold-extended.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold-italic.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold-italic.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty-bold.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/iosevka/iosevka-zesty-extended-italic.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty-extended-italic.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/iosevka/iosevka-zesty-extended.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty-extended.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/iosevka/iosevka-zesty-italic.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty-italic.ttf
Normal file
Binary file not shown.
BIN
src/assets/fonts/iosevka/iosevka-zesty.ttf
Normal file
BIN
src/assets/fonts/iosevka/iosevka-zesty.ttf
Normal file
Binary file not shown.
1
src/assets/solid.svg
Normal file
1
src/assets/solid.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 166 155.3"><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>
|
After Width: | Height: | Size: 1.6 KiB |
39
src/fonts.scss
Normal file
39
src/fonts.scss
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(./assets/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Regular.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(./assets/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Bold.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: normal;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(./assets/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Italic.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: bold;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(./assets/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Iosevka Zesty";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(./assets/fonts/iosevka/iosevka-zesty.ttf);
|
||||||
|
}
|
39
src/index.scss
Normal file
39
src/index.scss
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
@import "./fonts.scss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font: 16px/1.5 "Atkinson Hyperlegible", Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
--background-1: #24262b;
|
||||||
|
--background-2: #1e2024;
|
||||||
|
--background-3: #191b1d;
|
||||||
|
--background-4: #17181a;
|
||||||
|
--foreground-1: #eae8efdd;
|
||||||
|
--foreground-2: #eae8efb4;
|
||||||
|
|
||||||
|
color: var(--foreground-1);
|
||||||
|
|
||||||
|
// --background-1: #1a1923;
|
||||||
|
// --background-2: #14131d;
|
||||||
|
// --background-3: #100e18;
|
||||||
|
// --background-4: #0a0e11;
|
||||||
|
|
||||||
|
/*
|
||||||
|
--fg-text: #c7c6ca;
|
||||||
|
--fg-link: #b18cf3;
|
||||||
|
--fg-dimmed: #7f879b;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
7
src/index.tsx
Normal file
7
src/index.tsx
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/* @refresh reload */
|
||||||
|
import { render } from "solid-js/web";
|
||||||
|
import "./index.scss";
|
||||||
|
import App from "./App";
|
||||||
|
|
||||||
|
const root = document.getElementById("root");
|
||||||
|
render(() => <App />, root!);
|
20
src/interesting.tsx
Normal file
20
src/interesting.tsx
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
function Dots(props: any) {
|
||||||
|
return (
|
||||||
|
<svg width="100%">
|
||||||
|
<line stroke-dasharray="
|
||||||
|
10, 10, 30, 10, 30, 10, 30, 30,
|
||||||
|
10, 10, 30, 30,
|
||||||
|
30, 10, 10, 10, 30, 10, 10, 30,
|
||||||
|
30, 10, 10, 10, 30, 30,
|
||||||
|
10, 10, 30, 10, 30, 30,
|
||||||
|
10, 10, 30, 30,
|
||||||
|
30, 10, 30, 10, 10, 30,
|
||||||
|
30, 10, 30, 10, 30, 30,
|
||||||
|
30, 10, 10, 30"
|
||||||
|
x1="0" y1="5px" x2="100%" y2="5px"
|
||||||
|
style="stroke: var(--background-2)" stroke-width="10"
|
||||||
|
stroke-dashoffset={props.offset()}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
46
src/service.ts
Normal file
46
src/service.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// A *service worker*, to cache and provide data offline
|
||||||
|
|
||||||
|
// self.addEventListener("install", () => {
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// self.addEventListener("fetch", (event) => {
|
||||||
|
// // const { request } = event;
|
||||||
|
// // if (request.url === "/" && request.method === "GET") {
|
||||||
|
|
||||||
|
// // event.respondWith(
|
||||||
|
// // fetch(request).catch(function(error) {
|
||||||
|
// // // `fetch()` throws an exception when the server is unreachable but not
|
||||||
|
// // // for valid HTTP responses, even `4xx` or `5xx` range.
|
||||||
|
// // console.error(
|
||||||
|
// // '[onfetch] Failed. Serving cached offline fallback ' +
|
||||||
|
// // error
|
||||||
|
// // );
|
||||||
|
// // return caches.open('offline').then(function(cache) {
|
||||||
|
// // return cache.match('offline.html');
|
||||||
|
// // });
|
||||||
|
// // })
|
||||||
|
// // );
|
||||||
|
// // }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /*
|
||||||
|
// self.addEventListener('install', function(event) {
|
||||||
|
// // Put `offline.html` page into cache
|
||||||
|
// var offlineRequest = new Request('offline.html');
|
||||||
|
// event.waitUntil(
|
||||||
|
// fetch(offlineRequest).then(function(response) {
|
||||||
|
// return caches.open('offline').then(function(cache) {
|
||||||
|
// console.log('[oninstall] Cached offline page', response.url);
|
||||||
|
// return cache.put(offlineRequest, response);
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
// self.addEventListener('push', function(event) {
|
||||||
|
// event.waitUntil(
|
||||||
|
// self.registration.showNotification(title, { body })
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
// */
|
21
src/state.ts
Normal file
21
src/state.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// (possibly persisted) state in the app
|
||||||
|
|
||||||
|
interface GlobalState {
|
||||||
|
// - popups
|
||||||
|
// - emoji picker
|
||||||
|
// - recent rooms
|
||||||
|
// - main is threads, timeline
|
||||||
|
// - sidebar is members, timeline
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RoomState {
|
||||||
|
// - scroll position
|
||||||
|
// - new thread config
|
||||||
|
// - uploading files
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ThreadState {
|
||||||
|
// - scroll position
|
||||||
|
// - message config (input, reply, edit)
|
||||||
|
// - uploading files
|
||||||
|
}
|
19
src/util.ts
Normal file
19
src/util.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
class Lru {
|
||||||
|
private items: Array<string> = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly max: number,
|
||||||
|
private dispose: (id: string) => void,
|
||||||
|
) {
|
||||||
|
if (max <= 0) throw new Error("max can't be zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
touch(id: string) {
|
||||||
|
const idx = this.items.indexOf(id);
|
||||||
|
if (idx !== -1) this.items.splice(idx, 1);
|
||||||
|
this.items.push(id);
|
||||||
|
if (this.items.length > this.max) {
|
||||||
|
this.dispose(this.items.shift()!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="vite/client" />
|
1
src/worker.ts
Normal file
1
src/worker.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// A *shared worker*, to efficiently sync between multiple sessions?
|
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "solid-js",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
10
tsconfig.node.json
Normal file
10
tsconfig.node.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
6
vite.config.ts
Normal file
6
vite.config.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import solid from 'vite-plugin-solid'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [solid()],
|
||||||
|
})
|
Loading…
Reference in a new issue