merge: branch 'main' into reports

This commit is contained in:
Sam 2023-03-23 10:50:36 +01:00
commit 244c13cd84
No known key found for this signature in database
GPG Key ID: B4EF20DDE721CAA1
30 changed files with 207 additions and 435 deletions

View File

@ -1,13 +1,5 @@
all: generate backend frontend all: generate backend frontend
.PHONY: migrate
migrate:
go run -v ./scripts/migrate
.PHONY: seeddb
seeddb:
go run -v ./scripts/seeddb
.PHONY: backend .PHONY: backend
backend: backend:
CGO_ENABLED=0 go build -v -o pronouns -ldflags="-buildid= -X codeberg.org/u1f320/pronouns.cc/backend/server.Revision=`git rev-parse --short HEAD` -X codeberg.org/u1f320/pronouns.cc/backend/server.Tag=`git describe --tags --long`" . CGO_ENABLED=0 go build -v -o pronouns -ldflags="-buildid= -X codeberg.org/u1f320/pronouns.cc/backend/server.Revision=`git rev-parse --short HEAD` -X codeberg.org/u1f320/pronouns.cc/backend/server.Tag=`git describe --tags --long`" .

View File

@ -17,21 +17,6 @@ When working on the frontend, run the API and then use `pnpm dev` in `frontend/`
Note that the Vite dev server assumes that the backend listens on `:8080` and MinIO listens on `:9000`. Note that the Vite dev server assumes that the backend listens on `:8080` and MinIO listens on `:9000`.
If these ports differ on your development environment, you must edit `vite.config.ts`. If these ports differ on your development environment, you must edit `vite.config.ts`.
## Building
Run `make backend` to build the API server, then run `pnpm build` in `frontend/`.
## Running
Both the backend and frontend are expected to run behind a reverse proxy such as [Caddy](https://caddyserver.com/) or nginx.
Every path should be proxied to the frontend, except:
- `/api/`: this should be proxied to the backend, with the URL being rewritten to remove `/api`
(for example, a request to `$DOMAIN/api/v1/users/@me` should be proxied to `localhost:8080/v1/users/@me`)
- `/media/`: this should be proxied to your object storage.
Make sure to rewrite `/media` into your storage bucket's name.
## Development ## Development
Requirements: Requirements:
@ -40,36 +25,17 @@ Requirements:
- PostgreSQL (any currently supported version should work) - PostgreSQL (any currently supported version should work)
- Redis 6.0 or later - Redis 6.0 or later
- Node.js (latest version) - Node.js (latest version)
- MinIO **if testing uploads** (_not_ required otherwise) - MinIO **if using avatars or data exports** (_not_ required otherwise)
### Setup ### Setup
1. Create a PostgreSQL user and database (the user should own the database) 1. Create a PostgreSQL user and database (the user should own the database)
For example: `create user pronouns with password 'password'; create database pronouns with owner pronouns;` For example: `create user pronouns with password 'password'; create database pronouns with owner pronouns;`
2. Create a `.env` file in the repository root containing at least `HMAC_KEY`, `DATABASE_URL`, `REDIS`, `PORT`, and `MINIO_ENDPOINT` keys. 2. Create a `.env` file in the repository root containing at least `HMAC_KEY`, `DATABASE_URL`, `REDIS`, `PORT`, and `MINIO_ENDPOINT` keys.
(See below for an example) 3. Run `go run -v . database migrate` to initialize the database, then optionally `go run -v . database seed` to insert a test user.
3. Create a `.env` file in the `frontend/` directory containing `DOMAIN=http://localhost:5173`. 4. Run `go run -v . web` to run the backend.
4. Run `make migrate` to initialize the database, then optionally `make seeddb` to insert a test user. 5. Create `frontend/.env` with the following content: `PUBLIC_BASE_URL=http://localhost:5173`
5. Run `go run -v ./backend` to run the backend. 6. cd into the `frontend` directory and run `pnpm dev` to run the frontend.
6. Create `frontend/.env` with the following content: `API_BASE=http://localhost:8080`
7. cd into the `frontend` directory and run `pnpm dev` to run the frontend.
```sh
# Example env file
HMAC_KEY="`go run -v ./scripts/genkey`"
DATABASE_URL=postgresql://<username>:<pass>@localhost/<database> # PostgreSQL database URL
REDIS=localhost:6379
PORT=8080 # Port the API will listen on. Default is 8080, this is also default for the backend.
MINIO_ENDPOINT=localhost:9000 # This always needs to be set, it *does not* need to point to a running MinIO server.
```
## Updating in production
1. Build the backend with `make backend`
2. Build the frontend with `cd frontend && pnpm install && pnpm build`
3. Stop the servers: `systemctl stop pronouns-api pronouns-fe`
4. Run migrations: `./pronouns database migrate`
5. Start the servers: `systemctl start pronouns-api pronouns-fe`
## License ## License

View File

@ -190,6 +190,14 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error {
return err return err
} }
avatarHash = &hash avatarHash = &hash
// delete current avatar if member has one
if m.Avatar != nil {
err = s.DB.DeleteMemberAvatar(ctx, claims.UserID, *m.Avatar)
if err != nil {
log.Errorf("deleting existing avatar: %v", err)
}
}
} }
} }

View File

@ -137,6 +137,14 @@ func (s *Server) patchUser(w http.ResponseWriter, r *http.Request) error {
return err return err
} }
avatarHash = &hash avatarHash = &hash
// delete current avatar if user has one
if u.Avatar != nil {
err = s.DB.DeleteUserAvatar(ctx, claims.UserID, *u.Avatar)
if err != nil {
log.Errorf("deleting existing avatar: %v", err)
}
}
} }
} }

68
docs/production.md Normal file
View File

@ -0,0 +1,68 @@
# Running pronouns.cc in production
The configuration files in this directory are the same files used to run pronouns.cc in production.
You might have to change paths and ports, but they should work fine as-is.
## Building pronouns.cc
```bash
git clone https://codeberg.org/u1f320/pronouns.cc.git pronouns
cd pronouns
make all
# if running for the first time
./pronouns database migrate
```
## Configuration
pronouns.cc is configured using `.env` files. Note that there are two separate `.env` files,
one in the repository root (for the backend) and one in the frontend directory.
### Backend keys
- `HMAC_KEY`: the key used to sign tokens. This should be a base64 string, you can generate one with `scripts/genkey`.
- `DATABASE_URL`: the URL for the PostgreSQL database.
- `REDIS`: the URL for the Redis database.
- `PORT` (int): the port the backend will listen on.
- `EXPORTER_PORT` (int): the port that the exporter service will listen on.
- `DEBUG` (true/false): whether to enable request logging.
- `BASE_URL`: the base URL for the frontend, used to construct some links.
- `MINIO_ENDPOINT`: the S3 endpoint for object storage.
- `MINIO_BUCKET`: the S3 bucket name.
- `MINIO_ACCESS_KEY_ID`: the S3 access key ID.
- `MINIO_ACCESS_KEY_SECRET`: the S3 access key secret.
- `MINIO_SSL`: whether to use SSL for S3.
- `FRONTEND_IP`: the IP for the frontend, which the rate limiter will ignore.
- `REQUIRE_INVITE`: whether to require invites to sign up.
- `DISCORD_CLIENT_ID`: for Discord auth, the client ID.
- `DISCORD_CLIENT_SECRET`: for Discord auth, the client secret.
- `DISCORD_PUBLIC_KEY`: public key for the Discord bot endpoint.
### Frontend keys
- `PUBLIC_BASE_URL`: the base URL for the frontend.
- `PRIVATE_SENTRY_DSN`: your Sentry DSN.
## Updating
```bash
make all
systemctl stop pronouns-api pronouns-fe
systemctl stop pronouns-exporter # only if the User, Member, Field, Export tables changed
./pronouns database migrate # only if a new migration was added
systemctl start pronouns-api pronouns-fe
systemctl start pronouns-exporter # if the exporter was stopped
```
## Proxy
Both the backend and frontend are expected to run behind a reverse proxy such as Caddy or nginx.
This directory contains a sample configuration file for nginx.
Every path should be proxied to the frontend, except:
- `/api/`: this should be proxied to the backend, with the URL being rewritten to remove `/api`
(for example, a request to `$DOMAIN/api/v1/users/@me` should be proxied to `localhost:8080/v1/users/@me`)
- `/media/`: this should be proxied to your object storage.
Make sure to rewrite `/media` into your storage bucket's name.

View File

@ -15,24 +15,20 @@
"@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/adapter-node": "^1.2.2", "@sveltejs/adapter-node": "^1.2.2",
"@sveltejs/kit": "^1.5.0", "@sveltejs/kit": "^1.5.0",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/typography": "^0.5.9",
"@types/luxon": "^3.2.0", "@types/luxon": "^3.2.0",
"@types/marked": "^4.0.8", "@types/markdown-it": "^12.2.3",
"@types/node": "^18.15.3", "@types/node": "^18.15.3",
"@types/sanitize-html": "^2.8.1", "@types/sanitize-html": "^2.8.1",
"@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0", "@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.13",
"eslint": "^8.28.0", "eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte3": "^4.0.0", "eslint-plugin-svelte3": "^4.0.0",
"postcss": "^8.4.21",
"prettier": "^2.8.0", "prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.8.1", "prettier-plugin-svelte": "^2.8.1",
"svelte": "^3.54.0", "svelte": "^3.54.0",
"svelte-check": "^3.0.1", "svelte-check": "^3.0.1",
"tailwindcss": "^3.2.7", "sveltestrap": "^5.10.0",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"typescript": "^4.9.3", "typescript": "^4.9.3",
"vite": "^4.0.0" "vite": "^4.0.0"
@ -46,8 +42,7 @@
"bootstrap-icons": "^1.10.3", "bootstrap-icons": "^1.10.3",
"jose": "^4.13.1", "jose": "^4.13.1",
"luxon": "^3.3.0", "luxon": "^3.3.0",
"marked": "^4.2.12", "markdown-it": "^13.0.1",
"sanitize-html": "^2.10.0", "sanitize-html": "^2.10.0"
"sveltestrap": "^5.10.0"
} }
} }

View File

@ -6,15 +6,12 @@ specifiers:
'@sveltejs/adapter-auto': ^2.0.0 '@sveltejs/adapter-auto': ^2.0.0
'@sveltejs/adapter-node': ^1.2.2 '@sveltejs/adapter-node': ^1.2.2
'@sveltejs/kit': ^1.5.0 '@sveltejs/kit': ^1.5.0
'@tailwindcss/forms': ^0.5.3
'@tailwindcss/typography': ^0.5.9
'@types/luxon': ^3.2.0 '@types/luxon': ^3.2.0
'@types/marked': ^4.0.8 '@types/markdown-it': ^12.2.3
'@types/node': ^18.15.3 '@types/node': ^18.15.3
'@types/sanitize-html': ^2.8.1 '@types/sanitize-html': ^2.8.1
'@typescript-eslint/eslint-plugin': ^5.45.0 '@typescript-eslint/eslint-plugin': ^5.45.0
'@typescript-eslint/parser': ^5.45.0 '@typescript-eslint/parser': ^5.45.0
autoprefixer: ^10.4.13
base64-arraybuffer: ^1.0.2 base64-arraybuffer: ^1.0.2
bootstrap: 5.3.0-alpha1 bootstrap: 5.3.0-alpha1
bootstrap-icons: ^1.10.3 bootstrap-icons: ^1.10.3
@ -23,15 +20,13 @@ specifiers:
eslint-plugin-svelte3: ^4.0.0 eslint-plugin-svelte3: ^4.0.0
jose: ^4.13.1 jose: ^4.13.1
luxon: ^3.3.0 luxon: ^3.3.0
marked: ^4.2.12 markdown-it: ^13.0.1
postcss: ^8.4.21
prettier: ^2.8.0 prettier: ^2.8.0
prettier-plugin-svelte: ^2.8.1 prettier-plugin-svelte: ^2.8.1
sanitize-html: ^2.10.0 sanitize-html: ^2.10.0
svelte: ^3.54.0 svelte: ^3.54.0
svelte-check: ^3.0.1 svelte-check: ^3.0.1
sveltestrap: ^5.10.0 sveltestrap: ^5.10.0
tailwindcss: ^3.2.7
tslib: ^2.4.1 tslib: ^2.4.1
typescript: ^4.9.3 typescript: ^4.9.3
vite: ^4.0.0 vite: ^4.0.0
@ -44,32 +39,27 @@ dependencies:
bootstrap-icons: 1.10.3 bootstrap-icons: 1.10.3
jose: 4.13.1 jose: 4.13.1
luxon: 3.3.0 luxon: 3.3.0
marked: 4.2.12 markdown-it: 13.0.1
sanitize-html: 2.10.0 sanitize-html: 2.10.0
sveltestrap: 5.10.0_svelte@3.55.1
devDependencies: devDependencies:
'@sveltejs/adapter-auto': 2.0.0_@sveltejs+kit@1.11.0 '@sveltejs/adapter-auto': 2.0.0_@sveltejs+kit@1.11.0
'@sveltejs/adapter-node': 1.2.2_@sveltejs+kit@1.11.0 '@sveltejs/adapter-node': 1.2.2_@sveltejs+kit@1.11.0
'@sveltejs/kit': 1.11.0_svelte@3.55.1+vite@4.1.4 '@sveltejs/kit': 1.11.0_svelte@3.55.1+vite@4.1.4
'@tailwindcss/forms': 0.5.3_tailwindcss@3.2.7
'@tailwindcss/typography': 0.5.9_tailwindcss@3.2.7
'@types/luxon': 3.2.0 '@types/luxon': 3.2.0
'@types/marked': 4.0.8 '@types/markdown-it': 12.2.3
'@types/node': 18.15.3 '@types/node': 18.15.3
'@types/sanitize-html': 2.8.1 '@types/sanitize-html': 2.8.1
'@typescript-eslint/eslint-plugin': 5.54.1_mlk7dnz565t663n4razh6a6v6i '@typescript-eslint/eslint-plugin': 5.54.1_mlk7dnz565t663n4razh6a6v6i
'@typescript-eslint/parser': 5.54.1_ycpbpc6yetojsgtrx3mwntkhsu '@typescript-eslint/parser': 5.54.1_ycpbpc6yetojsgtrx3mwntkhsu
autoprefixer: 10.4.13_postcss@8.4.21
eslint: 8.35.0 eslint: 8.35.0
eslint-config-prettier: 8.7.0_eslint@8.35.0 eslint-config-prettier: 8.7.0_eslint@8.35.0
eslint-plugin-svelte3: 4.0.0_n4ieifq2d7jq3sqoe474cgqlim eslint-plugin-svelte3: 4.0.0_n4ieifq2d7jq3sqoe474cgqlim
postcss: 8.4.21
prettier: 2.8.4 prettier: 2.8.4
prettier-plugin-svelte: 2.9.0_jrsxveqmsx2uadbqiuq74wlc4u prettier-plugin-svelte: 2.9.0_jrsxveqmsx2uadbqiuq74wlc4u
svelte: 3.55.1 svelte: 3.55.1
svelte-check: 3.1.0_pehl75e5jsy22vp33udjja4soi svelte-check: 3.1.0_svelte@3.55.1
tailwindcss: 3.2.7_postcss@8.4.21 sveltestrap: 5.10.0_svelte@3.55.1
tslib: 2.5.0 tslib: 2.5.0
typescript: 4.9.5 typescript: 4.9.5
vite: 4.1.4_@types+node@18.15.3 vite: 4.1.4_@types+node@18.15.3
@ -359,7 +349,6 @@ packages:
/@popperjs/core/2.11.6: /@popperjs/core/2.11.6:
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
dev: false
/@rollup/plugin-commonjs/24.0.1_rollup@3.18.0: /@rollup/plugin-commonjs/24.0.1_rollup@3.18.0:
resolution: {integrity: sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==} resolution: {integrity: sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==}
@ -530,27 +519,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@tailwindcss/forms/0.5.3_tailwindcss@3.2.7:
resolution: {integrity: sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==}
peerDependencies:
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
dependencies:
mini-svg-data-uri: 1.4.4
tailwindcss: 3.2.7_postcss@8.4.21
dev: true
/@tailwindcss/typography/0.5.9_tailwindcss@3.2.7:
resolution: {integrity: sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
tailwindcss: 3.2.7_postcss@8.4.21
dev: true
/@types/cookie/0.5.1: /@types/cookie/0.5.1:
resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==} resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
dev: true dev: true
@ -563,12 +531,23 @@ packages:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
dev: true dev: true
/@types/linkify-it/3.0.2:
resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==}
dev: true
/@types/luxon/3.2.0: /@types/luxon/3.2.0:
resolution: {integrity: sha512-lGmaGFoaXHuOLXFvuju2bfvZRqxAqkHPx9Y9IQdQABrinJJshJwfNCKV+u7rR3kJbiqfTF/NhOkcxxAFrObyaA==} resolution: {integrity: sha512-lGmaGFoaXHuOLXFvuju2bfvZRqxAqkHPx9Y9IQdQABrinJJshJwfNCKV+u7rR3kJbiqfTF/NhOkcxxAFrObyaA==}
dev: true dev: true
/@types/marked/4.0.8: /@types/markdown-it/12.2.3:
resolution: {integrity: sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==} resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
dependencies:
'@types/linkify-it': 3.0.2
'@types/mdurl': 1.0.2
dev: true
/@types/mdurl/1.0.2:
resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==}
dev: true dev: true
/@types/node/18.15.3: /@types/node/18.15.3:
@ -738,25 +717,6 @@ packages:
acorn: 8.8.2 acorn: 8.8.2
dev: true dev: true
/acorn-node/1.8.2:
resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==}
dependencies:
acorn: 7.4.1
acorn-walk: 7.2.0
xtend: 4.0.2
dev: true
/acorn-walk/7.2.0:
resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
engines: {node: '>=0.4.0'}
dev: true
/acorn/7.4.1:
resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
/acorn/8.8.2: /acorn/8.8.2:
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
@ -801,35 +761,14 @@ packages:
picomatch: 2.3.1 picomatch: 2.3.1
dev: true dev: true
/arg/5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
dev: true
/argparse/2.0.1: /argparse/2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/array-union/2.1.0: /array-union/2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/autoprefixer/10.4.13_postcss@8.4.21:
resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
dependencies:
browserslist: 4.21.5
caniuse-lite: 1.0.30001464
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
postcss: 8.4.21
postcss-value-parser: 4.2.0
dev: true
/balanced-match/1.0.2: /balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true dev: true
@ -876,17 +815,6 @@ packages:
fill-range: 7.0.1 fill-range: 7.0.1
dev: true dev: true
/browserslist/4.21.5:
resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001464
electron-to-chromium: 1.4.325
node-releases: 2.0.10
update-browserslist-db: 1.0.10_browserslist@4.21.5
dev: true
/buffer-crc32/0.2.13: /buffer-crc32/0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
dev: true dev: true
@ -908,15 +836,6 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true dev: true
/camelcase-css/2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
dev: true
/caniuse-lite/1.0.30001464:
resolution: {integrity: sha512-oww27MtUmusatpRpCGSOneQk2/l5czXANDSFvsc7VuOQ86s3ANhZetpwXNf1zY/zdfP63Xvjz325DAdAoES13g==}
dev: true
/chalk/4.1.2: /chalk/4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -978,12 +897,6 @@ packages:
which: 2.0.2 which: 2.0.2
dev: true dev: true
/cssesc/3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
dev: true
/debug/4.3.4: /debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@ -1003,33 +916,15 @@ packages:
resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==} resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
/defined/1.0.1:
resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==}
dev: true
/detect-indent/6.1.0: /detect-indent/6.1.0:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/detective/5.2.1:
resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==}
engines: {node: '>=0.8.0'}
hasBin: true
dependencies:
acorn-node: 1.8.2
defined: 1.0.1
minimist: 1.2.8
dev: true
/devalue/4.3.0: /devalue/4.3.0:
resolution: {integrity: sha512-n94yQo4LI3w7erwf84mhRUkUJfhLoCZiLyoOZ/QFsDbcWNZePrLwbQpvZBUG2TNxwV3VjCKPxkiiQA6pe3TrTA==} resolution: {integrity: sha512-n94yQo4LI3w7erwf84mhRUkUJfhLoCZiLyoOZ/QFsDbcWNZePrLwbQpvZBUG2TNxwV3VjCKPxkiiQA6pe3TrTA==}
dev: true dev: true
/didyoumean/1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
dev: true
/dir-glob/3.0.1: /dir-glob/3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -1037,10 +932,6 @@ packages:
path-type: 4.0.0 path-type: 4.0.0
dev: true dev: true
/dlv/1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
dev: true
/doctrine/3.0.0: /doctrine/3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
@ -1071,9 +962,10 @@ packages:
domelementtype: 2.3.0 domelementtype: 2.3.0
domhandler: 5.0.3 domhandler: 5.0.3
/electron-to-chromium/1.4.325: /entities/3.0.1:
resolution: {integrity: sha512-K1C03NT4I7BuzsRdCU5RWkgZxtswnKDYM6/eMhkEXqKu4e5T+ck610x3FPzu1y7HVFSiQKZqP16gnJzPpji1TQ==} resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
dev: true engines: {node: '>=0.12'}
dev: false
/entities/4.4.0: /entities/4.4.0:
resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==}
@ -1113,11 +1005,6 @@ packages:
'@esbuild/win32-x64': 0.16.17 '@esbuild/win32-x64': 0.16.17
dev: true dev: true
/escalade/3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
dev: true
/escape-string-regexp/4.0.0: /escape-string-regexp/4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1335,10 +1222,6 @@ packages:
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
dev: true dev: true
/fraction.js/4.2.0:
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
dev: true
/fs.realpath/1.0.0: /fs.realpath/1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true dev: true
@ -1590,10 +1473,11 @@ packages:
type-check: 0.4.0 type-check: 0.4.0
dev: true dev: true
/lilconfig/2.1.0: /linkify-it/4.0.1:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==}
engines: {node: '>=10'} dependencies:
dev: true uc.micro: 1.0.6
dev: false
/locate-path/6.0.0: /locate-path/6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
@ -1602,14 +1486,6 @@ packages:
p-locate: 5.0.0 p-locate: 5.0.0
dev: true dev: true
/lodash.castarray/4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
dev: true
/lodash.isplainobject/4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
dev: true
/lodash.merge/4.6.2: /lodash.merge/4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true dev: true
@ -1651,10 +1527,19 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/sourcemap-codec': 1.4.14
dev: true dev: true
/marked/4.2.12: /markdown-it/13.0.1:
resolution: {integrity: sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==} resolution: {integrity: sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==}
engines: {node: '>= 12'}
hasBin: true hasBin: true
dependencies:
argparse: 2.0.1
entities: 3.0.1
linkify-it: 4.0.1
mdurl: 1.0.1
uc.micro: 1.0.6
dev: false
/mdurl/1.0.1:
resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==}
dev: false dev: false
/merge2/1.4.1: /merge2/1.4.1:
@ -1681,11 +1566,6 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/mini-svg-data-uri/1.4.4:
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
hasBin: true
dev: true
/minimatch/3.1.2: /minimatch/3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies: dependencies:
@ -1736,25 +1616,11 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true dev: true
/node-releases/2.0.10:
resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
dev: true
/normalize-path/3.0.0: /normalize-path/3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true dev: true
/normalize-range/0.1.2:
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
engines: {node: '>=0.10.0'}
dev: true
/object-hash/3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
dev: true
/once/1.4.0: /once/1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies: dependencies:
@ -1830,80 +1696,6 @@ packages:
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
dev: true dev: true
/pify/2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
dev: true
/postcss-import/14.1.0_postcss@8.4.21:
resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==}
engines: {node: '>=10.0.0'}
peerDependencies:
postcss: ^8.0.0
dependencies:
postcss: 8.4.21
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.1
dev: true
/postcss-js/4.0.1_postcss@8.4.21:
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
engines: {node: ^12 || ^14 || >= 16}
peerDependencies:
postcss: ^8.4.21
dependencies:
camelcase-css: 2.0.1
postcss: 8.4.21
dev: true
/postcss-load-config/3.1.4_postcss@8.4.21:
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
engines: {node: '>= 10'}
peerDependencies:
postcss: '>=8.0.9'
ts-node: '>=9.0.0'
peerDependenciesMeta:
postcss:
optional: true
ts-node:
optional: true
dependencies:
lilconfig: 2.1.0
postcss: 8.4.21
yaml: 1.10.2
dev: true
/postcss-nested/6.0.0_postcss@8.4.21:
resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==}
engines: {node: '>=12.0'}
peerDependencies:
postcss: ^8.2.14
dependencies:
postcss: 8.4.21
postcss-selector-parser: 6.0.11
dev: true
/postcss-selector-parser/6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
dev: true
/postcss-selector-parser/6.0.11:
resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==}
engines: {node: '>=4'}
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
dev: true
/postcss-value-parser/4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
dev: true
/postcss/8.4.21: /postcss/8.4.21:
resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@ -1942,17 +1734,6 @@ packages:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true dev: true
/quick-lru/5.1.1:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
dev: true
/read-cache/1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
dependencies:
pify: 2.3.0
dev: true
/readdirp/3.6.0: /readdirp/3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'} engines: {node: '>=8.10.0'}
@ -2137,7 +1918,7 @@ packages:
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dev: true dev: true
/svelte-check/3.1.0_pehl75e5jsy22vp33udjja4soi: /svelte-check/3.1.0_svelte@3.55.1:
resolution: {integrity: sha512-aSdnsGtndfqtb0dmN5qm9Zjl7wGpqh3cWF35WVCcK96TmGn2NEar4M40QW6bvaPPu089mrkZdpeD3Yar2SERBg==} resolution: {integrity: sha512-aSdnsGtndfqtb0dmN5qm9Zjl7wGpqh3cWF35WVCcK96TmGn2NEar4M40QW6bvaPPu089mrkZdpeD3Yar2SERBg==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -2150,7 +1931,7 @@ packages:
picocolors: 1.0.0 picocolors: 1.0.0
sade: 1.8.1 sade: 1.8.1
svelte: 3.55.1 svelte: 3.55.1
svelte-preprocess: 5.0.1_k4bhxdknaltjvjwprbm23edr5q svelte-preprocess: 5.0.1_4x7phaipmicbaooxtnresslofa
typescript: 4.9.5 typescript: 4.9.5
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'
@ -2173,7 +1954,7 @@ packages:
svelte: 3.55.1 svelte: 3.55.1
dev: true dev: true
/svelte-preprocess/5.0.1_k4bhxdknaltjvjwprbm23edr5q: /svelte-preprocess/5.0.1_4x7phaipmicbaooxtnresslofa:
resolution: {integrity: sha512-0HXyhCoc9rsW4zGOgtInylC6qj259E1hpFnJMJWTf+aIfeqh4O/QHT31KT2hvPEqQfdjmqBR/kO2JDkkciBLrQ==} resolution: {integrity: sha512-0HXyhCoc9rsW4zGOgtInylC6qj259E1hpFnJMJWTf+aIfeqh4O/QHT31KT2hvPEqQfdjmqBR/kO2JDkkciBLrQ==}
engines: {node: '>= 14.10.0'} engines: {node: '>= 14.10.0'}
requiresBuild: true requiresBuild: true
@ -2215,7 +1996,6 @@ packages:
'@types/sass': 1.45.0 '@types/sass': 1.45.0
detect-indent: 6.1.0 detect-indent: 6.1.0
magic-string: 0.27.0 magic-string: 0.27.0
postcss: 8.4.21
sorcery: 0.11.0 sorcery: 0.11.0
strip-indent: 3.0.0 strip-indent: 3.0.0
svelte: 3.55.1 svelte: 3.55.1
@ -2225,6 +2005,7 @@ packages:
/svelte/3.55.1: /svelte/3.55.1:
resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==} resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
dev: true
/sveltestrap/5.10.0_svelte@3.55.1: /sveltestrap/5.10.0_svelte@3.55.1:
resolution: {integrity: sha512-k6Ob+6G2AMYvBidXHBKM9W28fJqFHbmosqCe/NC8pv6TV7K+v47Yw+zmnLWkjqCzzmjkSLkL48SrHZrlWc9mYQ==} resolution: {integrity: sha512-k6Ob+6G2AMYvBidXHBKM9W28fJqFHbmosqCe/NC8pv6TV7K+v47Yw+zmnLWkjqCzzmjkSLkL48SrHZrlWc9mYQ==}
@ -2233,40 +2014,6 @@ packages:
dependencies: dependencies:
'@popperjs/core': 2.11.6 '@popperjs/core': 2.11.6
svelte: 3.55.1 svelte: 3.55.1
dev: false
/tailwindcss/3.2.7_postcss@8.4.21:
resolution: {integrity: sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==}
engines: {node: '>=12.13.0'}
hasBin: true
peerDependencies:
postcss: ^8.0.9
dependencies:
arg: 5.0.2
chokidar: 3.5.3
color-name: 1.1.4
detective: 5.2.1
didyoumean: 1.2.2
dlv: 1.1.3
fast-glob: 3.2.12
glob-parent: 6.0.2
is-glob: 4.0.3
lilconfig: 2.1.0
micromatch: 4.0.5
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.0.0
postcss: 8.4.21
postcss-import: 14.1.0_postcss@8.4.21
postcss-js: 4.0.1_postcss@8.4.21
postcss-load-config: 3.1.4_postcss@8.4.21
postcss-nested: 6.0.0_postcss@8.4.21
postcss-selector-parser: 6.0.11
postcss-value-parser: 4.2.0
quick-lru: 5.1.1
resolve: 1.22.1
transitivePeerDependencies:
- ts-node
dev: true dev: true
/text-table/0.2.0: /text-table/0.2.0:
@ -2327,6 +2074,10 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/uc.micro/1.0.6:
resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
dev: false
/undici/5.20.0: /undici/5.20.0:
resolution: {integrity: sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==} resolution: {integrity: sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==}
engines: {node: '>=12.18'} engines: {node: '>=12.18'}
@ -2334,27 +2085,12 @@ packages:
busboy: 1.6.0 busboy: 1.6.0
dev: true dev: true
/update-browserslist-db/1.0.10_browserslist@4.21.5:
resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
dependencies:
browserslist: 4.21.5
escalade: 3.1.1
picocolors: 1.0.0
dev: true
/uri-js/4.4.1: /uri-js/4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies: dependencies:
punycode: 2.3.0 punycode: 2.3.0
dev: true dev: true
/util-deprecate/1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
/vite/4.1.4_@types+node@18.15.3: /vite/4.1.4_@types+node@18.15.3:
resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==} resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
@ -2417,20 +2153,10 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true dev: true
/xtend/4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
dev: true
/yallist/4.0.0: /yallist/4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true dev: true
/yaml/1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
dev: true
/yocto-queue/0.1.0: /yocto-queue/0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}

View File

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -0,0 +1,11 @@
import MarkdownIt from "markdown-it";
import sanitize from "sanitize-html";
const md = new MarkdownIt({
html: false,
breaks: true,
}).disable(["heading", "link", "table"]);
export default function renderMarkdown(src: string | null) {
return src ? sanitize(md.render(src)) : null;
}

View File

@ -1,6 +1,4 @@
<script lang="ts"> <script lang="ts">
import { Card, CardHeader, CardTitle, ListGroup, ListGroupItem } from "sveltestrap";
import type { Field } from "$lib/api/entities"; import type { Field } from "$lib/api/entities";
import StatusIcon from "./StatusIcon.svelte"; import StatusIcon from "./StatusIcon.svelte";

View File

@ -31,7 +31,9 @@
</script> </script>
<div> <div>
<FallbackImage urls={memberAvatars(member)} width={200} alt="Avatar for {member.name}" /> <a href="/@{user.name}/{member.name}">
<FallbackImage urls={memberAvatars(member)} width={200} alt="Avatar for {member.name}" />
</a>
<p class="m-2"> <p class="m-2">
<a class="text-reset fs-5" href="/@{user.name}/{member.name}"> <a class="text-reset fs-5" href="/@{user.name}/{member.name}">
{member.display_name ?? member.name} {member.display_name ?? member.name}

View File

@ -4,18 +4,25 @@
export let pronouns: Pronoun; export let pronouns: Pronoun;
let pronounText: string; let pronounText: string;
if (pronouns.display_text) { $: pronounText = updatePronouns(pronouns);
pronounText = pronouns.display_text;
} else {
const split = pronouns.pronouns.split("/");
if (split.length < 2) pronounText = split.join("/");
else pronounText = split.slice(0, 2).join("/");
}
const link = pronouns.display_text const updatePronouns = (pronouns: Pronoun) => {
if (pronouns.display_text) {
return pronouns.display_text;
} else {
const split = pronouns.pronouns.split("/");
if (split.length < 2) return split.join("/");
else return split.slice(0, 2).join("/");
}
};
let link: string;
let shouldLink: boolean;
$: link = pronouns.display_text
? `${pronouns.pronouns},${pronouns.display_text}` ? `${pronouns.pronouns},${pronouns.display_text}`
: pronouns.pronouns; : pronouns.pronouns;
const shouldLink = pronouns.pronouns.split("/").length === 5; $: shouldLink = pronouns.pronouns.split("/").length === 5;
</script> </script>
{#if shouldLink} {#if shouldLink}

View File

@ -4,7 +4,7 @@ import type { APIError } from "$lib/api/entities";
import { apiFetch } from "$lib/api/fetch"; import { apiFetch } from "$lib/api/fetch";
import type { MetaResponse } from "$lib/api/responses"; import type { MetaResponse } from "$lib/api/responses";
export const load = (async (event) => { export const load = (async () => {
try { try {
return await apiFetch<MetaResponse>("/meta", {}); return await apiFetch<MetaResponse>("/meta", {});
} catch (e) { } catch (e) {

View File

@ -1,7 +1,4 @@
<script lang="ts"> <script lang="ts">
import { marked } from "marked";
import sanitizeHtml from "sanitize-html";
import type { PageData } from "./$types"; import type { PageData } from "./$types";
import { import {
@ -33,11 +30,12 @@
import { apiFetchClient } from "$lib/api/fetch"; import { apiFetchClient } from "$lib/api/fetch";
import ErrorAlert from "$lib/components/ErrorAlert.svelte"; import ErrorAlert from "$lib/components/ErrorAlert.svelte";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
import renderMarkdown from "$lib/api/markdown";
export let data: PageData; export let data: PageData;
let bio: string | null; let bio: string | null;
$: bio = data.bio ? sanitizeHtml(marked.parse(data.bio, { breaks: true })) : null; $: bio = renderMarkdown(data.bio);
let memberPage: number = 0; let memberPage: number = 0;
let memberSlice: PartialMember[] = []; let memberSlice: PartialMember[] = [];

View File

@ -1,7 +1,4 @@
<script lang="ts"> <script lang="ts">
import { marked } from "marked";
import sanitizeHtml from "sanitize-html";
import FieldCard from "$lib/components/FieldCard.svelte"; import FieldCard from "$lib/components/FieldCard.svelte";
import type { PageData } from "./$types"; import type { PageData } from "./$types";
@ -12,11 +9,12 @@
import { memberAvatars, pronounDisplay, WordStatus } from "$lib/api/entities"; import { memberAvatars, pronounDisplay, WordStatus } from "$lib/api/entities";
import { PUBLIC_BASE_URL } from "$env/static/public"; import { PUBLIC_BASE_URL } from "$env/static/public";
import { userStore } from "$lib/store"; import { userStore } from "$lib/store";
import renderMarkdown from "$lib/api/markdown";
export let data: PageData; export let data: PageData;
let bio: string | null; let bio: string | null;
$: bio = data.bio ? sanitizeHtml(marked.parse(data.bio, { breaks: true })) : null; $: bio = renderMarkdown(data.bio);
const favNames = data.names.filter((entry) => entry.status === WordStatus.Favourite); const favNames = data.names.filter((entry) => entry.status === WordStatus.Favourite);
const favPronouns = data.pronouns.filter((entry) => entry.status === WordStatus.Favourite); const favPronouns = data.pronouns.filter((entry) => entry.status === WordStatus.Favourite);

View File

@ -1,6 +1,6 @@
import type { APIError, MeUser } from "$lib/api/entities"; import type { APIError, MeUser } from "$lib/api/entities";
import { apiFetch } from "$lib/api/fetch"; import { apiFetch } from "$lib/api/fetch";
import type { PageServerLoad, Actions } from "./$types"; import type { PageServerLoad } from "./$types";
import { PUBLIC_BASE_URL } from "$env/static/public"; import { PUBLIC_BASE_URL } from "$env/static/public";
export const load = (async ({ url }) => { export const load = (async ({ url }) => {

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { WordStatus, type Field } from "$lib/api/entities"; import { WordStatus, type Field } from "$lib/api/entities";
import IconButton from "$lib/components/IconButton.svelte"; import IconButton from "$lib/components/IconButton.svelte";
import { Button, Input, InputGroup, InputGroupText } from "sveltestrap"; import { Button, Input, InputGroup } from "sveltestrap";
import FieldEntry from "./FieldEntry.svelte"; import FieldEntry from "./FieldEntry.svelte";
export let field: Field; export let field: Field;

View File

@ -88,6 +88,7 @@
const fieldsEqual = (arr1: Field[], arr2: Field[]) => { const fieldsEqual = (arr1: Field[], arr2: Field[]) => {
if (arr1?.length !== arr2?.length) return false; if (arr1?.length !== arr2?.length) return false;
if (!arr1.every((_, i) => arr1[i].entries.length === arr2[i].entries.length)) return false;
if (!arr1.every((_, i) => arr1[i].name === arr2[i].name)) return false; if (!arr1.every((_, i) => arr1[i].name === arr2[i].name)) return false;
return arr1.every((_, i) => return arr1.every((_, i) =>
@ -334,8 +335,8 @@
accept="image/png, image/jpeg, image/gif, image/webp" accept="image/png, image/jpeg, image/gif, image/webp"
/> />
<p class="text-muted mt-3"> <p class="text-muted mt-3">
<Icon name="info-circle-fill" /> Only PNG, JPEG, GIF, and WebP can be used as avatars. <Icon name="info-circle-fill" aria-hidden /> Only PNG, JPEG, GIF, and WebP can be used
Avatars cannot be larger than 1 MB, and animated avatars will be made static. as avatars. Avatars cannot be larger than 1 MB, and animated avatars will be made static.
</p> </p>
<a href="" on:click={() => (avatar = "")}>Remove avatar</a> <a href="" on:click={() => (avatar = "")}>Remove avatar</a>
</div> </div>
@ -356,6 +357,15 @@
<FormGroup floating label="Bio ({bio.length}/{MAX_DESCRIPTION_LENGTH})"> <FormGroup floating label="Bio ({bio.length}/{MAX_DESCRIPTION_LENGTH})">
<textarea style="min-height: 100px;" class="form-control" bind:value={bio} /> <textarea style="min-height: 100px;" class="form-control" bind:value={bio} />
</FormGroup> </FormGroup>
<p class="text-muted mt-3">
<Icon name="info-circle-fill" aria-hidden /> Your bio supports limited
<a
class="text-reset"
href="https://commonmark.org/help/"
target="_blank"
rel="noopener noreferrer">Markdown</a
>.
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -75,6 +75,7 @@
const fieldsEqual = (arr1: Field[], arr2: Field[]) => { const fieldsEqual = (arr1: Field[], arr2: Field[]) => {
if (arr1?.length !== arr2?.length) return false; if (arr1?.length !== arr2?.length) return false;
if (!arr1.every((_, i) => arr1[i].entries.length === arr2[i].entries.length)) return false;
if (!arr1.every((_, i) => arr1[i].name === arr2[i].name)) return false; if (!arr1.every((_, i) => arr1[i].name === arr2[i].name)) return false;
return arr1.every((_, i) => return arr1.every((_, i) =>
@ -281,8 +282,9 @@
accept="image/png, image/jpeg, image/gif, image/webp" accept="image/png, image/jpeg, image/gif, image/webp"
/> />
<p class="text-muted mt-3"> <p class="text-muted mt-3">
<Icon name="info-circle-fill" /> Only PNG, JPEG, GIF, and WebP images can be used as avatars. <Icon name="info-circle-fill" aria-hidden /> Only PNG, JPEG, GIF, and WebP images can be
Avatars cannot be larger than 1 MB, and animated avatars will be made static. used as avatars. Avatars cannot be larger than 1 MB, and animated avatars will be made
static.
</p> </p>
<p> <p>
<a href="" on:click={() => (avatar = "")}>Remove avatar</a> <a href="" on:click={() => (avatar = "")}>Remove avatar</a>
@ -298,6 +300,15 @@
<FormGroup floating label="Bio ({bio.length}/{MAX_DESCRIPTION_LENGTH})"> <FormGroup floating label="Bio ({bio.length}/{MAX_DESCRIPTION_LENGTH})">
<textarea style="min-height: 100px;" class="form-control" bind:value={bio} /> <textarea style="min-height: 100px;" class="form-control" bind:value={bio} />
</FormGroup> </FormGroup>
<p class="text-muted mt-3">
<Icon name="info-circle-fill" aria-hidden /> Your bio supports limited
<a
class="text-reset"
href="https://commonmark.org/help/"
target="_blank"
rel="noopener noreferrer">Markdown</a
>.
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,10 +1,4 @@
import { import { ErrorCode, type APIError, type Invite, type MeUser } from "$lib/api/entities";
ErrorCode,
type APIError,
type Invite,
type MeUser,
type PartialMember,
} from "$lib/api/entities";
import { apiFetchClient } from "$lib/api/fetch"; import { apiFetchClient } from "$lib/api/fetch";
import type { LayoutLoad } from "./$types"; import type { LayoutLoad } from "./$types";
@ -12,7 +6,6 @@ export const ssr = false;
export const load = (async ({ parent }) => { export const load = (async ({ parent }) => {
const user = await apiFetchClient<MeUser>("/users/@me"); const user = await apiFetchClient<MeUser>("/users/@me");
const members = await apiFetchClient<PartialMember[]>("/users/@me/members");
let invites: Invite[] = []; let invites: Invite[] = [];
let invitesEnabled = true; let invitesEnabled = true;
@ -29,7 +22,6 @@ export const load = (async ({ parent }) => {
return { return {
...data, ...data,
user, user,
members,
invites, invites,
invitesEnabled, invitesEnabled,
}; };

View File

@ -91,7 +91,7 @@
</tr> </tr>
<tr> <tr>
<th scope="row">Members</th> <th scope="row">Members</th>
<td>{data.members.length}/{MAX_MEMBERS}</td> <td>{data.user.members.length}/{MAX_MEMBERS}</td>
</tr> </tr>
{#if data.invitesEnabled} {#if data.invitesEnabled}
<tr> <tr>

View File

@ -5,8 +5,8 @@
export let data: PageData; export let data: PageData;
import * as jose from "jose"; import { decodeJwt } from "jose";
const claims = jose.decodeJwt(localStorage.getItem("pronouns-token")!); const claims = decodeJwt(localStorage.getItem("pronouns-token")!);
</script> </script>
<h1>Tokens ({data.tokens.length})</h1> <h1>Tokens ({data.tokens.length})</h1>

View File

@ -1,9 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {},
},
plugins: [require("@tailwindcss/typography"), require("@tailwindcss/forms")],
}