diff --git a/Makefile b/Makefile index 5f8b50d..475b3bc 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,5 @@ all: generate backend frontend -.PHONY: migrate -migrate: - go run -v ./scripts/migrate - -.PHONY: seeddb -seeddb: - go run -v ./scripts/seeddb - .PHONY: 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`" . diff --git a/README.md b/README.md index b39015a..61c0a99 100644 --- a/README.md +++ b/README.md @@ -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`. 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 Requirements: @@ -40,36 +25,17 @@ Requirements: - PostgreSQL (any currently supported version should work) - Redis 6.0 or later - Node.js (latest version) -- MinIO **if testing uploads** (_not_ required otherwise) +- MinIO **if using avatars or data exports** (_not_ required otherwise) ### Setup 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;` 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. Create a `.env` file in the `frontend/` directory containing `DOMAIN=http://localhost:5173`. -4. Run `make migrate` to initialize the database, then optionally `make seeddb` to insert a test user. -5. Run `go run -v ./backend` to run the backend. -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://:@localhost/ # 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` +3. Run `go run -v . database migrate` to initialize the database, then optionally `go run -v . database seed` to insert a test user. +4. Run `go run -v . web` to run the backend. +5. Create `frontend/.env` with the following content: `PUBLIC_BASE_URL=http://localhost:5173` +6. cd into the `frontend` directory and run `pnpm dev` to run the frontend. ## License diff --git a/backend/routes/member/patch_member.go b/backend/routes/member/patch_member.go index ce89db4..8182c6f 100644 --- a/backend/routes/member/patch_member.go +++ b/backend/routes/member/patch_member.go @@ -190,6 +190,14 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error { return err } 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) + } + } } } diff --git a/backend/routes/user/patch_user.go b/backend/routes/user/patch_user.go index 0a5a228..e56898b 100644 --- a/backend/routes/user/patch_user.go +++ b/backend/routes/user/patch_user.go @@ -137,6 +137,14 @@ func (s *Server) patchUser(w http.ResponseWriter, r *http.Request) error { return err } 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) + } + } } } diff --git a/docs/production.md b/docs/production.md new file mode 100644 index 0000000..8588b71 --- /dev/null +++ b/docs/production.md @@ -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. \ No newline at end of file diff --git a/config/pronouns-api.service b/docs/pronouns-api.service similarity index 100% rename from config/pronouns-api.service rename to docs/pronouns-api.service diff --git a/config/pronouns-clean.service b/docs/pronouns-clean.service similarity index 100% rename from config/pronouns-clean.service rename to docs/pronouns-clean.service diff --git a/config/pronouns-clean.timer b/docs/pronouns-clean.timer similarity index 100% rename from config/pronouns-clean.timer rename to docs/pronouns-clean.timer diff --git a/config/pronouns-exporter.service b/docs/pronouns-exporter.service similarity index 100% rename from config/pronouns-exporter.service rename to docs/pronouns-exporter.service diff --git a/config/pronouns-fe.service b/docs/pronouns-fe.service similarity index 100% rename from config/pronouns-fe.service rename to docs/pronouns-fe.service diff --git a/config/pronounscc.nginx b/docs/pronounscc.nginx similarity index 100% rename from config/pronounscc.nginx rename to docs/pronounscc.nginx diff --git a/frontend/package.json b/frontend/package.json index c346583..e092658 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,24 +15,20 @@ "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/adapter-node": "^1.2.2", "@sveltejs/kit": "^1.5.0", - "@tailwindcss/forms": "^0.5.3", - "@tailwindcss/typography": "^0.5.9", "@types/luxon": "^3.2.0", - "@types/marked": "^4.0.8", + "@types/markdown-it": "^12.2.3", "@types/node": "^18.15.3", "@types/sanitize-html": "^2.8.1", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", - "autoprefixer": "^10.4.13", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte3": "^4.0.0", - "postcss": "^8.4.21", "prettier": "^2.8.0", "prettier-plugin-svelte": "^2.8.1", "svelte": "^3.54.0", "svelte-check": "^3.0.1", - "tailwindcss": "^3.2.7", + "sveltestrap": "^5.10.0", "tslib": "^2.4.1", "typescript": "^4.9.3", "vite": "^4.0.0" @@ -46,8 +42,7 @@ "bootstrap-icons": "^1.10.3", "jose": "^4.13.1", "luxon": "^3.3.0", - "marked": "^4.2.12", - "sanitize-html": "^2.10.0", - "sveltestrap": "^5.10.0" + "markdown-it": "^13.0.1", + "sanitize-html": "^2.10.0" } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 055219f..4b3da03 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -6,15 +6,12 @@ specifiers: '@sveltejs/adapter-auto': ^2.0.0 '@sveltejs/adapter-node': ^1.2.2 '@sveltejs/kit': ^1.5.0 - '@tailwindcss/forms': ^0.5.3 - '@tailwindcss/typography': ^0.5.9 '@types/luxon': ^3.2.0 - '@types/marked': ^4.0.8 + '@types/markdown-it': ^12.2.3 '@types/node': ^18.15.3 '@types/sanitize-html': ^2.8.1 '@typescript-eslint/eslint-plugin': ^5.45.0 '@typescript-eslint/parser': ^5.45.0 - autoprefixer: ^10.4.13 base64-arraybuffer: ^1.0.2 bootstrap: 5.3.0-alpha1 bootstrap-icons: ^1.10.3 @@ -23,15 +20,13 @@ specifiers: eslint-plugin-svelte3: ^4.0.0 jose: ^4.13.1 luxon: ^3.3.0 - marked: ^4.2.12 - postcss: ^8.4.21 + markdown-it: ^13.0.1 prettier: ^2.8.0 prettier-plugin-svelte: ^2.8.1 sanitize-html: ^2.10.0 svelte: ^3.54.0 svelte-check: ^3.0.1 sveltestrap: ^5.10.0 - tailwindcss: ^3.2.7 tslib: ^2.4.1 typescript: ^4.9.3 vite: ^4.0.0 @@ -44,32 +39,27 @@ dependencies: bootstrap-icons: 1.10.3 jose: 4.13.1 luxon: 3.3.0 - marked: 4.2.12 + markdown-it: 13.0.1 sanitize-html: 2.10.0 - sveltestrap: 5.10.0_svelte@3.55.1 devDependencies: '@sveltejs/adapter-auto': 2.0.0_@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 - '@tailwindcss/forms': 0.5.3_tailwindcss@3.2.7 - '@tailwindcss/typography': 0.5.9_tailwindcss@3.2.7 '@types/luxon': 3.2.0 - '@types/marked': 4.0.8 + '@types/markdown-it': 12.2.3 '@types/node': 18.15.3 '@types/sanitize-html': 2.8.1 '@typescript-eslint/eslint-plugin': 5.54.1_mlk7dnz565t663n4razh6a6v6i '@typescript-eslint/parser': 5.54.1_ycpbpc6yetojsgtrx3mwntkhsu - autoprefixer: 10.4.13_postcss@8.4.21 eslint: 8.35.0 eslint-config-prettier: 8.7.0_eslint@8.35.0 eslint-plugin-svelte3: 4.0.0_n4ieifq2d7jq3sqoe474cgqlim - postcss: 8.4.21 prettier: 2.8.4 prettier-plugin-svelte: 2.9.0_jrsxveqmsx2uadbqiuq74wlc4u svelte: 3.55.1 - svelte-check: 3.1.0_pehl75e5jsy22vp33udjja4soi - tailwindcss: 3.2.7_postcss@8.4.21 + svelte-check: 3.1.0_svelte@3.55.1 + sveltestrap: 5.10.0_svelte@3.55.1 tslib: 2.5.0 typescript: 4.9.5 vite: 4.1.4_@types+node@18.15.3 @@ -359,7 +349,6 @@ packages: /@popperjs/core/2.11.6: resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} - dev: false /@rollup/plugin-commonjs/24.0.1_rollup@3.18.0: resolution: {integrity: sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==} @@ -530,27 +519,6 @@ packages: - supports-color 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: resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==} dev: true @@ -563,12 +531,23 @@ packages: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true + /@types/linkify-it/3.0.2: + resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==} + dev: true + /@types/luxon/3.2.0: resolution: {integrity: sha512-lGmaGFoaXHuOLXFvuju2bfvZRqxAqkHPx9Y9IQdQABrinJJshJwfNCKV+u7rR3kJbiqfTF/NhOkcxxAFrObyaA==} dev: true - /@types/marked/4.0.8: - resolution: {integrity: sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==} + /@types/markdown-it/12.2.3: + 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 /@types/node/18.15.3: @@ -738,25 +717,6 @@ packages: acorn: 8.8.2 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: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} @@ -801,35 +761,14 @@ packages: picomatch: 2.3.1 dev: true - /arg/5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: true - /argparse/2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true /array-union/2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} 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: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -876,17 +815,6 @@ packages: fill-range: 7.0.1 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: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} dev: true @@ -908,15 +836,6 @@ packages: engines: {node: '>=6'} 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: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -978,12 +897,6 @@ packages: which: 2.0.2 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: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -1003,33 +916,15 @@ packages: resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==} engines: {node: '>=0.10.0'} - /defined/1.0.1: - resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} - dev: true - /detect-indent/6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} 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: resolution: {integrity: sha512-n94yQo4LI3w7erwf84mhRUkUJfhLoCZiLyoOZ/QFsDbcWNZePrLwbQpvZBUG2TNxwV3VjCKPxkiiQA6pe3TrTA==} dev: true - /didyoumean/1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: true - /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -1037,10 +932,6 @@ packages: path-type: 4.0.0 dev: true - /dlv/1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: true - /doctrine/3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -1071,9 +962,10 @@ packages: domelementtype: 2.3.0 domhandler: 5.0.3 - /electron-to-chromium/1.4.325: - resolution: {integrity: sha512-K1C03NT4I7BuzsRdCU5RWkgZxtswnKDYM6/eMhkEXqKu4e5T+ck610x3FPzu1y7HVFSiQKZqP16gnJzPpji1TQ==} - dev: true + /entities/3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + dev: false /entities/4.4.0: resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} @@ -1113,11 +1005,6 @@ packages: '@esbuild/win32-x64': 0.16.17 dev: true - /escalade/3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - /escape-string-regexp/4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1335,10 +1222,6 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /fraction.js/4.2.0: - resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} - dev: true - /fs.realpath/1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -1590,10 +1473,11 @@ packages: type-check: 0.4.0 dev: true - /lilconfig/2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - dev: true + /linkify-it/4.0.1: + resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==} + dependencies: + uc.micro: 1.0.6 + dev: false /locate-path/6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -1602,14 +1486,6 @@ packages: p-locate: 5.0.0 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: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -1651,10 +1527,19 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /marked/4.2.12: - resolution: {integrity: sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==} - engines: {node: '>= 12'} + /markdown-it/13.0.1: + resolution: {integrity: sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==} 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 /merge2/1.4.1: @@ -1681,11 +1566,6 @@ packages: engines: {node: '>=4'} dev: true - /mini-svg-data-uri/1.4.4: - resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} - hasBin: true - dev: true - /minimatch/3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -1736,25 +1616,11 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /node-releases/2.0.10: - resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} - dev: true - /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} 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: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -1830,80 +1696,6 @@ packages: engines: {node: '>=8.6'} 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: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} engines: {node: ^10 || ^12 || >=14} @@ -1942,17 +1734,6 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 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: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -2137,7 +1918,7 @@ packages: engines: {node: '>= 0.4'} dev: true - /svelte-check/3.1.0_pehl75e5jsy22vp33udjja4soi: + /svelte-check/3.1.0_svelte@3.55.1: resolution: {integrity: sha512-aSdnsGtndfqtb0dmN5qm9Zjl7wGpqh3cWF35WVCcK96TmGn2NEar4M40QW6bvaPPu089mrkZdpeD3Yar2SERBg==} hasBin: true peerDependencies: @@ -2150,7 +1931,7 @@ packages: picocolors: 1.0.0 sade: 1.8.1 svelte: 3.55.1 - svelte-preprocess: 5.0.1_k4bhxdknaltjvjwprbm23edr5q + svelte-preprocess: 5.0.1_4x7phaipmicbaooxtnresslofa typescript: 4.9.5 transitivePeerDependencies: - '@babel/core' @@ -2173,7 +1954,7 @@ packages: svelte: 3.55.1 dev: true - /svelte-preprocess/5.0.1_k4bhxdknaltjvjwprbm23edr5q: + /svelte-preprocess/5.0.1_4x7phaipmicbaooxtnresslofa: resolution: {integrity: sha512-0HXyhCoc9rsW4zGOgtInylC6qj259E1hpFnJMJWTf+aIfeqh4O/QHT31KT2hvPEqQfdjmqBR/kO2JDkkciBLrQ==} engines: {node: '>= 14.10.0'} requiresBuild: true @@ -2215,7 +1996,6 @@ packages: '@types/sass': 1.45.0 detect-indent: 6.1.0 magic-string: 0.27.0 - postcss: 8.4.21 sorcery: 0.11.0 strip-indent: 3.0.0 svelte: 3.55.1 @@ -2225,6 +2005,7 @@ packages: /svelte/3.55.1: resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==} engines: {node: '>= 8'} + dev: true /sveltestrap/5.10.0_svelte@3.55.1: resolution: {integrity: sha512-k6Ob+6G2AMYvBidXHBKM9W28fJqFHbmosqCe/NC8pv6TV7K+v47Yw+zmnLWkjqCzzmjkSLkL48SrHZrlWc9mYQ==} @@ -2233,40 +2014,6 @@ packages: dependencies: '@popperjs/core': 2.11.6 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 /text-table/0.2.0: @@ -2327,6 +2074,10 @@ packages: hasBin: true dev: true + /uc.micro/1.0.6: + resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + dev: false + /undici/5.20.0: resolution: {integrity: sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==} engines: {node: '>=12.18'} @@ -2334,27 +2085,12 @@ packages: busboy: 1.6.0 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: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 dev: true - /util-deprecate/1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true - /vite/4.1.4_@types+node@18.15.3: resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -2417,20 +2153,10 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /xtend/4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - dev: true - /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true - /yaml/1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} - dev: true - /yocto-queue/0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs deleted file mode 100644 index 33ad091..0000000 --- a/frontend/postcss.config.cjs +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/frontend/src/app.css b/frontend/src/app.css deleted file mode 100644 index b5c61c9..0000000 --- a/frontend/src/app.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/frontend/src/lib/api/markdown.ts b/frontend/src/lib/api/markdown.ts new file mode 100644 index 0000000..4557feb --- /dev/null +++ b/frontend/src/lib/api/markdown.ts @@ -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; +} diff --git a/frontend/src/lib/components/FieldCard.svelte b/frontend/src/lib/components/FieldCard.svelte index 489ce0d..a8af4d6 100644 --- a/frontend/src/lib/components/FieldCard.svelte +++ b/frontend/src/lib/components/FieldCard.svelte @@ -1,6 +1,4 @@
- + + +

{member.display_name ?? member.name} diff --git a/frontend/src/lib/components/PronounLink.svelte b/frontend/src/lib/components/PronounLink.svelte index 983a405..30431fe 100644 --- a/frontend/src/lib/components/PronounLink.svelte +++ b/frontend/src/lib/components/PronounLink.svelte @@ -4,18 +4,25 @@ export let pronouns: Pronoun; let pronounText: string; - if (pronouns.display_text) { - pronounText = pronouns.display_text; - } else { - const split = pronouns.pronouns.split("/"); - if (split.length < 2) pronounText = split.join("/"); - else pronounText = split.slice(0, 2).join("/"); - } + $: pronounText = updatePronouns(pronouns); - 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; - const shouldLink = pronouns.pronouns.split("/").length === 5; + $: shouldLink = pronouns.pronouns.split("/").length === 5; {#if shouldLink} diff --git a/frontend/src/routes/+layout.server.ts b/frontend/src/routes/+layout.server.ts index f8d44d8..d26a80c 100644 --- a/frontend/src/routes/+layout.server.ts +++ b/frontend/src/routes/+layout.server.ts @@ -4,7 +4,7 @@ import type { APIError } from "$lib/api/entities"; import { apiFetch } from "$lib/api/fetch"; import type { MetaResponse } from "$lib/api/responses"; -export const load = (async (event) => { +export const load = (async () => { try { return await apiFetch("/meta", {}); } catch (e) { diff --git a/frontend/src/routes/@[username]/+page.svelte b/frontend/src/routes/@[username]/+page.svelte index dbcf766..d249579 100644 --- a/frontend/src/routes/@[username]/+page.svelte +++ b/frontend/src/routes/@[username]/+page.svelte @@ -1,7 +1,4 @@

Tokens ({data.tokens.length})

diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs deleted file mode 100644 index 7988a1b..0000000 --- a/frontend/tailwind.config.cjs +++ /dev/null @@ -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")], -}