{#if error.errors}
diff --git a/Foxnouns.Frontend/src/lib/i18n/locales/en.json b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
index 5d603d7..abc4d85 100644
--- a/Foxnouns.Frontend/src/lib/i18n/locales/en.json
+++ b/Foxnouns.Frontend/src/lib/i18n/locales/en.json
@@ -16,7 +16,8 @@
},
"title": {
"log-in": "Log in",
- "welcome": "Welcome"
+ "welcome": "Welcome",
+ "settings": "Settings"
},
"auth": {
"log-in-form-title": "Log in with email",
@@ -59,5 +60,32 @@
"validation-reason": "Reason",
"validation-generic": "The value you entered is not allowed here. Reason",
"extra-info-header": "Extra error information"
- }
+ },
+ "settings": {
+ "general-information-tab": "General information",
+ "your-profile-tab": "Your profile",
+ "members-tab": "Members",
+ "authentication-tab": "Authentication",
+ "export-tab": "Export your data",
+ "change-username-button": "Change username",
+ "username-change-hint": "Changing your username will make any existing links to your or your members' profiles invalid.\nYour username must be unique, be at most 40 characters long, and only contain letters from the basic English alphabet, dashes, underscores, and periods. Your username is used as part of your profile link, you can set a separate display name.",
+ "username-update-error": "Could not update your username as the new username is invalid:\n{{message}}",
+ "change-avatar-link": "Change your avatar here",
+ "new-username": "New username",
+ "table-role": "Role",
+ "table-custom-preferences": "Custom preferences",
+ "table-member-list-hidden": "Member list hidden?",
+ "table-member-count": "Member count",
+ "table-created-at": "Account created at",
+ "table-id": "Your ID",
+ "table-title": "Account information",
+ "force-log-out-title": "Log out everywhere",
+ "force-log-out-button": "Force log out",
+ "force-log-out-hint": "If you think one of your tokens might have been compromised, you can log out on all devices by clicking this button.",
+ "log-out-title": "Log out",
+ "log-out-hint": "Use this button to log out on this device only.",
+ "log-out-button": "Log out"
+ },
+ "yes": "Yes",
+ "no": "No"
}
diff --git a/Foxnouns.Frontend/src/lib/index.ts b/Foxnouns.Frontend/src/lib/index.ts
index 6b65464..7105327 100644
--- a/Foxnouns.Frontend/src/lib/index.ts
+++ b/Foxnouns.Frontend/src/lib/index.ts
@@ -1,6 +1,7 @@
// place files you want to import through the `$lib` alias in this folder.
import type { Cookies } from "@sveltejs/kit";
+import { DateTime } from "luxon";
export const TOKEN_COOKIE_NAME = "__Host-pronounscc-token";
@@ -10,3 +11,6 @@ export const clearToken = (cookies: Cookies) => cookies.delete(TOKEN_COOKIE_NAME
// TODO: change this to something we actually clearly have the rights to use
export const DEFAULT_AVATAR = "https://pronouns.cc/default/512.webp";
+
+export const idTimestamp = (id: string) =>
+ DateTime.fromMillis(parseInt(id, 10) / (1 << 22) + 1_640_995_200_000);
diff --git a/Foxnouns.Frontend/src/routes/+layout.server.ts b/Foxnouns.Frontend/src/routes/+layout.server.ts
index e73ca7d..00c3ef3 100644
--- a/Foxnouns.Frontend/src/routes/+layout.server.ts
+++ b/Foxnouns.Frontend/src/routes/+layout.server.ts
@@ -1,15 +1,15 @@
import { clearToken, TOKEN_COOKIE_NAME } from "$lib";
import { apiRequest } from "$api";
import ApiError, { ErrorCode } from "$api/error";
-import type { Meta, User } from "$api/models";
+import type { Meta, MeUser } from "$api/models";
import log from "$lib/log";
import type { LayoutServerLoad } from "./$types";
export const load = (async ({ fetch, cookies }) => {
- let meUser: User | null = null;
+ let meUser: MeUser | null = null;
if (cookies.get(TOKEN_COOKIE_NAME)) {
try {
- meUser = await apiRequest("GET", "/users/@me", { fetch, cookies });
+ meUser = await apiRequest("GET", "/users/@me", { fetch, cookies });
} catch (e) {
if (e instanceof ApiError && e.code === ErrorCode.AuthenticationRequired) clearToken(cookies);
else log.error("Could not fetch /users/@me and token has not expired:", e);
diff --git a/Foxnouns.Frontend/src/routes/settings/+layout.server.ts b/Foxnouns.Frontend/src/routes/settings/+layout.server.ts
new file mode 100644
index 0000000..a1ac93c
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/settings/+layout.server.ts
@@ -0,0 +1,8 @@
+import { redirect } from "@sveltejs/kit";
+
+export const load = async ({ parent }) => {
+ const data = await parent();
+ if (!data.meUser) redirect(303, "/auth/log-in");
+
+ return { user: data.meUser! };
+};
diff --git a/Foxnouns.Frontend/src/routes/settings/+layout.svelte b/Foxnouns.Frontend/src/routes/settings/+layout.svelte
new file mode 100644
index 0000000..0b0ac53
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/settings/+layout.svelte
@@ -0,0 +1,44 @@
+
+
+
+ {$t("title.settings")} • pronouns.cc
+
+
+