Compare commits

..

No commits in common. "dev" and "dev" have entirely different histories.
dev ... dev

38 changed files with 199 additions and 29968 deletions

View file

@ -1,6 +1,6 @@
# autonomous.contact # autonomous.contact
A hub for communities as a single service with no required external dependencies. Bringing the BBS back.
## TODO ## TODO

View file

@ -11,15 +11,11 @@
"test": "DENO_ENV=test FSDB_ROOT=$PWD/tests/data/$(date --iso-8601=seconds) SERVERUS_ROOT=$PWD/public SERVERUS_PUT_PATHS_ALLOWED=./files SERVERUS_DELETE_PATHS_ALLOWED=./files deno test --allow-env --allow-read --allow-write --allow-net --allow-import --trace-leaks --fail-fast tests/" "test": "DENO_ENV=test FSDB_ROOT=$PWD/tests/data/$(date --iso-8601=seconds) SERVERUS_ROOT=$PWD/public SERVERUS_PUT_PATHS_ALLOWED=./files SERVERUS_DELETE_PATHS_ALLOWED=./files deno test --allow-env --allow-read --allow-write --allow-net --allow-import --trace-leaks --fail-fast tests/"
}, },
"test": { "test": {
"exclude": [ "exclude": ["tests/data/"]
"tests/data/"
]
}, },
"compilerOptions": {}, "compilerOptions": {},
"fmt": { "fmt": {
"include": [ "include": ["**/*.ts"],
"**/*.ts"
],
"options": { "options": {
"useTabs": true, "useTabs": true,
"lineWidth": 180, "lineWidth": 180,
@ -29,28 +25,22 @@
} }
}, },
"lint": { "lint": {
"include": [ "include": ["**/*.ts"],
"**/*.ts"
],
"rules": { "rules": {
"tags": [ "tags": ["recommended"],
"recommended" "exclude": ["no-explicit-any"]
],
"exclude": [
"no-explicit-any"
]
} }
}, },
"imports": { "imports": {
"@andyburke/fsdb": "jsr:@andyburke/fsdb@^1.2.4", "@andyburke/fsdb": "jsr:@andyburke/fsdb@^1.2.4",
"@andyburke/lurid": "jsr:@andyburke/lurid@^0.2.0", "@andyburke/lurid": "jsr:@andyburke/lurid@^0.2.0",
"@andyburke/serverus": "jsr:@andyburke/serverus@^0.16.0", "@andyburke/serverus": "jsr:@andyburke/serverus@^0.13.0",
"@da/bcrypt": "jsr:@da/bcrypt@^1.0.1", "@da/bcrypt": "jsr:@da/bcrypt@^1.0.1",
"@std/assert": "jsr:@std/assert@^1.0.17", "@std/assert": "jsr:@std/assert@^1.0.15",
"@std/encoding": "jsr:@std/encoding@^1.0.10", "@std/encoding": "jsr:@std/encoding@^1.0.10",
"@std/fs": "jsr:@std/fs@^1.0.22", "@std/fs": "jsr:@std/fs@^1.0.19",
"@std/http": "jsr:@std/http@^1.0.23", "@std/http": "jsr:@std/http@^1.0.21",
"@std/media-types": "jsr:@std/media-types@^1.1.0", "@std/media-types": "jsr:@std/media-types@^1.1.0",
"@std/path": "jsr:@std/path@^1.1.4" "@std/path": "jsr:@std/path@^1.1.2"
} }
} }

84
deno.lock generated
View file

@ -3,31 +3,31 @@
"specifiers": { "specifiers": {
"jsr:@andyburke/fsdb@^1.2.4": "1.2.4", "jsr:@andyburke/fsdb@^1.2.4": "1.2.4",
"jsr:@andyburke/lurid@0.2": "0.2.0", "jsr:@andyburke/lurid@0.2": "0.2.0",
"jsr:@andyburke/serverus@0.16": "0.16.0", "jsr:@andyburke/serverus@0.13": "0.13.0",
"jsr:@da/bcrypt@*": "1.0.1", "jsr:@da/bcrypt@*": "1.0.1",
"jsr:@da/bcrypt@^1.0.1": "1.0.1", "jsr:@da/bcrypt@^1.0.1": "1.0.1",
"jsr:@std/assert@^1.0.17": "1.0.17", "jsr:@std/assert@^1.0.15": "1.0.15",
"jsr:@std/cli@^1.0.19": "1.0.25", "jsr:@std/cli@^1.0.19": "1.0.23",
"jsr:@std/cli@^1.0.20": "1.0.25", "jsr:@std/cli@^1.0.20": "1.0.23",
"jsr:@std/cli@^1.0.21": "1.0.25", "jsr:@std/cli@^1.0.21": "1.0.23",
"jsr:@std/cli@^1.0.25": "1.0.25", "jsr:@std/cli@^1.0.23": "1.0.23",
"jsr:@std/encoding@^1.0.10": "1.0.10", "jsr:@std/encoding@^1.0.10": "1.0.10",
"jsr:@std/fmt@^1.0.6": "1.0.8", "jsr:@std/fmt@^1.0.6": "1.0.8",
"jsr:@std/fmt@^1.0.8": "1.0.8", "jsr:@std/fmt@^1.0.8": "1.0.8",
"jsr:@std/fs@^1.0.18": "1.0.22", "jsr:@std/fs@^1.0.18": "1.0.19",
"jsr:@std/fs@^1.0.19": "1.0.22", "jsr:@std/fs@^1.0.19": "1.0.19",
"jsr:@std/fs@^1.0.21": "1.0.22",
"jsr:@std/fs@^1.0.22": "1.0.22",
"jsr:@std/html@^1.0.5": "1.0.5", "jsr:@std/html@^1.0.5": "1.0.5",
"jsr:@std/http@^1.0.20": "1.0.23", "jsr:@std/http@^1.0.20": "1.0.21",
"jsr:@std/http@^1.0.23": "1.0.23", "jsr:@std/http@^1.0.21": "1.0.21",
"jsr:@std/internal@^1.0.10": "1.0.12",
"jsr:@std/internal@^1.0.12": "1.0.12", "jsr:@std/internal@^1.0.12": "1.0.12",
"jsr:@std/internal@^1.0.9": "1.0.12",
"jsr:@std/media-types@^1.1.0": "1.1.0", "jsr:@std/media-types@^1.1.0": "1.1.0",
"jsr:@std/net@^1.0.6": "1.0.6", "jsr:@std/net@^1.0.6": "1.0.6",
"jsr:@std/path@^1.1.0": "1.1.4", "jsr:@std/path@^1.1.0": "1.1.2",
"jsr:@std/path@^1.1.1": "1.1.4", "jsr:@std/path@^1.1.1": "1.1.2",
"jsr:@std/path@^1.1.4": "1.1.4", "jsr:@std/path@^1.1.2": "1.1.2",
"jsr:@std/streams@^1.0.16": "1.0.16", "jsr:@std/streams@^1.0.13": "1.0.13",
"npm:@types/node@*": "22.15.15" "npm:@types/node@*": "22.15.15"
}, },
"jsr": { "jsr": {
@ -45,8 +45,8 @@
"jsr:@std/cli@^1.0.19" "jsr:@std/cli@^1.0.19"
] ]
}, },
"@andyburke/serverus@0.16.0": { "@andyburke/serverus@0.13.0": {
"integrity": "625fc3f08ddc377beb86b282d603ca6154cf38e136d916ec19a87ae4c4ed86d5", "integrity": "73f451e1b68cd9be3938333b06290bfeab275361453559f40dfeab19dc4ad6d7",
"dependencies": [ "dependencies": [
"jsr:@std/cli@^1.0.21", "jsr:@std/cli@^1.0.21",
"jsr:@std/fmt@^1.0.6", "jsr:@std/fmt@^1.0.6",
@ -59,14 +59,14 @@
"@da/bcrypt@1.0.1": { "@da/bcrypt@1.0.1": {
"integrity": "d2172d3acbcff52e0465557a1a48b1ff1c92df08c90712dae5372255a8c45eb3" "integrity": "d2172d3acbcff52e0465557a1a48b1ff1c92df08c90712dae5372255a8c45eb3"
}, },
"@std/assert@1.0.17": { "@std/assert@1.0.15": {
"integrity": "df5ebfffe77c03b3fa1401e11c762cc8f603d51021c56c4d15a8c7ab45e90dbe", "integrity": "d64018e951dbdfab9777335ecdb000c0b4e3df036984083be219ce5941e4703b",
"dependencies": [ "dependencies": [
"jsr:@std/internal" "jsr:@std/internal@^1.0.12"
] ]
}, },
"@std/cli@1.0.25": { "@std/cli@1.0.23": {
"integrity": "1f85051b370c97a7a9dfc6ba626e7ed57a91bea8c081597276d1e78d929d8c91" "integrity": "bf95b7a9425ba2af1ae5a6359daf58c508f2decf711a76ed2993cd352498ccca"
}, },
"@std/encoding@1.0.10": { "@std/encoding@1.0.10": {
"integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1"
@ -74,27 +74,27 @@
"@std/fmt@1.0.8": { "@std/fmt@1.0.8": {
"integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7" "integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7"
}, },
"@std/fs@1.0.22": { "@std/fs@1.0.19": {
"integrity": "de0f277a58a867147a8a01bc1b181d0dfa80bfddba8c9cf2bacd6747bcec9308", "integrity": "051968c2b1eae4d2ea9f79a08a3845740ef6af10356aff43d3e2ef11ed09fb06",
"dependencies": [ "dependencies": [
"jsr:@std/internal", "jsr:@std/internal@^1.0.9",
"jsr:@std/path@^1.1.4" "jsr:@std/path@^1.1.1"
] ]
}, },
"@std/html@1.0.5": { "@std/html@1.0.5": {
"integrity": "4e2d693f474cae8c16a920fa5e15a3b72267b94b84667f11a50c6dd1cb18d35e" "integrity": "4e2d693f474cae8c16a920fa5e15a3b72267b94b84667f11a50c6dd1cb18d35e"
}, },
"@std/http@1.0.23": { "@std/http@1.0.21": {
"integrity": "6634e9e034c589bf35101c1b5ee5bbf052a5987abca20f903e58bdba85c80dee", "integrity": "abb5c747651ee6e3ea6139858fd9b1810d2c97f53a5e6722f3b6d27a6d263edc",
"dependencies": [ "dependencies": [
"jsr:@std/cli@^1.0.25", "jsr:@std/cli@^1.0.23",
"jsr:@std/encoding", "jsr:@std/encoding",
"jsr:@std/fmt@^1.0.8", "jsr:@std/fmt@^1.0.8",
"jsr:@std/fs@^1.0.21", "jsr:@std/fs@^1.0.19",
"jsr:@std/html", "jsr:@std/html",
"jsr:@std/media-types", "jsr:@std/media-types",
"jsr:@std/net", "jsr:@std/net",
"jsr:@std/path@^1.1.4", "jsr:@std/path@^1.1.2",
"jsr:@std/streams" "jsr:@std/streams"
] ]
}, },
@ -107,14 +107,14 @@
"@std/net@1.0.6": { "@std/net@1.0.6": {
"integrity": "110735f93e95bb9feb95790a8b1d1bf69ec0dc74f3f97a00a76ea5efea25500c" "integrity": "110735f93e95bb9feb95790a8b1d1bf69ec0dc74f3f97a00a76ea5efea25500c"
}, },
"@std/path@1.1.4": { "@std/path@1.1.2": {
"integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5", "integrity": "c0b13b97dfe06546d5e16bf3966b1cadf92e1cc83e56ba5476ad8b498d9e3038",
"dependencies": [ "dependencies": [
"jsr:@std/internal" "jsr:@std/internal@^1.0.10"
] ]
}, },
"@std/streams@1.0.16": { "@std/streams@1.0.13": {
"integrity": "85030627befb1767c60d4f65cb30fa2f94af1d6ee6e5b2515b76157a542e89c4" "integrity": "772d208cd0d3e5dac7c1d9e6cdb25842846d136eea4a41a62e44ed4ab0c8dd9e"
} }
}, },
"npm": { "npm": {
@ -135,14 +135,14 @@
"dependencies": [ "dependencies": [
"jsr:@andyburke/fsdb@^1.2.4", "jsr:@andyburke/fsdb@^1.2.4",
"jsr:@andyburke/lurid@0.2", "jsr:@andyburke/lurid@0.2",
"jsr:@andyburke/serverus@0.16", "jsr:@andyburke/serverus@0.13",
"jsr:@da/bcrypt@^1.0.1", "jsr:@da/bcrypt@^1.0.1",
"jsr:@std/assert@^1.0.17", "jsr:@std/assert@^1.0.15",
"jsr:@std/encoding@^1.0.10", "jsr:@std/encoding@^1.0.10",
"jsr:@std/fs@^1.0.22", "jsr:@std/fs@^1.0.19",
"jsr:@std/http@^1.0.23", "jsr:@std/http@^1.0.21",
"jsr:@std/media-types@^1.1.0", "jsr:@std/media-types@^1.1.0",
"jsr:@std/path@^1.1.4" "jsr:@std/path@^1.1.2"
] ]
} }
} }

View file

View file

@ -6,11 +6,10 @@ import { SESSION, SESSIONS } from '../../../models/session.ts';
import { TOTP_ENTRIES } from '../../../models/totp_entry.ts'; import { TOTP_ENTRIES } from '../../../models/totp_entry.ts';
import { encodeBase64 } from '@std/encoding/base64'; import { encodeBase64 } from '@std/encoding/base64';
import parse_body from '../../../utils/bodyparser.ts'; import parse_body from '../../../utils/bodyparser.ts';
import { AUTHED_BEFORE_COOKIE_ID, get_session, get_user, PRECHECK_TABLE, require_user, SESSION_ID_TOKEN, SESSION_SECRET_TOKEN } from '../../../utils/prechecks.ts'; import { get_session, get_user, PRECHECK_TABLE, require_user, SESSION_ID_TOKEN, SESSION_SECRET_TOKEN } from '../../../utils/prechecks.ts';
import * as bcrypt from '@da/bcrypt'; import * as bcrypt from '@da/bcrypt';
import { verifyTotp } from '../../../utils/totp.ts'; import { verifyTotp } from '../../../utils/totp.ts';
const AUTHED_BEFORE_EXPIRATION: number = 399 * (24 * (60 * (60 * 1_000))); // 399 days
const DEFAULT_SESSION_TIME: number = 365 * (24 * (60 * (60 * 1_000))); // 365 days const DEFAULT_SESSION_TIME: number = 365 * (24 * (60 * (60 * 1_000))); // 365 days
export const PRECHECKS: PRECHECK_TABLE = {}; export const PRECHECKS: PRECHECK_TABLE = {};
@ -207,7 +206,6 @@ export async function create_new_session(session_settings: SESSION_INFO): Promis
const headers = new Headers(); const headers = new Headers();
const expires_in_utc = new Date(session.timestamps.expires).toUTCString(); const expires_in_utc = new Date(session.timestamps.expires).toUTCString();
headers.append('Set-Cookie', `${AUTHED_BEFORE_COOKIE_ID}=1; Path=/; Secure; Expires=${new Date(new Date(now).valueOf() + AUTHED_BEFORE_EXPIRATION).toUTCString()}`);
headers.append('Set-Cookie', `${SESSION_ID_TOKEN}=${session.id}; Path=/; Secure; Expires=${expires_in_utc}`); headers.append('Set-Cookie', `${SESSION_ID_TOKEN}=${session.id}; Path=/; Secure; Expires=${expires_in_utc}`);
headers.append(`x-${SESSION_ID_TOKEN}`, session.id); headers.append(`x-${SESSION_ID_TOKEN}`, session.id);

View file

@ -169,15 +169,6 @@ body {
/* fixed height? */ /* fixed height? */
} }
#background-container {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: -1;
}
main { main {
position: relative; position: relative;
width: 100%; width: 100%;
@ -1691,32 +1682,6 @@ body[data-perms*="files.write.own"] [data-requires-permission="files.write.own"]
left: 11px; left: 11px;
} }
.icon.map-pin {
box-sizing: border-box;
position: relative;
display: block;
transform: rotate(45deg) scale(var(--icon-scale, 1));
width: 18px;
height: 18px;
border-radius: 100% 100% 0 100%;
border: 2px solid;
margin-top: -4px;
}
.icon.map-pin::before {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
width: 8px;
height: 8px;
border: 2px solid;
top: 3px;
left: 3px;
border-radius: 40px;
}
/* AUDIO PLAYER ICONS */ /* AUDIO PLAYER ICONS */
.icon.skip-back { .icon.skip-back {
box-sizing: border-box; box-sizing: border-box;

View file

@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<h1>Hello World - foo</h1>
</body>
</html>

View file

@ -3,57 +3,54 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><!-- #include "./files/settings/title.txt" or "./title.txt" --></title> <title>autonomous.contact</title>
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" ></link> <link rel="apple-touch-icon" sizes="180x180" href="./icons/apple-touch-icon.png" ></link>
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png" ></link> <link rel="icon" type="image/png" sizes="32x32" href="./icons/favicon-32x32.png" ></link>
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png" ></link> <link rel="icon" type="image/png" sizes="16x16" href="./icons/favicon-16x16.png" ></link>
<link rel="stylesheet" href="/base.css"></link> <link rel="stylesheet" href="./base.css"></link>
<link rel="stylesheet" href="/files/custom.css"></link>
<!-- inlining these to force them to be scoped for everything else --> <!-- inlining these to force them to be scoped for everything else -->
<script type="text/javascript"><!-- #include "./js/_utils.js" --></script> <script type="text/javascript"><!-- #include file="./js/_utils.js" --></script>
<script type="text/javascript"><!-- #include "./js/api.js" --></script> <script type="text/javascript"><!-- #include file="./js/api.js" --></script>
<script type="text/javascript"><!-- #include "./js/app.js" --></script> <script type="text/javascript"><!-- #include file="./js/app.js" --></script>
<!-- everything else --> <!-- everything else -->
<script src="/js/audioplayer.js" type="text/javascript"></script> <script src="./js/audioplayer.js" type="text/javascript"></script>
<script src="/js/datetimeutils.js" type="text/javascript"></script> <script src="./js/datetimeutils.js" type="text/javascript"></script>
<script src="/js/debounce.js" type="text/javascript"></script> <script src="./js/debounce.js" type="text/javascript"></script>
<script src="/js/external/md_to_html.js" type="text/javascript"></script> <script src="./js/external/md_to_html.js" type="text/javascript"></script>
<script src="/js/embeds/audio.js" type="text/javascript"></script> <script src="./js/embeds/audio.js" type="text/javascript"></script>
<script src="/js/embeds/gif.js" type="text/javascript"></script> <script src="./js/embeds/gif.js" type="text/javascript"></script>
<script src="/js/embeds/image.js" type="text/javascript"></script> <script src="./js/embeds/image.js" type="text/javascript"></script>
<script src="/js/embeds/link.js" type="text/javascript"></script> <script src="./js/embeds/link.js" type="text/javascript"></script>
<script src="/js/embeds/mkv.js" type="text/javascript"></script> <script src="./js/embeds/mkv.js" type="text/javascript"></script>
<script src="/js/embeds/mov.js" type="text/javascript"></script> <script src="./js/embeds/mov.js" type="text/javascript"></script>
<script src="/js/embeds/mp4.js" type="text/javascript"></script> <script src="./js/embeds/mp4.js" type="text/javascript"></script>
<script src="/js/embeds/spotify.js" type="text/javascript"></script> <script src="./js/embeds/spotify.js" type="text/javascript"></script>
<script src="/js/embeds/tidal.js" type="text/javascript"></script> <script src="./js/embeds/tidal.js" type="text/javascript"></script>
<script src="/js/embeds/vimeo.js" type="text/javascript"></script> <script src="./js/embeds/vimeo.js" type="text/javascript"></script>
<script src="/js/embeds/youtube.js" type="text/javascript"></script> <script src="./js/embeds/youtube.js" type="text/javascript"></script>
<script src="/js/emojis/en.js" type="text/javascript"></script> <script src="./js/emojis/en.js" type="text/javascript"></script>
<script src="/js/eventactions.js" type="text/javascript"></script> <script src="./js/eventactions.js" type="text/javascript"></script>
<script src="/js/htmlify.js" type="text/javascript"></script> <script src="./js/htmlify.js" type="text/javascript"></script>
<script src="/js/locationchange.js" type="text/javascript"></script> <script src="./js/locationchange.js" type="text/javascript"></script>
<script src="/js/notifications.js" type="text/javascript"></script> <script src="./js/notifications.js" type="text/javascript"></script>
<script src="/js/reactions.js" type="text/javascript"></script> <script src="./js/reactions.js" type="text/javascript"></script>
<script src="/js/smartfeeds.js" type="text/javascript"></script> <script src="./js/smartfeeds.js" type="text/javascript"></script>
<script src="/js/smartforms.js" type="text/javascript"></script> <script src="./js/smartforms.js" type="text/javascript"></script>
<script src="/js/textareaenhancements.js" type="text/javascript"></script> <script src="./js/textareaenhancements.js" type="text/javascript"></script>
<script src="/js/totp.js" type="text/javascript"></script> <script src="./js/totp.js" type="text/javascript"></script>
</head> </head>
<body> <body>
<div id="background-container"></div> <!-- #include file="./signup_login_wall.html" -->
<!-- #include "./signup_login_wall.html" -->
<main> <main>
<!-- #include "./sidebar/sidebar.html" --> <!-- #include file="./sidebar/sidebar.html" -->
<!-- #include "./tabs/tabs.html" --> <!-- #include file="./tabs/tabs.html" -->
</main> </main>
</body> </body>
</html> </html>

View file

@ -5,13 +5,10 @@ const api = {
...__options, ...__options,
}; };
// FIXME: this will break with different server settings
// TODO: we need the cookie names here to match any configured on the server
const session_id = (document.cookie.match( const session_id = (document.cookie.match(
/^(?:.*;)?\s*session_id\s*=\s*([^;]+)(?:.*)?$/, /^(?:.*;)?\s*session_id\s*=\s*([^;]+)(?:.*)?$/,
) || [, null])[1]; ) || [, null])[1];
// FIXME: this will break with different server settings
// TODO: this wasn't really intended to be persisted in a cookie // TODO: this wasn't really intended to be persisted in a cookie
const session_secret = (document.cookie.match( const session_secret = (document.cookie.match(
/^(?:.*;)?\s*session_secret\s*=\s*([^;]+)(?:.*)?$/, /^(?:.*;)?\s*session_secret\s*=\s*([^;]+)(?:.*)?$/,

View file

@ -68,13 +68,13 @@ const APP = {
this._emit( 'view_changed', { this._emit( 'view_changed', {
previous, previous,
view, view
channel_id
}); });
} }
if (!document.body.dataset.channel || document.body.dataset.channel !== channel_id) { if (!document.body.dataset.channel || document.body.dataset.channel !== channel_id) {
const previous = typeof document.body.dataset.channel === 'string' ? document.body.dataset.channel : undefined; const previous = typeof document.body.dataset.channel === 'string' ? document.body.dataset.channel : undefined;
if ( channel_id ) { if ( channel_id ) {
document.body.dataset.channel = channel_id; document.body.dataset.channel = channel_id;
} }
@ -82,10 +82,21 @@ const APP = {
delete document.body.dataset.channel; delete document.body.dataset.channel;
} }
this._emit( 'channel_changed', { const target_channel_id = channel_id ?? this.CHANNELS.CHANNEL_LIST[0]?.id;
previous,
channel_id // TODO: allow a different default than chat
}); const hash_target = `/${ view ? view : 'chat' }` + ( target_channel_id ? `/channel/${ target_channel_id }` : '' );
if ( window.location.hash?.slice( 1 ) !== hash_target ) {
if ( previous !== target_channel_id ) {
this._emit( 'channel_changed', {
previous,
channel_id: target_channel_id
});
}
window.location.hash = hash_target;
}
} }
}, },
@ -225,11 +236,22 @@ const APP = {
const channels_response = await api.fetch("/api/channels"); const channels_response = await api.fetch("/api/channels");
if (channels_response.ok) { if (channels_response.ok) {
const new_channels = await channels_response.json(); const new_channels = await channels_response.json();
APP.CHANNELS.CHANNEL_LIST = [...new_channels]; const has_differences =
APP.CHANNELS.CHANNEL_LIST.length !== new_channels.length ||
new_channels.some((channel, index) => {
return (
APP.CHANNELS.CHANNEL_LIST[index]?.id !== channel.id ||
APP.CHANNELS.CHANNEL_LIST[index]?.name !== channel.name
);
});
APP._emit( 'channels_updated', { if (has_differences) {
channels: APP.CHANNELS.CHANNEL_LIST APP.CHANNELS.CHANNEL_LIST = [...new_channels];
});
APP._emit( 'channels_updated', {
channels: APP.CHANNELS.CHANNEL_LIST
});
}
APP.CHANNELS._last_channel_update = now; APP.CHANNELS._last_channel_update = now;
} }
@ -249,8 +271,3 @@ const APP = {
}; };
document.addEventListener("DOMContentLoaded", APP.load.bind( APP )); document.addEventListener("DOMContentLoaded", APP.load.bind( APP ));
APP.on( 'view_changed', ( { view } ) => {
if ( !view ) {
window.location.hash = '/chat';
}
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,661 +0,0 @@
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
width: auto;
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.8);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
line-height: 1.4;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
vertical-align: baseline !important;
width: 1em;
height: 0.6669em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
white-space: nowrap;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 24px 13px 20px;
line-height: 1.3;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 17px 0;
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-top: -1px;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
pointer-events: auto;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
border: none;
text-align: center;
width: 24px;
height: 24px;
font: 16px/24px Tahoma, Verdana, sans-serif;
color: #757575;
text-decoration: none;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
-ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -87,11 +87,6 @@
border-right: 1px solid var(--border-subtle); border-right: 1px solid var(--border-subtle);
} }
#sidebar .profile-container {
width: 100%;
max-width: 100%;
}
#sidebar #sidebar-context-menu { #sidebar #sidebar-context-menu {
display: none; display: none;
visibility: hidden; visibility: hidden;

View file

@ -14,24 +14,11 @@
background: var(--bg); background: var(--bg);
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
transition: all 0.33s ease; transition: all 0.33s;
animation: slideIn 0.4s ease;
}
@keyframes slideIn {
from {
opacity: 0;
transform: scale(1.2);
}
to {
opacity: 1;
transform: scale(1.0);
}
} }
#login-tab .tab-content { #login-tab .tab-content {
min-height: 17rem; min-height: 17rem;
overflow: hidden;
} }
#signup-tab .tab-content { #signup-tab .tab-content {
@ -61,17 +48,52 @@
} }
</style> </style>
<!-- #include "./files/settings/signup_pitch.html" or "./files/settings/signup_pitch.md" or "./signup_pitch.default.md" --> <!-- #include file="./signup_pitch.md" -->
<div class="limiter"> <div class="limiter">
<div class="tabs"> <div class="tabs">
<div id="login-tab" class="tab">
<input
type="radio"
name="signup-login-tabs"
id="login-tab-input"
class="tab-switch"
checked="checked"
/>
<label for="login-tab-input" class="tab-label">
<div class="label">Log In</div>
</label>
<div class="tab-content">
<form data-smart="true" data-method="POST" id="login-form" action="/api/auth">
<script>
{
const form = document.currentScript.closest("form");
form.on_reply = (response) => {
const user = response.user;
APP.login( user );
};
}
</script>
<div>
<input id="login-username" type="text" name="username" required />
<label class="placeholder" for="login-username">username</label>
</div>
<div>
<input id="login-password" type="password" name="password" required />
<label class="placeholder" for="login-password">password</label>
</div>
<div>
<button id="login-submit" type="submit" class="primary">Log In</button>
</div>
</form>
</div>
</div>
<div id="signup-tab" class="tab"> <div id="signup-tab" class="tab">
<input <input
type="radio" type="radio"
name="signup-login-tabs" name="signup-login-tabs"
id="signup-tab-input" id="signup-tab-input"
class="tab-switch" class="tab-switch"
checked="checked"
/> />
<label for="signup-tab-input" class="tab-label"> <label for="signup-tab-input" class="tab-label">
<div class="label">Sign Up</div> <div class="label">Sign Up</div>
@ -113,7 +135,6 @@
id="signup-invite-code" id="signup-invite-code"
type="text" type="text"
name="invite_code" name="invite_code"
required
/> />
<label class="placeholder" for="signup-invite-code">invite code</label> <label class="placeholder" for="signup-invite-code">invite code</label>
</div> </div>
@ -121,53 +142,6 @@
</form> </form>
</div> </div>
</div> </div>
<div id="login-tab" class="tab">
<input
type="radio"
name="signup-login-tabs"
id="login-tab-input"
class="tab-switch"
/>
<label for="login-tab-input" class="tab-label">
<div class="label">Log In</div>
</label>
<div class="tab-content">
<form data-smart="true" data-method="POST" id="login-form" action="/api/auth">
<script>
{
const form = document.currentScript.closest("form");
form.on_reply = (response) => {
const user = response.user;
APP.login( user );
};
}
</script>
<div>
<input id="login-username" type="text" name="username" required />
<label class="placeholder" for="login-username">username</label>
</div>
<div>
<input id="login-password" type="password" name="password" required />
<label class="placeholder" for="login-password">password</label>
</div>
<div>
<button id="login-submit" type="submit" class="primary">Log In</button>
</div>
</form>
</div>
</div>
</div> </div>
</div> </div>
<script>
document.addEventListener( 'DOMContentLoaded', () => {
const authed_before = (document.cookie.match(
/^(?:.*;)?\s*authed_before\s*=\s*([^;]+)(?:.*)?$/,
) || [, null])[1];
if ( authed_before ) {
document.getElementById("login-tab-input").checked = true;
}
});
</script>
</div> </div>

View file

@ -1,6 +1,6 @@
# Welcome! # verifiedhuman.network
## You're here because someone else thought you needed an invite. ## You're here because someone else said you were a cool human.
### Use your invite code to gain access. ### Use your invite code to gain access.

View file

@ -141,9 +141,9 @@
</label> </label>
<div class="tab-content"> <div class="tab-content">
<div id="blurbs-container" class="container"> <div id="blurbs-container" class="container">
<!-- #include "./README.md" --> <!-- #include file="./README.md" -->
<!-- #include "./new_blurb.html" --> <!-- #include file="./new_blurb.html" -->
<div <div
id="blurbs-list" id="blurbs-list"
@ -227,7 +227,7 @@
<div class="content-container">${htmlify(md_to_html(context.blurb.data.blurb))}</div> <div class="content-container">${htmlify(md_to_html(context.blurb.data.blurb))}</div>
<div class="reactions-container"></div> <div class="reactions-container"></div>
<button class="icon more" commandfor="eventactionspopover"></button> <button class="icon more" commandfor="eventactionspopover"></button>
<!-- #include "./new_blurb.html" --> <!-- #include file="./new_blurb.html" -->
<div class="replies-container"></div> <div class="replies-container"></div>
</div> </div>
</template> </template>

View file

@ -11,6 +11,6 @@
<div class="label">Calendar</div></label <div class="label">Calendar</div></label
> >
<div class="tab-content"> <div class="tab-content">
<!-- #include "./README.md" --> <!-- #include file="./README.md" -->
</div> </div>
</div> </div>

View file

@ -1,53 +1,13 @@
<script> <script>
function on_channels_updated({ channels }) { APP.on("channels_updated", ({ channels }) => {
const channel_list = document.getElementById("channel-list"); const channel_list = document.getElementById("channel-list");
if ( !channel_list ) {
setTimeout( () => {
on_channels_updated( { channels } );
}, 100 );
return;
}
channel_list.innerHTML = ""; channel_list.innerHTML = "";
for (const channel of channels.sort((lhs, rhs) => lhs.name.localeCompare(rhs.name))) { for (const channel of channels.sort((lhs, rhs) => lhs.name.localeCompare(rhs.name))) {
if ( !document.body.dataset.channel ) {
document.body.dataset.channel = APP.user?.meta?.chat?.last_channel ?? channel.id;
if ( APP.view === 'chat' ) {
window.location.hash = '/chat/channel/' + document.body.dataset.channel;
}
}
channel_list.insertAdjacentHTML( channel_list.insertAdjacentHTML(
"beforeend", "beforeend",
`<li id="channel-selector-${channel.id}" class="channel" data-channel-selector-for="${channel.id}"><a href="#/chat/channel/${channel.id}">${channel.name}</a></li>`, `<li id="channel-selector-${channel.id}" class="channel" data-channel-selector-for="${channel.id}"><a href="#/channel/${channel.id}/chat">${channel.name}</a></li>`,
); );
} }
}
APP.on("channels_updated", on_channels_updated );
APP.on( 'view_changed', async ( { previous, view, channel_id } ) => {
if ( view !== 'chat' ) {
return;
}
const previous_channel = typeof document.body.dataset.channel === 'string' ? document.body.dataset.channel : undefined;
if ( channel_id ) {
document.body.dataset.channel = channel_id;
}
else {
delete document.body.dataset.channel;
}
await APP.CHANNELS.update(); // don't force, but ensure we have channels
const target_channel_id = channel_id ?? APP.CHANNELS.CHANNEL_LIST[0]?.id;
const hash_target = `/chat` + ( target_channel_id ? `/channel/${ target_channel_id }` : '' );
if ( window.location.hash?.slice( 1 ) !== hash_target ) {
window.location.hash = hash_target;
}
}); });
function update_channel_indicators(event) { function update_channel_indicators(event) {
@ -117,25 +77,20 @@
} }
}); });
APP.on( 'view_changed', ( {previous, view} ) => { APP.on( 'view_changed', ( {view} ) => {
if ( !view === 'chat' ) {
return;
}
const sidebar_dynamic_container = document.getElementById( 'sidebar-dynamic-container'); const sidebar_dynamic_container = document.getElementById( 'sidebar-dynamic-container');
if ( !sidebar_dynamic_container ) { if ( !sidebar_dynamic_container ) {
console.error( 'could not get #sidebar-dynamic-container' ); console.error( 'could not get #sidebar-dynamic-container' );
return; return;
} }
if ( view !== 'chat' && previous === 'chat' ) {
sidebar_dynamic_container.innerHTML = '';
delete document.body.dataset.channel;
return;
}
else if ( view !== 'chat' ) {
return;
}
const template = document.getElementById( 'channel-list-template'); const template = document.getElementById( 'channel-list-template');
sidebar_dynamic_container.innerHTML = template.innerHTML.trim(); sidebar_dynamic_container.innerHTML = template.innerHTML.trim();
APP.CHANNELS.update(true); APP.CHANNELS.update();
}); });
</script> </script>
<style> <style>

View file

@ -12,7 +12,7 @@
</label> </label>
<div class="tab-content"> <div class="tab-content">
<style> <style>
<!-- #include "./chat.css" --> <!-- #include file="./chat.css" -->
</style> </style>
<script src="/js/external/mimetypes.js" type="text/javascript"></script> <script src="/js/external/mimetypes.js" type="text/javascript"></script>
<script src="/js/external/punycode.js" type="text/javascript"></script> <script src="/js/external/punycode.js" type="text/javascript"></script>
@ -232,4 +232,4 @@
</div> </div>
</div> </div>
</div> </div>
<!-- #include "./channel_sidebar.html" --> <!-- #include file="./channel_sidebar.html" -->

View file

@ -109,8 +109,8 @@
</label> </label>
<div class="tab-content"> <div class="tab-content">
<div id="essays-container" class="container"> <div id="essays-container" class="container">
<!-- #include "./README.md" --> <!-- #include file="./README.md" -->
<!-- #include "./new_essay.html" --> <!-- #include file="./new_essay.html" -->
<div <div
id="essays-list" id="essays-list"

View file

@ -11,6 +11,6 @@
<div class="label">Exchange</div></label <div class="label">Exchange</div></label
> >
<div class="tab-content"> <div class="tab-content">
<!-- #include "./README.md" --> <!-- #include file="./README.md" -->
</div> </div>
</div> </div>

View file

@ -140,7 +140,7 @@
<div class="label">Forum</div></label <div class="label">Forum</div></label
> >
<div class="tab-content forum-container"> <div class="tab-content forum-container">
<!-- #include "./README.md" --> <!-- #include file="./README.md" -->
<div <div
id="posts-list" id="posts-list"
@ -234,7 +234,7 @@
</div> </div>
<div class="reactions-container"></div> <div class="reactions-container"></div>
<button class="icon more" commandfor="eventactionspopover"></button> <button class="icon more" commandfor="eventactionspopover"></button>
<!-- #include "./new_post.html" --> <!-- #include file="./new_post.html" -->
<div class="replies-container"></div> <div class="replies-container"></div>
</div> </div>
</template> </template>
@ -251,6 +251,6 @@
</template> </template>
</div> </div>
<!-- #include "./new_post.html" --> <!-- #include file="./new_post.html" -->
</div> </div>
</div> </div>

View file

@ -12,6 +12,6 @@
<div class="label">Home</div> <div class="label">Home</div>
</label> </label>
<div class="tab-content"> <div class="tab-content">
<!-- #include "./README.md" --> <!-- #include file="./README.md" -->
</div> </div>
</div> </div>

View file

@ -1,55 +0,0 @@
<link rel="stylesheet" href="/js/external/leaflet/leaflet.css"/>
<script src="/js/external/leaflet/leaflet.js"></script>
<script type="module">
var map = L.map('map').setView([33.88,-118.13], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
APP.on( "view_changed", ({ view }) => {
if ( view === 'map' ) {
map.invalidateSize();
}
});
</script>
<style>
#map-tab .tab-content {
overflow: hidden;
}
#map {
position: absolute;
top: 4em;
left: 4em;
right: 4em;
bottom: 4em;
}
@media screen and (max-width: 640px) {
#map {
top: 1em;
left: 1em;
right: 1em;
bottom: 1em;
}
}
</style>
<div id="map-tab" class="tab">
<input
type="radio"
name="top-level-tabs"
id="map-tab-tab-input"
class="tab-switch"
data-view="map"
/>
<label for="map-tab-tab-input" class="tab-label"
><div class="icon map-pin"></div>
<div class="label">Map</div>
</label>
<div class="tab-content">
<div id="map"></div>
</div>
</div>

View file

@ -10,5 +10,5 @@
><div class="icon resources"></div> ><div class="icon resources"></div>
<div class="label">Resources</div></label <div class="label">Resources</div></label
> >
<div class="tab-content"><!-- #include "./README.md" --></div> <div class="tab-content"><!-- #include file="./README.md" --></div>
</div> </div>

View file

@ -13,7 +13,6 @@
tab_switch.addEventListener("input", (event) => { tab_switch.addEventListener("input", (event) => {
const tab_selector = event.target; const tab_selector = event.target;
const view = tab_selector.dataset.view; const view = tab_selector.dataset.view;
if (view) { if (view) {
window.location.hash = `/${view}${ document.body.dataset.channel ? `/channel/${ document.body.dataset.channel }` : '' }`; window.location.hash = `/${view}${ document.body.dataset.channel ? `/channel/${ document.body.dataset.channel }` : '' }`;
} }
@ -111,21 +110,28 @@
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
.tab-label { .tab-label {
width: 4rem; width: 3rem;
}
.tab-label .label {
font-size: small;
} }
} }
@media screen and (max-width: 400px) { @media screen and (max-width: 400px) {
.tab-label { .tab-label {
width: 3rem; width: 2.5rem;
}
.tab-label .label {
font-size: 8px;
} }
} }
</style> </style>
<div class="tabs"> <div class="tabs">
<!-- #include "./chat/chat.html" --> <!-- #include file="./chat/chat.html" -->
<!-- #include "./blurbs/blurbs.html" --> <!-- #include file="./blurbs/blurbs.html" -->
<!-- #include "./forum/forum.html" --> <!-- #include file="./forum/forum.html" -->
<!-- #include "./essays/essays.html" --> <!-- #include file="./essays/essays.html" -->
<!-- #include "./map/map.html" -->
</div> </div>

View file

@ -10,5 +10,5 @@
><div class="icon work"></div> ><div class="icon work"></div>
<div class="label">Work</div> <div class="label">Work</div>
</label> </label>
<div class="tab-content"><!-- #include "./README.md" --></div> <div class="tab-content"><!-- #include file="./README.md" --></div>
</div> </div>

View file

@ -8,7 +8,6 @@ import { EVENT } from '../models/event.ts';
export type PRECHECK = (req: Request, meta: Record<string, any>) => Promise<Response | undefined> | Response | undefined; export type PRECHECK = (req: Request, meta: Record<string, any>) => Promise<Response | undefined> | Response | undefined;
export type PRECHECK_TABLE = Record<string, PRECHECK[]>; export type PRECHECK_TABLE = Record<string, PRECHECK[]>;
export const AUTHED_BEFORE_COOKIE_ID: string = Deno.env.get('AUTHED_BEFORE_COOKIE_ID') ?? 'authed_before';
export const SESSION_ID_TOKEN: string = Deno.env.get('SESSION_ID_TOKEN') ?? 'session_id'; export const SESSION_ID_TOKEN: string = Deno.env.get('SESSION_ID_TOKEN') ?? 'session_id';
export const SESSION_SECRET_TOKEN: string = Deno.env.get('SESSION_SECRET_TOKEN') ?? 'session_secret'; export const SESSION_SECRET_TOKEN: string = Deno.env.get('SESSION_SECRET_TOKEN') ?? 'session_secret';
export const TOTP_TOKEN: string = Deno.env.get('TOTP_TOKEN') ?? 'totp'; export const TOTP_TOKEN: string = Deno.env.get('TOTP_TOKEN') ?? 'totp';