metadata and titles
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Title } from "@solidjs/meta";
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { HttpStatusCode } from "@solidjs/start";
|
import { HttpStatusCode } from "@solidjs/start";
|
||||||
import { useNavigate } from "@solidjs/router";
|
import { useNavigate } from "@solidjs/router";
|
||||||
import { createEffect, createSignal, For } from "solid-js";
|
import { createEffect, createSignal, For } from "solid-js";
|
||||||
@@ -47,7 +47,11 @@ export default function Page_401() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>401 - Unauthorized</Title>
|
<Title>401 Unauthorized | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="401 - Unauthorized access. Please log in to access this page."
|
||||||
|
/>
|
||||||
<HttpStatusCode code={401} />
|
<HttpStatusCode code={401} />
|
||||||
<div class="relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-slate-900 via-amber-950/20 to-slate-900 dark:from-black dark:via-amber-950/30 dark:to-black">
|
<div class="relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-slate-900 via-amber-950/20 to-slate-900 dark:from-black dark:via-amber-950/30 dark:to-black">
|
||||||
{/* Animated particle background */}
|
{/* Animated particle background */}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Title } from "@solidjs/meta";
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { HttpStatusCode } from "@solidjs/start";
|
import { HttpStatusCode } from "@solidjs/start";
|
||||||
import { useNavigate } from "@solidjs/router";
|
import { useNavigate } from "@solidjs/router";
|
||||||
import { createEffect, createSignal, For } from "solid-js";
|
import { createEffect, createSignal, For } from "solid-js";
|
||||||
@@ -43,7 +43,11 @@ export default function NotFound() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>404 - Not Found</Title>
|
<Title>404 Not Found | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="404 - Page not found. The page you're looking for doesn't exist."
|
||||||
|
/>
|
||||||
<HttpStatusCode code={404} />
|
<HttpStatusCode code={404} />
|
||||||
<div class="relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 dark:from-black dark:via-slate-900 dark:to-black">
|
<div class="relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 dark:from-black dark:via-slate-900 dark:to-black">
|
||||||
{/* Animated particle background */}
|
{/* Animated particle background */}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
import { Title } from "@solidjs/meta";
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
|
|
||||||
export default function About() {
|
export default function About() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>About | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Learn more about Michael Freno - Software Engineer, game developer, and open source contributor."
|
||||||
|
/>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<Title>About</Title>
|
|
||||||
<h1>About</h1>
|
<h1>About</h1>
|
||||||
</main>
|
</main>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createSignal, createEffect, Show, onMount } from "solid-js";
|
import { createSignal, createEffect, Show, onMount } from "solid-js";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { useNavigate, cache, redirect } from "@solidjs/router";
|
import { useNavigate, cache, redirect } from "@solidjs/router";
|
||||||
import { getEvent } from "vinxi/http";
|
import { getEvent } from "vinxi/http";
|
||||||
import Eye from "~/components/icons/Eye";
|
import Eye from "~/components/icons/Eye";
|
||||||
@@ -453,6 +454,13 @@ export default function AccountPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Account | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Manage your account settings, update profile information, and configure preferences."
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="bg-base mx-8 min-h-screen md:mx-24 lg:mx-36">
|
<div class="bg-base mx-8 min-h-screen md:mx-24 lg:mx-36">
|
||||||
<div class="pt-24">
|
<div class="pt-24">
|
||||||
<Show
|
<Show
|
||||||
@@ -507,7 +515,9 @@ export default function AccountPage() {
|
|||||||
: "bg-blue hover:brightness-125 active:scale-90"
|
: "bg-blue hover:brightness-125 active:scale-90"
|
||||||
} mt-2 flex w-full justify-center rounded px-4 py-2 text-base transition-all duration-300 ease-out`}
|
} mt-2 flex w-full justify-center rounded px-4 py-2 text-base transition-all duration-300 ease-out`}
|
||||||
>
|
>
|
||||||
{profileImageSetLoading() ? "Uploading..." : "Set Image"}
|
{profileImageSetLoading()
|
||||||
|
? "Uploading..."
|
||||||
|
: "Set Image"}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<Show when={showImageSuccess()}>
|
<Show when={showImageSuccess()}>
|
||||||
@@ -618,7 +628,8 @@ export default function AccountPage() {
|
|||||||
/>
|
/>
|
||||||
<span class="bar"></span>
|
<span class="bar"></span>
|
||||||
<label class="underlinedInputLabel">
|
<label class="underlinedInputLabel">
|
||||||
Set {currentUser().displayName ? "New " : ""}Display Name
|
Set {currentUser().displayName ? "New " : ""}Display
|
||||||
|
Name
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
@@ -631,7 +642,9 @@ export default function AccountPage() {
|
|||||||
: "bg-blue hover:brightness-125 active:scale-90"
|
: "bg-blue hover:brightness-125 active:scale-90"
|
||||||
} mt-2 flex justify-center rounded px-4 py-2 text-base transition-all duration-300 ease-out`}
|
} mt-2 flex justify-center rounded px-4 py-2 text-base transition-all duration-300 ease-out`}
|
||||||
>
|
>
|
||||||
{displayNameButtonLoading() ? "Submitting..." : "Submit"}
|
{displayNameButtonLoading()
|
||||||
|
? "Submitting..."
|
||||||
|
: "Submit"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<Show when={showDisplayNameSuccess()}>
|
<Show when={showDisplayNameSuccess()}>
|
||||||
@@ -673,7 +686,10 @@ export default function AccountPage() {
|
|||||||
}
|
}
|
||||||
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
||||||
>
|
>
|
||||||
<Show when={showOldPasswordInput()} fallback={<Eye />}>
|
<Show
|
||||||
|
when={showOldPasswordInput()}
|
||||||
|
fallback={<Eye />}
|
||||||
|
>
|
||||||
<EyeSlash />
|
<EyeSlash />
|
||||||
</Show>
|
</Show>
|
||||||
</button>
|
</button>
|
||||||
@@ -695,7 +711,9 @@ export default function AccountPage() {
|
|||||||
<label class="underlinedInputLabel">New Password</label>
|
<label class="underlinedInputLabel">New Password</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowPasswordInput(!showPasswordInput())}
|
onClick={() =>
|
||||||
|
setShowPasswordInput(!showPasswordInput())
|
||||||
|
}
|
||||||
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
||||||
>
|
>
|
||||||
<Show when={showPasswordInput()} fallback={<Eye />}>
|
<Show when={showPasswordInput()} fallback={<Eye />}>
|
||||||
@@ -837,5 +855,6 @@ export default function AccountPage() {
|
|||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Show, Suspense, For } from "solid-js";
|
import { Show, Suspense, For } from "solid-js";
|
||||||
import { useParams, A, Navigate, query } from "@solidjs/router";
|
import { useParams, A, Navigate, query } from "@solidjs/router";
|
||||||
import { Title } from "@solidjs/meta";
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { createAsync } from "@solidjs/router";
|
import { createAsync } from "@solidjs/router";
|
||||||
import { getRequestEvent } from "solid-js/web";
|
import { getRequestEvent } from "solid-js/web";
|
||||||
import SessionDependantLike from "~/components/blog/SessionDependantLike";
|
import SessionDependantLike from "~/components/blog/SessionDependantLike";
|
||||||
@@ -159,6 +159,13 @@ export default function PostPage() {
|
|||||||
<Title>
|
<Title>
|
||||||
{p().title.replaceAll("_", " ")} | Michael Freno
|
{p().title.replaceAll("_", " ")} | Michael Freno
|
||||||
</Title>
|
</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content={
|
||||||
|
p().subtitle ||
|
||||||
|
`Read ${p().title.replaceAll("_", " ")} by Michael Freno on the freno.me blog.`
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="relative overflow-x-hidden">
|
<div class="relative overflow-x-hidden">
|
||||||
{/* Fixed banner image background */}
|
{/* Fixed banner image background */}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Show, createSignal, createEffect, onCleanup } from "solid-js";
|
import { Show, createSignal, createEffect, onCleanup } from "solid-js";
|
||||||
import { useNavigate, query } from "@solidjs/router";
|
import { useNavigate, query } from "@solidjs/router";
|
||||||
import { Title } from "@solidjs/meta";
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { createAsync } from "@solidjs/router";
|
import { createAsync } from "@solidjs/router";
|
||||||
import { getRequestEvent } from "solid-js/web";
|
import { getRequestEvent } from "solid-js/web";
|
||||||
import { api } from "~/lib/api";
|
import { api } from "~/lib/api";
|
||||||
@@ -195,6 +195,10 @@ export default function CreatePost() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>Create Blog Post | Michael Freno</Title>
|
<Title>Create Blog Post | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Create a new blog post with rich text editing, image uploads, and tag management."
|
||||||
|
/>
|
||||||
|
|
||||||
<Show
|
<Show
|
||||||
when={authState()?.privilegeLevel === "admin"}
|
when={authState()?.privilegeLevel === "admin"}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Show, createSignal, createEffect, onCleanup } from "solid-js";
|
import { Show, createSignal, createEffect, onCleanup } from "solid-js";
|
||||||
import { useParams, useNavigate, query } from "@solidjs/router";
|
import { useParams, useNavigate, query } from "@solidjs/router";
|
||||||
import { Title } from "@solidjs/meta";
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { createAsync } from "@solidjs/router";
|
import { createAsync } from "@solidjs/router";
|
||||||
import { getRequestEvent } from "solid-js/web";
|
import { getRequestEvent } from "solid-js/web";
|
||||||
import { api } from "~/lib/api";
|
import { api } from "~/lib/api";
|
||||||
@@ -241,6 +241,10 @@ export default function EditPost() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>Edit Post | Michael Freno</Title>
|
<Title>Edit Post | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Edit your blog post with rich text editing, image management, and tag updates."
|
||||||
|
/>
|
||||||
|
|
||||||
<Show
|
<Show
|
||||||
when={data()?.privilegeLevel === "admin"}
|
when={data()?.privilegeLevel === "admin"}
|
||||||
|
|||||||
@@ -1,23 +1,32 @@
|
|||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import DeletionForm from "~/components/DeletionForm";
|
import DeletionForm from "~/components/DeletionForm";
|
||||||
|
|
||||||
export default function LifeAndLinageDeletionForm() {
|
export default function LifeAndLinageDeletionForm() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Account Deletion - Life and Lineage | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Request account deletion for Life and Lineage. Remove all your data from our system with a 24-hour grace period."
|
||||||
|
/>
|
||||||
<div class="pt-20">
|
<div class="pt-20">
|
||||||
<div class="mx-auto p-4 md:p-6 lg:p-12">
|
<div class="mx-auto p-4 md:p-6 lg:p-12">
|
||||||
<div class="w-full justify-center text-text">
|
<div class="text-text w-full justify-center">
|
||||||
<div class="text-xl">
|
<div class="text-xl">
|
||||||
<em>What will happen</em>:
|
<em>What will happen</em>:
|
||||||
</div>
|
</div>
|
||||||
Once you send, if a match to the email provided is found in our
|
Once you send, if a match to the email provided is found in our
|
||||||
system, a 24hr grace period is started where you can request a
|
system, a 24hr grace period is started where you can request a
|
||||||
cancellation of the account deletion. Once the grace period ends, the
|
cancellation of the account deletion. Once the grace period ends,
|
||||||
account's entry in our central database will be completely removed,
|
the account's entry in our central database will be completely
|
||||||
and your individual database storing your remote saves will also be
|
removed, and your individual database storing your remote saves will
|
||||||
deleted. No data related to the account is retained in any way.
|
also be deleted. No data related to the account is retained in any
|
||||||
|
way.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DeletionForm />
|
<DeletionForm />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { A } from "@solidjs/router";
|
import { A } from "@solidjs/router";
|
||||||
import DownloadOnAppStore from "~/components/icons/DownloadOnAppStore";
|
import DownloadOnAppStore from "~/components/icons/DownloadOnAppStore";
|
||||||
import GitHub from "~/components/icons/GitHub";
|
import GitHub from "~/components/icons/GitHub";
|
||||||
@@ -21,6 +22,13 @@ export default function DownloadsPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Downloads | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Download Life and Lineage, Shapes with Abigail, and Cork for macOS. Available on iOS, Android, and macOS."
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="bg-base min-h-screen pt-[15vh] pb-12">
|
<div class="bg-base min-h-screen pt-[15vh] pb-12">
|
||||||
<div class="text-text text-center text-3xl tracking-widest">
|
<div class="text-text text-center text-3xl tracking-widest">
|
||||||
Downloads
|
Downloads
|
||||||
@@ -163,5 +171,6 @@ export default function DownloadsPage() {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import DownloadOnAppStore from "~/components/icons/DownloadOnAppStore";
|
import DownloadOnAppStore from "~/components/icons/DownloadOnAppStore";
|
||||||
import { Typewriter } from "~/components/Typewriter";
|
import { Typewriter } from "~/components/Typewriter";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Home | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Michael Freno - Software Engineer based in Brooklyn, NY. Passionate about dev tooling, game development, and open source software."
|
||||||
|
/>
|
||||||
|
|
||||||
<main class="flex h-full flex-col gap-8 p-4 text-xl">
|
<main class="flex h-full flex-col gap-8 p-4 text-xl">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<Typewriter speed={30} keepAlive={2000}>
|
<Typewriter speed={30} keepAlive={2000}>
|
||||||
@@ -151,5 +159,6 @@ export default function Home() {
|
|||||||
</Typewriter>
|
</Typewriter>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
cache,
|
cache,
|
||||||
redirect
|
redirect
|
||||||
} from "@solidjs/router";
|
} from "@solidjs/router";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { getEvent } from "vinxi/http";
|
import { getEvent } from "vinxi/http";
|
||||||
import GoogleLogo from "~/components/icons/GoogleLogo";
|
import GoogleLogo from "~/components/icons/GoogleLogo";
|
||||||
import GitHub from "~/components/icons/GitHub";
|
import GitHub from "~/components/icons/GitHub";
|
||||||
@@ -320,6 +321,12 @@ export default function LoginPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Login | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Sign in to your account or register for a new account to access personalized features and manage your profile."
|
||||||
|
/>
|
||||||
<div class="flex h-dvh flex-row justify-evenly">
|
<div class="flex h-dvh flex-row justify-evenly">
|
||||||
{/* Logo section - hidden on mobile */}
|
{/* Logo section - hidden on mobile */}
|
||||||
{/* <div class="hidden md:flex">
|
{/* <div class="hidden md:flex">
|
||||||
@@ -639,5 +646,6 @@ export default function LoginPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createSignal, createEffect, Show } from "solid-js";
|
import { createSignal, createEffect, Show } from "solid-js";
|
||||||
import { A, useNavigate, useSearchParams } from "@solidjs/router";
|
import { A, useNavigate, useSearchParams } from "@solidjs/router";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import CountdownCircleTimer from "~/components/CountdownCircleTimer";
|
import CountdownCircleTimer from "~/components/CountdownCircleTimer";
|
||||||
import Eye from "~/components/icons/Eye";
|
import Eye from "~/components/icons/Eye";
|
||||||
import EyeSlash from "~/components/icons/EyeSlash";
|
import EyeSlash from "~/components/icons/EyeSlash";
|
||||||
@@ -13,8 +14,10 @@ export default function PasswordResetPage() {
|
|||||||
const [passwordBlurred, setPasswordBlurred] = createSignal(false);
|
const [passwordBlurred, setPasswordBlurred] = createSignal(false);
|
||||||
const [passwordChangeLoading, setPasswordChangeLoading] = createSignal(false);
|
const [passwordChangeLoading, setPasswordChangeLoading] = createSignal(false);
|
||||||
const [passwordsMatch, setPasswordsMatch] = createSignal(false);
|
const [passwordsMatch, setPasswordsMatch] = createSignal(false);
|
||||||
const [showPasswordLengthWarning, setShowPasswordLengthWarning] = createSignal(false);
|
const [showPasswordLengthWarning, setShowPasswordLengthWarning] =
|
||||||
const [passwordLengthSufficient, setPasswordLengthSufficient] = createSignal(false);
|
createSignal(false);
|
||||||
|
const [passwordLengthSufficient, setPasswordLengthSufficient] =
|
||||||
|
createSignal(false);
|
||||||
const [showRequestNewEmail, setShowRequestNewEmail] = createSignal(false);
|
const [showRequestNewEmail, setShowRequestNewEmail] = createSignal(false);
|
||||||
const [countDown, setCountDown] = createSignal(false);
|
const [countDown, setCountDown] = createSignal(false);
|
||||||
const [error, setError] = createSignal("");
|
const [error, setError] = createSignal("");
|
||||||
@@ -70,8 +73,8 @@ export default function PasswordResetPage() {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
token: token,
|
token: token,
|
||||||
newPassword,
|
newPassword,
|
||||||
newPasswordConfirmation: newPasswordConf,
|
newPasswordConfirmation: newPasswordConf
|
||||||
}),
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
@@ -158,14 +161,26 @@ export default function PasswordResetPage() {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div class="timer text-center">
|
<div class="timer text-center">
|
||||||
<div class="text-sm text-slate-700 dark:text-slate-300">Change Successful!</div>
|
<div class="text-sm text-slate-700 dark:text-slate-300">
|
||||||
<div class="value py-1 text-3xl text-blue-500 dark:text-blue-400">{timeRemaining}</div>
|
Change Successful!
|
||||||
<div class="text-sm text-slate-700 dark:text-slate-300">Redirecting...</div>
|
</div>
|
||||||
|
<div class="value py-1 text-3xl text-blue-500 dark:text-blue-400">
|
||||||
|
{timeRemaining}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-slate-700 dark:text-slate-300">
|
||||||
|
Redirecting...
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Reset Password | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Set a new password for your account to regain access to your profile and personalized features."
|
||||||
|
/>
|
||||||
<div class="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
|
<div class="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
|
||||||
<div class="pt-24 text-center text-xl font-semibold text-slate-800 dark:text-slate-100">
|
<div class="pt-24 text-center text-xl font-semibold text-slate-800 dark:text-slate-100">
|
||||||
Set New Password
|
Set New Password
|
||||||
@@ -175,9 +190,9 @@ export default function PasswordResetPage() {
|
|||||||
onSubmit={(e) => setNewPasswordTrigger(e)}
|
onSubmit={(e) => setNewPasswordTrigger(e)}
|
||||||
class="mt-4 flex w-full justify-center"
|
class="mt-4 flex w-full justify-center"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col justify-center max-w-md w-full px-4">
|
<div class="flex w-full max-w-md flex-col justify-center px-4">
|
||||||
{/* New Password Input */}
|
{/* New Password Input */}
|
||||||
<div class="input-group mx-4 relative">
|
<div class="input-group relative mx-4">
|
||||||
<input
|
<input
|
||||||
ref={newPasswordRef}
|
ref={newPasswordRef}
|
||||||
name="newPassword"
|
name="newPassword"
|
||||||
@@ -194,7 +209,7 @@ export default function PasswordResetPage() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowPasswordInput(!showPasswordInput())}
|
onClick={() => setShowPasswordInput(!showPasswordInput())}
|
||||||
class="absolute right-0 top-2 text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
|
class="absolute top-2 right-0 text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
|
||||||
>
|
>
|
||||||
<Show when={showPasswordInput()} fallback={<Eye />}>
|
<Show when={showPasswordInput()} fallback={<Eye />}>
|
||||||
<EyeSlash />
|
<EyeSlash />
|
||||||
@@ -205,14 +220,14 @@ export default function PasswordResetPage() {
|
|||||||
{/* Password Length Warning */}
|
{/* Password Length Warning */}
|
||||||
<div
|
<div
|
||||||
class={`${
|
class={`${
|
||||||
showPasswordLengthWarning() ? "" : "select-none opacity-0"
|
showPasswordLengthWarning() ? "" : "opacity-0 select-none"
|
||||||
} transition-opacity text-center text-red-500 text-sm duration-200 ease-in-out mt-2`}
|
} mt-2 text-center text-sm text-red-500 transition-opacity duration-200 ease-in-out`}
|
||||||
>
|
>
|
||||||
Password too short! Min Length: 8
|
Password too short! Min Length: 8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Password Confirmation Input */}
|
{/* Password Confirmation Input */}
|
||||||
<div class="input-group mx-4 mt-6 relative">
|
<div class="input-group relative mx-4 mt-6">
|
||||||
<input
|
<input
|
||||||
ref={newPasswordConfRef}
|
ref={newPasswordConfRef}
|
||||||
name="newPasswordConf"
|
name="newPasswordConf"
|
||||||
@@ -227,8 +242,10 @@ export default function PasswordResetPage() {
|
|||||||
<label class="underlinedInputLabel">Password Confirmation</label>
|
<label class="underlinedInputLabel">Password Confirmation</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowPasswordConfInput(!showPasswordConfInput())}
|
onClick={() =>
|
||||||
class="absolute right-0 top-2 text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
|
setShowPasswordConfInput(!showPasswordConfInput())
|
||||||
|
}
|
||||||
|
class="absolute top-2 right-0 text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
|
||||||
>
|
>
|
||||||
<Show when={showPasswordConfInput()} fallback={<Eye />}>
|
<Show when={showPasswordConfInput()} fallback={<Eye />}>
|
||||||
<EyeSlash />
|
<EyeSlash />
|
||||||
@@ -244,8 +261,8 @@ export default function PasswordResetPage() {
|
|||||||
newPasswordConfRef &&
|
newPasswordConfRef &&
|
||||||
newPasswordConfRef.value.length >= 6
|
newPasswordConfRef.value.length >= 6
|
||||||
? ""
|
? ""
|
||||||
: "select-none opacity-0"
|
: "opacity-0 select-none"
|
||||||
} transition-opacity text-center text-red-500 text-sm duration-200 ease-in-out mt-2`}
|
} mt-2 text-center text-sm text-red-500 transition-opacity duration-200 ease-in-out`}
|
||||||
>
|
>
|
||||||
Passwords do not match!
|
Passwords do not match!
|
||||||
</div>
|
</div>
|
||||||
@@ -259,9 +276,9 @@ export default function PasswordResetPage() {
|
|||||||
disabled={passwordChangeLoading() || !passwordsMatch()}
|
disabled={passwordChangeLoading() || !passwordsMatch()}
|
||||||
class={`${
|
class={`${
|
||||||
passwordChangeLoading() || !passwordsMatch()
|
passwordChangeLoading() || !passwordsMatch()
|
||||||
? "bg-zinc-400 cursor-not-allowed"
|
? "cursor-not-allowed bg-zinc-400"
|
||||||
: "bg-blue-400 hover:bg-blue-500 active:scale-90 dark:bg-blue-600 dark:hover:bg-blue-700"
|
: "bg-blue-400 hover:bg-blue-500 active:scale-90 dark:bg-blue-600 dark:hover:bg-blue-700"
|
||||||
} flex justify-center rounded transition-all duration-300 ease-out my-6 px-4 py-2 text-white font-medium`}
|
} my-6 flex justify-center rounded px-4 py-2 font-medium text-white transition-all duration-300 ease-out`}
|
||||||
>
|
>
|
||||||
{passwordChangeLoading() ? "Setting..." : "Set New Password"}
|
{passwordChangeLoading() ? "Setting..." : "Set New Password"}
|
||||||
</button>
|
</button>
|
||||||
@@ -285,16 +302,16 @@ export default function PasswordResetPage() {
|
|||||||
|
|
||||||
{/* Error Message */}
|
{/* Error Message */}
|
||||||
<Show when={error() && !showRequestNewEmail()}>
|
<Show when={error() && !showRequestNewEmail()}>
|
||||||
<div class="flex justify-center mt-4">
|
<div class="mt-4 flex justify-center">
|
||||||
<div class="text-red-500 text-sm italic">{error()}</div>
|
<div class="text-sm text-red-500 italic">{error()}</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
{/* Token Expired Message */}
|
{/* Token Expired Message */}
|
||||||
<div
|
<div
|
||||||
class={`${
|
class={`${
|
||||||
showRequestNewEmail() ? "" : "select-none opacity-0"
|
showRequestNewEmail() ? "" : "opacity-0 select-none"
|
||||||
} text-red-500 italic transition-opacity flex justify-center duration-300 ease-in-out px-4`}
|
} flex justify-center px-4 text-red-500 italic transition-opacity duration-300 ease-in-out`}
|
||||||
>
|
>
|
||||||
Token has expired, request a new one{" "}
|
Token has expired, request a new one{" "}
|
||||||
<A
|
<A
|
||||||
@@ -307,15 +324,16 @@ export default function PasswordResetPage() {
|
|||||||
|
|
||||||
{/* Back to Login Link */}
|
{/* Back to Login Link */}
|
||||||
<Show when={!countDown()}>
|
<Show when={!countDown()}>
|
||||||
<div class="flex justify-center mt-6">
|
<div class="mt-6 flex justify-center">
|
||||||
<A
|
<A
|
||||||
href="/login"
|
href="/login"
|
||||||
class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 underline underline-offset-4 transition-colors"
|
class="text-blue-500 underline underline-offset-4 transition-colors hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||||
>
|
>
|
||||||
Back to Login
|
Back to Login
|
||||||
</A>
|
</A>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createSignal, createEffect, onCleanup, Show } from "solid-js";
|
import { createSignal, createEffect, onCleanup, Show } from "solid-js";
|
||||||
import { A, useNavigate } from "@solidjs/router";
|
import { A, useNavigate } from "@solidjs/router";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import CountdownCircleTimer from "~/components/CountdownCircleTimer";
|
import CountdownCircleTimer from "~/components/CountdownCircleTimer";
|
||||||
import { isValidEmail } from "~/lib/validation";
|
import { isValidEmail } from "~/lib/validation";
|
||||||
import { getClientCookie } from "~/lib/cookies.client";
|
import { getClientCookie } from "~/lib/cookies.client";
|
||||||
@@ -37,7 +38,10 @@ export default function RequestPasswordResetPage() {
|
|||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const timer = getClientCookie("passwordResetRequested");
|
const timer = getClientCookie("passwordResetRequested");
|
||||||
if (timer) {
|
if (timer) {
|
||||||
timerInterval = setInterval(() => calcRemainder(timer), 1000) as unknown as number;
|
timerInterval = setInterval(
|
||||||
|
() => calcRemainder(timer),
|
||||||
|
1000
|
||||||
|
) as unknown as number;
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
if (timerInterval) {
|
if (timerInterval) {
|
||||||
clearInterval(timerInterval);
|
clearInterval(timerInterval);
|
||||||
@@ -71,7 +75,7 @@ export default function RequestPasswordResetPage() {
|
|||||||
const response = await fetch("/api/trpc/auth.requestPasswordReset", {
|
const response = await fetch("/api/trpc/auth.requestPasswordReset", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ email }),
|
body: JSON.stringify({ email })
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
@@ -115,6 +119,12 @@ export default function RequestPasswordResetPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Request Password Reset | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Request a password reset link to regain access to your account. Enter your email to receive reset instructions."
|
||||||
|
/>
|
||||||
<div class="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
|
<div class="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
|
||||||
<div class="pt-24 text-center text-xl font-semibold text-slate-800 dark:text-slate-100">
|
<div class="pt-24 text-center text-xl font-semibold text-slate-800 dark:text-slate-100">
|
||||||
Password Reset Request
|
Password Reset Request
|
||||||
@@ -151,7 +161,7 @@ export default function RequestPasswordResetPage() {
|
|||||||
loading()
|
loading()
|
||||||
? "bg-zinc-400"
|
? "bg-zinc-400"
|
||||||
: "bg-blue-400 hover:bg-blue-500 active:scale-90 dark:bg-blue-600 dark:hover:bg-blue-700"
|
: "bg-blue-400 hover:bg-blue-500 active:scale-90 dark:bg-blue-600 dark:hover:bg-blue-700"
|
||||||
} flex justify-center rounded transition-all duration-300 ease-out my-6 px-4 py-2 text-white font-medium`}
|
} my-6 flex justify-center rounded px-4 py-2 font-medium text-white transition-all duration-300 ease-out`}
|
||||||
>
|
>
|
||||||
{loading() ? "Sending..." : "Request Password Reset"}
|
{loading() ? "Sending..." : "Request Password Reset"}
|
||||||
</button>
|
</button>
|
||||||
@@ -177,28 +187,29 @@ export default function RequestPasswordResetPage() {
|
|||||||
{/* Success Message */}
|
{/* Success Message */}
|
||||||
<div
|
<div
|
||||||
class={`${
|
class={`${
|
||||||
showSuccessMessage() ? "" : "select-none opacity-0"
|
showSuccessMessage() ? "" : "opacity-0 select-none"
|
||||||
} text-green-500 italic transition-opacity flex justify-center duration-300 ease-in-out`}
|
} flex justify-center text-green-500 italic transition-opacity duration-300 ease-in-out`}
|
||||||
>
|
>
|
||||||
If email exists, you will receive an email shortly!
|
If email exists, you will receive an email shortly!
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Error Message */}
|
{/* Error Message */}
|
||||||
<Show when={error()}>
|
<Show when={error()}>
|
||||||
<div class="flex justify-center mt-4">
|
<div class="mt-4 flex justify-center">
|
||||||
<div class="text-red-500 text-sm italic">{error()}</div>
|
<div class="text-sm text-red-500 italic">{error()}</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
{/* Back to Login Link */}
|
{/* Back to Login Link */}
|
||||||
<div class="flex justify-center mt-6">
|
<div class="mt-6 flex justify-center">
|
||||||
<A
|
<A
|
||||||
href="/login"
|
href="/login"
|
||||||
class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 underline underline-offset-4 transition-colors"
|
class="text-blue-500 underline underline-offset-4 transition-colors hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||||
>
|
>
|
||||||
Back to Login
|
Back to Login
|
||||||
</A>
|
</A>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
import { A } from "@solidjs/router";
|
import { A } from "@solidjs/router";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import SimpleParallax from "~/components/SimpleParallax";
|
import SimpleParallax from "~/components/SimpleParallax";
|
||||||
import DownloadOnAppStoreDark from "~/components/icons/DownloadOnAppStoreDark";
|
import DownloadOnAppStoreDark from "~/components/icons/DownloadOnAppStoreDark";
|
||||||
|
|
||||||
export default function LifeAndLineageMarketing() {
|
export default function LifeAndLineageMarketing() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Life and Lineage | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="A dark fantasy adventure mobile game. Download Life and Lineage on the App Store and Google Play."
|
||||||
|
/>
|
||||||
<SimpleParallax>
|
<SimpleParallax>
|
||||||
<div class="flex flex-col items-center justify-center h-full text-white">
|
<div class="flex h-full flex-col items-center justify-center text-white">
|
||||||
<div>
|
<div>
|
||||||
<img
|
<img
|
||||||
src="/LineageIcon.png"
|
src="/LineageIcon.png"
|
||||||
@@ -15,10 +22,8 @@ export default function LifeAndLineageMarketing() {
|
|||||||
class="object-cover object-center"
|
class="object-cover object-center"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-5xl font-bold mb-4 text-center">
|
<h1 class="mb-4 text-center text-5xl font-bold">Life and Lineage</h1>
|
||||||
Life and Lineage
|
<p class="mb-8 text-xl">A dark fantasy adventure</p>
|
||||||
</h1>
|
|
||||||
<p class="text-xl mb-8">A dark fantasy adventure</p>
|
|
||||||
<div class="flex space-x-4">
|
<div class="flex space-x-4">
|
||||||
<a
|
<a
|
||||||
class="my-auto transition-all duration-200 ease-out active:scale-95"
|
class="my-auto transition-all duration-200 ease-out active:scale-95"
|
||||||
@@ -42,5 +47,6 @@ export default function LifeAndLineageMarketing() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SimpleParallax>
|
</SimpleParallax>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { A } from "@solidjs/router";
|
import { A } from "@solidjs/router";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
|
|
||||||
export default function PrivacyPolicy() {
|
export default function PrivacyPolicy() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Privacy Policy - Life and Lineage | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Privacy policy for Life and Lineage mobile game, outlining data collection, usage, and user rights."
|
||||||
|
/>
|
||||||
<div class="min-h-screen px-[8vw] py-[10vh]">
|
<div class="min-h-screen px-[8vw] py-[10vh]">
|
||||||
<div class="py-4 text-xl">Life and Lineage's Privacy Policy</div>
|
<div class="py-4 text-xl">Life and Lineage's Privacy Policy</div>
|
||||||
<div class="py-2">Last Updated: October 22, 2024</div>
|
<div class="py-2">Last Updated: October 22, 2024</div>
|
||||||
@@ -18,13 +25,13 @@ export default function PrivacyPolicy() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="pl-4">
|
<div class="pl-4">
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
<div class="-ml-6">(a) Collection of Personal Data:</div> Life and
|
<div class="-ml-6">(a) Collection of Personal Data:</div> Life
|
||||||
Lineage collects and stores personal data only if users opt to use
|
and Lineage collects and stores personal data only if users opt
|
||||||
the remote saving feature. The information collected includes
|
to use the remote saving feature. The information collected
|
||||||
email address, and if using an OAuth provider - first name, and
|
includes email address, and if using an OAuth provider - first
|
||||||
last name. This information is used solely for the purpose of
|
name, and last name. This information is used solely for the
|
||||||
providing and managing the remote saving feature. It is and never
|
purpose of providing and managing the remote saving feature. It
|
||||||
will be shared with a third party.
|
is and never will be shared with a third party.
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
<div class="-ml-6">(b) Data Removal:</div> Users can request the
|
<div class="-ml-6">(b) Data Removal:</div> Users can request the
|
||||||
@@ -59,11 +66,11 @@ export default function PrivacyPolicy() {
|
|||||||
<span class="-ml-4 pr-2">3.</span> Security
|
<span class="-ml-4 pr-2">3.</span> Security
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-2 pl-4">
|
<div class="pb-2 pl-4">
|
||||||
<div class="-ml-6">(a) Data Protection:</div>Life and Lineage takes
|
<div class="-ml-6">(a) Data Protection:</div>Life and Lineage
|
||||||
appropriate measures to protect the personal information of users
|
takes appropriate measures to protect the personal information of
|
||||||
who opt for the remote saving feature. We implement
|
users who opt for the remote saving feature. We implement
|
||||||
industry-standard security protocols to prevent unauthorized access,
|
industry-standard security protocols to prevent unauthorized
|
||||||
disclosure, alteration, or destruction of user data.
|
access, disclosure, alteration, or destruction of user data.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -85,8 +92,8 @@ export default function PrivacyPolicy() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="pb-2 pl-4">
|
<div class="pb-2 pl-4">
|
||||||
<div class="-ml-6">(a) Reaching Out:</div> If there are any
|
<div class="-ml-6">(a) Reaching Out:</div> If there are any
|
||||||
questions or comments regarding this privacy policy, you can contact
|
questions or comments regarding this privacy policy, you can
|
||||||
us{" "}
|
contact us{" "}
|
||||||
<A href="/contact" class="text-blue hover-underline-animation">
|
<A href="/contact" class="text-blue hover-underline-animation">
|
||||||
here
|
here
|
||||||
</A>
|
</A>
|
||||||
@@ -95,5 +102,6 @@ export default function PrivacyPolicy() {
|
|||||||
</div>
|
</div>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { A } from "@solidjs/router";
|
import { A } from "@solidjs/router";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
|
|
||||||
export default function PrivacyPolicy() {
|
export default function PrivacyPolicy() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Privacy Policy - Shapes with Abigail | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Privacy policy for Shapes with Abigail app, explaining our commitment to child safety and non-collection of personal data."
|
||||||
|
/>
|
||||||
<div class="bg-zinc-100 dark:bg-zinc-900">
|
<div class="bg-zinc-100 dark:bg-zinc-900">
|
||||||
<div class="min-h-screen px-[8vw] py-[8vh]">
|
<div class="min-h-screen px-[8vw] py-[8vh]">
|
||||||
<div class="py-4 text-xl">
|
<div class="py-4 text-xl">
|
||||||
@@ -24,9 +31,7 @@ export default function PrivacyPolicy() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="pl-4">
|
<div class="pl-4">
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
<div class="-ml-6">
|
<div class="-ml-6">(a) Non-Collection of Personal Data:</div>{" "}
|
||||||
(a) Non-Collection of Personal Data:
|
|
||||||
</div>{" "}
|
|
||||||
Shapes with Abigail! does not collect nor store personal data.
|
Shapes with Abigail! does not collect nor store personal data.
|
||||||
We respect the privacy of our users, especially considering
|
We respect the privacy of our users, especially considering
|
||||||
the age of our users. We believe that no information, whether
|
the age of our users. We believe that no information, whether
|
||||||
@@ -41,10 +46,10 @@ export default function PrivacyPolicy() {
|
|||||||
<span class="-ml-4 pr-2">2.</span> Third-Party Access
|
<span class="-ml-4 pr-2">2.</span> Third-Party Access
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-2 pl-4">
|
<div class="pb-2 pl-4">
|
||||||
<div class="-ml-6">(a) No Third-Party Access:</div> Since we
|
<div class="-ml-6">(a) No Third-Party Access:</div> Since we do
|
||||||
do not collect or store any user data, there is no possibility
|
not collect or store any user data, there is no possibility of
|
||||||
of sharing or selling our users' information to third
|
sharing or selling our users' information to third parties.
|
||||||
parties. Our priority is the safety and privacy of our users.
|
Our priority is the safety and privacy of our users.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -63,14 +68,13 @@ export default function PrivacyPolicy() {
|
|||||||
|
|
||||||
<div class="py-2">
|
<div class="py-2">
|
||||||
<div class="pb-2 text-lg">
|
<div class="pb-2 text-lg">
|
||||||
<span class="-ml-4 pr-2">4.</span> Changes to the Privacy
|
<span class="-ml-4 pr-2">4.</span> Changes to the Privacy Policy
|
||||||
Policy
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-2 pl-4">
|
<div class="pb-2 pl-4">
|
||||||
<div class="-ml-6">(a) Updates:</div> We may update this
|
<div class="-ml-6">(a) Updates:</div> We may update this privacy
|
||||||
privacy policy periodically. Any changes to this privacy policy
|
policy periodically. Any changes to this privacy policy will be
|
||||||
will be posted on this page. However, since we do not collect
|
posted on this page. However, since we do not collect any
|
||||||
any personal data, these updates are likely to be insignificant.
|
personal data, these updates are likely to be insignificant.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -94,5 +98,6 @@ export default function PrivacyPolicy() {
|
|||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { Title } from "@solidjs/meta";
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
|
|
||||||
export default function Resume() {
|
export default function Resume() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Resume | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="View Michael Freno's resume - Software Engineer with expertise in full-stack development, game development, and open source."
|
||||||
|
/>
|
||||||
|
|
||||||
<main class="flex h-screen w-full flex-col">
|
<main class="flex h-screen w-full flex-col">
|
||||||
<Title>Resume - Freno.dev</Title>
|
<Title>Resume - Freno.dev</Title>
|
||||||
<div class="flex h-full w-full items-center justify-center">
|
<div class="flex h-full w-full items-center justify-center">
|
||||||
@@ -12,5 +19,6 @@ export default function Resume() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { createSignal } from "solid-js";
|
import { createSignal } from "solid-js";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import Input from "~/components/ui/Input";
|
import Input from "~/components/ui/Input";
|
||||||
import Button from "~/components/ui/Button";
|
import Button from "~/components/ui/Button";
|
||||||
import { isValidEmail, validatePassword, passwordsMatch } from "~/lib/validation";
|
import {
|
||||||
|
isValidEmail,
|
||||||
|
validatePassword,
|
||||||
|
passwordsMatch
|
||||||
|
} from "~/lib/validation";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test page to validate Task 01 components and utilities
|
* Test page to validate Task 01 components and utilities
|
||||||
@@ -36,24 +41,30 @@ export default function TestUtilsPage() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
// Simulate API call
|
// Simulate API call
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
alert(`Form submitted!\nEmail: ${email()}\nPassword: ${password()}`);
|
alert(`Form submitted!\nEmail: ${email()}\nPassword: ${password()}`);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>Utility Testing | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="Testing page for form components and validation utilities."
|
||||||
|
/>
|
||||||
<main class="min-h-screen bg-gray-100 p-8">
|
<main class="min-h-screen bg-gray-100 p-8">
|
||||||
<div class="max-w-2xl mx-auto">
|
<div class="mx-auto max-w-2xl">
|
||||||
<div class="bg-white rounded-lg shadow-lg p-6 mb-6">
|
<div class="mb-6 rounded-lg bg-white p-6 shadow-lg">
|
||||||
<h1 class="text-3xl font-bold mb-2">Task 01 - Utility Testing</h1>
|
<h1 class="mb-2 text-3xl font-bold">Task 01 - Utility Testing</h1>
|
||||||
<p class="text-gray-600 mb-4">
|
<p class="mb-4 text-gray-600">
|
||||||
Testing shared utilities, types, and UI components
|
Testing shared utilities, types, and UI components
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow p-6 mb-6">
|
<div class="mb-6 rounded-lg bg-white p-6 shadow">
|
||||||
<h2 class="text-xl font-bold mb-4">Form Components & Validation</h2>
|
<h2 class="mb-4 text-xl font-bold">Form Components & Validation</h2>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} class="space-y-4">
|
<form onSubmit={handleSubmit} class="space-y-4">
|
||||||
<Input
|
<Input
|
||||||
@@ -130,30 +141,42 @@ export default function TestUtilsPage() {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow p-6">
|
<div class="rounded-lg bg-white p-6 shadow">
|
||||||
<h2 class="text-xl font-bold mb-4">Validation Status</h2>
|
<h2 class="mb-4 text-xl font-bold">Validation Status</h2>
|
||||||
|
|
||||||
<div class="space-y-2 text-sm">
|
<div class="space-y-2 text-sm">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class={`w-3 h-3 rounded-full ${isValidEmail(email()) ? "bg-green-500" : "bg-gray-300"}`} />
|
<span
|
||||||
|
class={`h-3 w-3 rounded-full ${isValidEmail(email()) ? "bg-green-500" : "bg-gray-300"}`}
|
||||||
|
/>
|
||||||
<span>Email Valid: {isValidEmail(email()) ? "✓" : "✗"}</span>
|
<span>Email Valid: {isValidEmail(email()) ? "✓" : "✗"}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class={`w-3 h-3 rounded-full ${validatePassword(password()).isValid ? "bg-green-500" : "bg-gray-300"}`} />
|
<span
|
||||||
<span>Password Valid: {validatePassword(password()).isValid ? "✓" : "✗"}</span>
|
class={`h-3 w-3 rounded-full ${validatePassword(password()).isValid ? "bg-green-500" : "bg-gray-300"}`}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
Password Valid:{" "}
|
||||||
|
{validatePassword(password()).isValid ? "✓" : "✗"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class={`w-3 h-3 rounded-full ${passwordsMatch(password(), passwordConf()) ? "bg-green-500" : "bg-gray-300"}`} />
|
<span
|
||||||
<span>Passwords Match: {passwordsMatch(password(), passwordConf()) ? "✓" : "✗"}</span>
|
class={`h-3 w-3 rounded-full ${passwordsMatch(password(), passwordConf()) ? "bg-green-500" : "bg-gray-300"}`}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
Passwords Match:{" "}
|
||||||
|
{passwordsMatch(password(), passwordConf()) ? "✓" : "✗"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-blue-50 border border-blue-200 rounded p-4 mt-6">
|
<div class="mt-6 rounded border border-blue-200 bg-blue-50 p-4">
|
||||||
<h3 class="font-bold text-blue-800 mb-2">✅ Task 01 Complete</h3>
|
<h3 class="mb-2 font-bold text-blue-800">✅ Task 01 Complete</h3>
|
||||||
<ul class="text-sm text-blue-700 space-y-1">
|
<ul class="space-y-1 text-sm text-blue-700">
|
||||||
<li>✓ User types created</li>
|
<li>✓ User types created</li>
|
||||||
<li>✓ Cookie utilities created</li>
|
<li>✓ Cookie utilities created</li>
|
||||||
<li>✓ Validation helpers created</li>
|
<li>✓ Validation helpers created</li>
|
||||||
@@ -165,5 +188,6 @@ export default function TestUtilsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createSignal, For, Show } from "solid-js";
|
import { createSignal, For, Show } from "solid-js";
|
||||||
import { query, createAsync } from "@solidjs/router";
|
import { query, createAsync } from "@solidjs/router";
|
||||||
|
import { Title, Meta } from "@solidjs/meta";
|
||||||
import { getRequestEvent } from "solid-js/web";
|
import { getRequestEvent } from "solid-js/web";
|
||||||
import { api } from "~/lib/api";
|
import { api } from "~/lib/api";
|
||||||
|
|
||||||
@@ -932,6 +933,12 @@ export default function TestPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Title>API Testing | Michael Freno</Title>
|
||||||
|
<Meta
|
||||||
|
name="description"
|
||||||
|
content="tRPC API testing dashboard for developers to test endpoints and verify functionality."
|
||||||
|
/>
|
||||||
<Show
|
<Show
|
||||||
when={authState()?.privilegeLevel === "admin"}
|
when={authState()?.privilegeLevel === "admin"}
|
||||||
fallback={
|
fallback={
|
||||||
@@ -946,7 +953,9 @@ export default function TestPage() {
|
|||||||
<main class="min-h-screen p-8">
|
<main class="min-h-screen p-8">
|
||||||
<div class="mx-auto max-w-6xl">
|
<div class="mx-auto max-w-6xl">
|
||||||
<div class="bg-surface0 mb-6 rounded-lg p-6 shadow-lg">
|
<div class="bg-surface0 mb-6 rounded-lg p-6 shadow-lg">
|
||||||
<h1 class="mb-2 text-3xl font-bold">tRPC API Testing Dashboard</h1>
|
<h1 class="mb-2 text-3xl font-bold">
|
||||||
|
tRPC API Testing Dashboard
|
||||||
|
</h1>
|
||||||
<p class="text-text mb-4">
|
<p class="text-text mb-4">
|
||||||
Complete API coverage: Example, Auth, Database, User, Misc, and
|
Complete API coverage: Example, Auth, Database, User, Misc, and
|
||||||
Lineage routers
|
Lineage routers
|
||||||
@@ -994,7 +1003,8 @@ export default function TestPage() {
|
|||||||
<For each={section.endpoints}>
|
<For each={section.endpoints}>
|
||||||
{(endpoint) => {
|
{(endpoint) => {
|
||||||
const key = `${endpoint.router}.${endpoint.procedure}`;
|
const key = `${endpoint.router}.${endpoint.procedure}`;
|
||||||
const hasInput = endpoint.sampleInput !== undefined;
|
const hasInput =
|
||||||
|
endpoint.sampleInput !== undefined;
|
||||||
const displayInput = () => {
|
const displayInput = () => {
|
||||||
if (inputEdits()[key]) {
|
if (inputEdits()[key]) {
|
||||||
return inputEdits()[key];
|
return inputEdits()[key];
|
||||||
@@ -1069,7 +1079,10 @@ export default function TestPage() {
|
|||||||
<textarea
|
<textarea
|
||||||
value={displayInput()}
|
value={displayInput()}
|
||||||
onInput={(e) =>
|
onInput={(e) =>
|
||||||
updateInput(key, e.currentTarget.value)
|
updateInput(
|
||||||
|
key,
|
||||||
|
e.currentTarget.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
class="border-lavender bg-crust min-h-[100px] w-full rounded border p-2 font-mono text-xs"
|
class="border-lavender bg-crust min-h-[100px] w-full rounded border p-2 font-mono text-xs"
|
||||||
spellcheck={false}
|
spellcheck={false}
|
||||||
@@ -1096,7 +1109,11 @@ export default function TestPage() {
|
|||||||
✓ Response:
|
✓ Response:
|
||||||
</p>
|
</p>
|
||||||
<pre class="max-h-60 overflow-auto text-xs text-green-400">
|
<pre class="max-h-60 overflow-auto text-xs text-green-400">
|
||||||
{JSON.stringify(results()[key], null, 2)}
|
{JSON.stringify(
|
||||||
|
results()[key],
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
@@ -1118,18 +1135,20 @@ export default function TestPage() {
|
|||||||
|
|
||||||
<div class="space-y-4 text-base">
|
<div class="space-y-4 text-base">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="mb-2 text-lg font-semibold">🟢 No Auth Required</h3>
|
<h3 class="mb-2 text-lg font-semibold">
|
||||||
|
🟢 No Auth Required
|
||||||
|
</h3>
|
||||||
<ul class="ml-6 list-disc space-y-1 text-sm">
|
<ul class="ml-6 list-disc space-y-1 text-sm">
|
||||||
<li>
|
<li>
|
||||||
<strong>Example Router</strong> - Hello endpoint
|
<strong>Example Router</strong> - Hello endpoint
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Lineage JSON Service</strong> - All 6 endpoints work
|
<strong>Lineage JSON Service</strong> - All 6 endpoints
|
||||||
immediately
|
work immediately
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Database</strong> - All endpoints (comments, posts,
|
<strong>Database</strong> - All endpoints (comments,
|
||||||
users, reactions, likes)
|
posts, users, reactions, likes)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Misc</strong> - Downloads, S3 operations, password
|
<strong>Misc</strong> - Downloads, S3 operations, password
|
||||||
@@ -1179,30 +1198,32 @@ export default function TestPage() {
|
|||||||
<strong>Example Router</strong> - Admin Dashboard
|
<strong>Example Router</strong> - Admin Dashboard
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Lineage Maintenance</strong> - Find Loose Databases,
|
<strong>Lineage Maintenance</strong> - Find Loose
|
||||||
Cleanup Expired
|
Databases, Cleanup Expired
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="mb-2 text-lg font-semibold">📝 Typical Workflows</h3>
|
<h3 class="mb-2 text-lg font-semibold">
|
||||||
|
📝 Typical Workflows
|
||||||
|
</h3>
|
||||||
<ol class="ml-6 list-decimal space-y-2 text-sm">
|
<ol class="ml-6 list-decimal space-y-2 text-sm">
|
||||||
<li>
|
<li>
|
||||||
<strong>Test public endpoints:</strong> Start with Example
|
<strong>Test public endpoints:</strong> Start with Example
|
||||||
Hello, Lineage JSON Service, or Database queries
|
Hello, Lineage JSON Service, or Database queries
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>OAuth flow:</strong> Use Auth router callbacks with
|
<strong>OAuth flow:</strong> Use Auth router callbacks
|
||||||
OAuth codes from GitHub/Google
|
with OAuth codes from GitHub/Google
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Email auth flow:</strong> Register → verify email →
|
<strong>Email auth flow:</strong> Register → verify email
|
||||||
login → use JWT
|
→ login → use JWT
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Blog/Project management:</strong> Create posts → add
|
<strong>Blog/Project management:</strong> Create posts →
|
||||||
comments/likes → upload images via S3
|
add comments/likes → upload images via S3
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>Lineage game data:</strong> Fetch JSON data →
|
<strong>Lineage game data:</strong> Fetch JSON data →
|
||||||
@@ -1214,9 +1235,9 @@ export default function TestPage() {
|
|||||||
<div class="border-rosewater bg-rosewater mt-4 rounded border p-4">
|
<div class="border-rosewater bg-rosewater mt-4 rounded border p-4">
|
||||||
<p class="text-crust text-sm">
|
<p class="text-crust text-sm">
|
||||||
<strong>Note:</strong> Some endpoints require specific setup
|
<strong>Note:</strong> Some endpoints require specific setup
|
||||||
(e.g., OAuth codes, existing database records, valid S3 keys).
|
(e.g., OAuth codes, existing database records, valid S3
|
||||||
Check the sample input to understand what data each endpoint
|
keys). Check the sample input to understand what data each
|
||||||
expects.
|
endpoint expects.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1224,5 +1245,6 @@ export default function TestPage() {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</Show>
|
</Show>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user