Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
8eaa96f018
|
@ -6,7 +6,7 @@ tmp_dir = "tmp"
|
||||||
bin = "./tmp/main"
|
bin = "./tmp/main"
|
||||||
cmd = "go build -o ./tmp/main ."
|
cmd = "go build -o ./tmp/main ."
|
||||||
delay = 1000
|
delay = 1000
|
||||||
exclude_dir = ["docs", "frontend", "prns", "pronounslib", "tmp", "target"]
|
exclude_dir = ["docs", "frontend", "prns", "pronounslib", "tmp", "target", "node_modules"]
|
||||||
exclude_file = []
|
exclude_file = []
|
||||||
exclude_regex = ["_test.go"]
|
exclude_regex = ["_test.go"]
|
||||||
exclude_unchanged = false
|
exclude_unchanged = false
|
||||||
|
|
|
@ -33,8 +33,9 @@ Requirements:
|
||||||
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. Copy `.env.example` in the repository root to a new file named `.env` and fill out the required options.
|
2. Copy `.env.example` in the repository root to a new file named `.env` and fill out the required options.
|
||||||
3. Run `go run -v . database migrate` to initialize the database, then optionally `go run -v . database seed` to insert a test user.
|
3. Copy `frontend/.env.example` to `frontend/env` and fill out the required options.
|
||||||
4. Run `pnpm dev`. Alternatively, if you don't want the backend to live reload, run `go run -v . web`,
|
4. Run `go run -v . database migrate` to initialize the database, then optionally `go run -v . database seed` to insert a test user.
|
||||||
|
5. Run `pnpm dev`. Alternatively, if you don't want the backend to live reload, run `go run -v . web`,
|
||||||
then change to the `frontend/` directory and run `pnpm dev`.
|
then change to the `frontend/` directory and run `pnpm dev`.
|
||||||
|
|
||||||
See [`docs/production.md`](/docs/production.md#configuration) for more information about keys in the backend and frontend `.env` files.
|
See [`docs/production.md`](/docs/production.md#configuration) for more information about keys in the backend and frontend `.env` files.
|
||||||
|
|
|
@ -43,7 +43,10 @@ func (f Field) Validate(custom CustomPreferences) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !entry.Status.Valid(custom) {
|
if !entry.Status.Valid(custom) {
|
||||||
return fmt.Sprintf("entries.%d: status is invalid", i)
|
if entry.Status == "missing" {
|
||||||
|
return fmt.Sprintf("didn't select a status for entries.%d. make sure to select it to the right of the field", i)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("entries.%d status: '%s' is invalid", i, entry.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,9 @@ func (s *Server) noAppFediverseURL(ctx context.Context, w http.ResponseWriter, r
|
||||||
}
|
}
|
||||||
|
|
||||||
switch softwareName {
|
switch softwareName {
|
||||||
|
case "iceshrimp":
|
||||||
|
softwareName = "firefish"
|
||||||
|
fallthrough
|
||||||
case "misskey", "foundkey", "calckey", "firefish":
|
case "misskey", "foundkey", "calckey", "firefish":
|
||||||
return s.noAppMisskeyURL(ctx, w, r, softwareName, instance)
|
return s.noAppMisskeyURL(ctx, w, r, softwareName, instance)
|
||||||
case "mastodon", "pleroma", "akkoma", "incestoma", "pixelfed", "gotosocial":
|
case "mastodon", "pleroma", "akkoma", "incestoma", "pixelfed", "gotosocial":
|
||||||
|
|
|
@ -49,7 +49,7 @@ func (s *Server) meta(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
|
||||||
var notice *MetaNotice
|
var notice *MetaNotice
|
||||||
if n, err := s.DB.CurrentNotice(ctx); err != nil {
|
if n, err := s.DB.CurrentNotice(ctx); err != nil {
|
||||||
if err == db.ErrNoNotice {
|
if err != db.ErrNoNotice {
|
||||||
log.Errorf("getting notice: %v", err)
|
log.Errorf("getting notice: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Base of frontend URLs
|
# Base of frontend URLs (required)
|
||||||
PUBLIC_BASE_URL=http://localhost:5173
|
PUBLIC_BASE_URL=http://localhost:5173
|
||||||
|
|
||||||
# Base of media URLs, required for avatars, pride flags, and data exports
|
# Base of media URLs, required for avatars, pride flags, and data exports
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parser: '@typescript-eslint/parser',
|
parser: "@typescript-eslint/parser",
|
||||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||||
plugins: ['svelte3', '@typescript-eslint'],
|
plugins: ["svelte3", "@typescript-eslint"],
|
||||||
ignorePatterns: ['*.cjs'],
|
ignorePatterns: ["*.cjs"],
|
||||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||||
settings: {
|
settings: {
|
||||||
'svelte3/typescript': () => require('typescript')
|
"svelte3/typescript": () => require("typescript"),
|
||||||
},
|
},
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: 'module',
|
sourceType: "module",
|
||||||
ecmaVersion: 2020
|
ecmaVersion: 2020,
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
es2017: true,
|
es2017: true,
|
||||||
node: true
|
node: true,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,52 +1,52 @@
|
||||||
{
|
{
|
||||||
"name": "pronouns-fe",
|
"name": "pronouns-fe",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||||
"format": "prettier --plugin-search-dir . --write ."
|
"format": "prettier --plugin-search-dir . --write ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-auto": "^2.0.0",
|
"@sveltejs/adapter-auto": "^2.0.0",
|
||||||
"@sveltejs/adapter-node": "^1.2.3",
|
"@sveltejs/adapter-node": "^1.2.3",
|
||||||
"@sveltejs/kit": "^1.15.0",
|
"@sveltejs/kit": "^1.15.0",
|
||||||
"@types/luxon": "^3.2.2",
|
"@types/luxon": "^3.2.2",
|
||||||
"@types/markdown-it": "^12.2.3",
|
"@types/markdown-it": "^12.2.3",
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
"@types/sanitize-html": "^2.9.0",
|
"@types/sanitize-html": "^2.9.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
||||||
"@typescript-eslint/parser": "^5.57.1",
|
"@typescript-eslint/parser": "^5.57.1",
|
||||||
"eslint": "^8.37.0",
|
"eslint": "^8.37.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-svelte3": "^4.0.0",
|
"eslint-plugin-svelte3": "^4.0.0",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"prettier-plugin-svelte": "^2.10.0",
|
"prettier-plugin-svelte": "^2.10.0",
|
||||||
"svelte": "^3.58.0",
|
"svelte": "^3.58.0",
|
||||||
"svelte-check": "^3.1.4",
|
"svelte-check": "^3.1.4",
|
||||||
"svelte-hcaptcha": "^0.1.1",
|
"svelte-hcaptcha": "^0.1.1",
|
||||||
"sveltestrap": "^5.10.0",
|
"sveltestrap": "^5.10.0",
|
||||||
"tslib": "^2.5.0",
|
"tslib": "^2.5.0",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"vite": "^4.2.1",
|
"vite": "^4.2.1",
|
||||||
"vite-plugin-markdown": "^2.1.0"
|
"vite-plugin-markdown": "^2.1.0"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/firago": "^4.5.3",
|
"@fontsource/firago": "^4.5.3",
|
||||||
"@popperjs/core": "^2.11.7",
|
"@popperjs/core": "^2.11.7",
|
||||||
"@sentry/node": "^7.46.0",
|
"@sentry/node": "^7.46.0",
|
||||||
"base64-arraybuffer": "^1.0.2",
|
"base64-arraybuffer": "^1.0.2",
|
||||||
"bootstrap": "5.3.0-alpha1",
|
"bootstrap": "5.3.0-alpha1",
|
||||||
"bootstrap-icons": "^1.10.4",
|
"bootstrap-icons": "^1.10.4",
|
||||||
"jose": "^4.13.1",
|
"jose": "^4.13.1",
|
||||||
"luxon": "^3.3.0",
|
"luxon": "^3.3.0",
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"pretty-bytes": "^6.1.0",
|
"pretty-bytes": "^6.1.0",
|
||||||
"sanitize-html": "^2.10.0"
|
"sanitize-html": "^2.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -69,7 +69,7 @@ export interface Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Field {
|
export interface Field {
|
||||||
name: string;
|
name: string | null;
|
||||||
entries: FieldEntry[];
|
entries: FieldEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
$: currentPreference =
|
$: currentPreference =
|
||||||
status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.missing;
|
status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.missing;
|
||||||
|
|
||||||
let iconElement: HTMLElement;
|
let iconElement: HTMLSpanElement;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span bind:this={iconElement} tabindex={0}
|
<span bind:this={iconElement} aria-hidden>
|
||||||
><Icon name={currentPreference.icon} class={className} /></span
|
<Icon name={currentPreference.icon} class={className} />
|
||||||
>
|
</span>
|
||||||
<Tooltip target={iconElement} placement="top">{currentPreference.tooltip}</Tooltip>
|
<span class="visually-hidden">{currentPreference.tooltip}:</span>
|
||||||
|
<Tooltip aria-hidden target={iconElement} placement="top">{currentPreference.tooltip}</Tooltip>
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="p-3">
|
<div class="p-3">
|
||||||
<h5>{field.name}</h5>
|
<h5>{field.name ? field.name : "New field"}</h5>
|
||||||
<InputGroup class="m-1">
|
<InputGroup class="m-1">
|
||||||
<IconButton
|
<IconButton
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
tooltip="Move field right"
|
tooltip="Move field right"
|
||||||
click={() => moveField(false)}
|
click={() => moveField(false)}
|
||||||
/>
|
/>
|
||||||
<Input bind:value={field.name} />
|
<Input placeholder="New field" bind:value={field.name} />
|
||||||
<Button color="danger" on:click={() => deleteField()}>Delete field</Button>
|
<Button color="danger" on:click={() => deleteField()}>Delete field</Button>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
<hr />
|
<hr />
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<form class="input-group m-1" on:submit={addEntry}>
|
<form class="m-1 input-group" on:submit={addEntry}>
|
||||||
<input type="text" class="form-control" placeholder="New entry" bind:value={newEntry} />
|
<input type="text" class="form-control" placeholder="New entry" bind:value={newEntry} />
|
||||||
<IconButton color="success" icon="plus" tooltip="Add entry" />
|
<IconButton color="success" icon="plus" tooltip="Add entry" />
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
on:click={() => ($member.fields = [...$member.fields, { name: "New field", entries: [] }])}
|
on:click={() => ($member.fields = [...$member.fields, { name: null, entries: [] }])}
|
||||||
>
|
>
|
||||||
<Icon name="plus" aria-hidden /> Add new field
|
<Icon name="plus" aria-hidden /> Add new field
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button on:click={() => ($user.fields = [...$user.fields, { name: "New field", entries: [] }])}>
|
<Button on:click={() => ($user.fields = [...$user.fields, { name: null, entries: [] }])}>
|
||||||
<Icon name="plus" aria-hidden /> Add new field
|
<Icon name="plus" aria-hidden /> Add new field
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -34,7 +34,9 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const fediLogin = async () => {
|
const fediLogin = async (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
fediDisabled = true;
|
fediDisabled = true;
|
||||||
try {
|
try {
|
||||||
const resp = await apiFetch<{ url: string }>(
|
const resp = await apiFetch<{ url: string }>(
|
||||||
|
@ -71,26 +73,28 @@
|
||||||
{/if}
|
{/if}
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
<Modal header="Pick an instance" isOpen={modalOpen} toggle={toggleModal}>
|
<Modal header="Pick an instance" isOpen={modalOpen} toggle={toggleModal}>
|
||||||
<ModalBody>
|
<form on:submit={(e) => fediLogin(e)}>
|
||||||
<Input placeholder="Instance (e.g. mastodon.social)" bind:value={instance} />
|
<ModalBody>
|
||||||
<p class="text-muted mt-2">
|
<Input placeholder="Instance (e.g. mastodon.social)" bind:value={instance} />
|
||||||
<Icon name="info-circle-fill" aria-label="Info" /> This should be the domain you use to access
|
<p class="text-muted mt-2">
|
||||||
posts. For example, if your username is <code>@timmie@mastodon.example</code>, but your
|
<Icon name="info-circle-fill" aria-label="Info" /> This should be the domain you use to
|
||||||
user <em>page</em> is at
|
access posts. For example, if your username is <code>@timmie@mastodon.example</code>,
|
||||||
<code>social.mastodon.example/timmie</code>, you should fill in
|
but your user <em>page</em> is at
|
||||||
<code>social.mastodon.example</code>.
|
<code>social.mastodon.example/timmie</code>, you should fill in
|
||||||
</p>
|
<code>social.mastodon.example</code>.
|
||||||
{#if error}
|
</p>
|
||||||
<div class="mt-2">
|
{#if error}
|
||||||
<ErrorAlert {error} />
|
<div class="mt-2">
|
||||||
</div>
|
<ErrorAlert {error} />
|
||||||
{/if}
|
</div>
|
||||||
</ModalBody>
|
{/if}
|
||||||
<ModalFooter>
|
</ModalBody>
|
||||||
<Button color="primary" disabled={fediDisabled || instance === ""} on:click={fediLogin}
|
<ModalFooter>
|
||||||
>Log in</Button
|
<Button type="submit" color="primary" disabled={fediDisabled || instance === ""}
|
||||||
>
|
>Log in</Button
|
||||||
</ModalFooter>
|
>
|
||||||
|
</ModalFooter>
|
||||||
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
<p class="text-muted mt-2 mx-1">
|
<p class="text-muted mt-2 mx-1">
|
||||||
<Icon name="info-circle-fill" aria-hidden /> By signing in, you consent to pronouns.cc storing
|
<Icon name="info-circle-fill" aria-hidden /> By signing in, you consent to pronouns.cc storing
|
||||||
|
|
|
@ -44,7 +44,9 @@
|
||||||
let googleUnlinkModalOpen = false;
|
let googleUnlinkModalOpen = false;
|
||||||
let toggleGoogleUnlinkModal = () => (googleUnlinkModalOpen = !googleUnlinkModalOpen);
|
let toggleGoogleUnlinkModal = () => (googleUnlinkModalOpen = !googleUnlinkModalOpen);
|
||||||
|
|
||||||
const fediLogin = async () => {
|
const fediLogin = async (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
fediDisabled = true;
|
fediDisabled = true;
|
||||||
try {
|
try {
|
||||||
const resp = await apiFetch<{ url: string }>(
|
const resp = await apiFetch<{ url: string }>(
|
||||||
|
@ -205,19 +207,21 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<Modal header="Pick an instance" isOpen={fediLinkModalOpen} toggle={toggleFediLinkModal}>
|
<Modal header="Pick an instance" isOpen={fediLinkModalOpen} toggle={toggleFediLinkModal}>
|
||||||
<ModalBody>
|
<form on:submit={(e) => fediLogin(e)}>
|
||||||
<Input placeholder="Instance (e.g. mastodon.social)" bind:value={instance} />
|
<ModalBody>
|
||||||
{#if error}
|
<Input placeholder="Instance (e.g. mastodon.social)" bind:value={instance} />
|
||||||
<div class="mt-2">
|
{#if error}
|
||||||
<ErrorAlert {error} />
|
<div class="mt-2">
|
||||||
</div>
|
<ErrorAlert {error} />
|
||||||
{/if}
|
</div>
|
||||||
</ModalBody>
|
{/if}
|
||||||
<ModalFooter>
|
</ModalBody>
|
||||||
<Button color="primary" disabled={fediDisabled || instance === ""} on:click={fediLogin}
|
<ModalFooter>
|
||||||
>Log in</Button
|
<Button type="submit" color="primary" disabled={fediDisabled || instance === ""}
|
||||||
>
|
>Log in</Button
|
||||||
</ModalFooter>
|
>
|
||||||
|
</ModalFooter>
|
||||||
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
{
|
{
|
||||||
"extends": "./.svelte-kit/tsconfig.json",
|
"extends": "./.svelte-kit/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"ignoreDeprecations": "5.0",
|
"ignoreDeprecations": "5.0",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true
|
"strict": true
|
||||||
}
|
}
|
||||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||||
//
|
//
|
||||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue