diff --git a/fresh.gen.ts b/fresh.gen.ts
index cfe976b..e628f9e 100644
--- a/fresh.gen.ts
+++ b/fresh.gen.ts
@@ -7,11 +7,14 @@ import * as $_app from "./routes/_app.tsx";
import * as $api_create from "./routes/api/create.ts";
import * as $api_res_tailwind_css from "./routes/api/res/tailwind.css.ts";
import * as $api_secret_uuid_ from "./routes/api/secret/[uuid].ts";
+import * as $create from "./routes/create.tsx";
import * as $index from "./routes/index.tsx";
import * as $secret_uuid_ from "./routes/secret/[uuid].tsx";
import * as $CreateSecret from "./islands/CreateSecret.tsx";
import * as $FetchSecret from "./islands/FetchSecret.tsx";
import * as $Log from "./islands/Log.tsx";
+import * as $messages_CardMsg from "./islands/messages/CardMsg.tsx";
+import * as $messages_ErrorCardMsg from "./islands/messages/ErrorCardMsg.tsx";
import type { Manifest } from "$fresh/server.ts";
const manifest = {
@@ -21,6 +24,7 @@ const manifest = {
"./routes/api/create.ts": $api_create,
"./routes/api/res/tailwind.css.ts": $api_res_tailwind_css,
"./routes/api/secret/[uuid].ts": $api_secret_uuid_,
+ "./routes/create.tsx": $create,
"./routes/index.tsx": $index,
"./routes/secret/[uuid].tsx": $secret_uuid_,
},
@@ -28,6 +32,8 @@ const manifest = {
"./islands/CreateSecret.tsx": $CreateSecret,
"./islands/FetchSecret.tsx": $FetchSecret,
"./islands/Log.tsx": $Log,
+ "./islands/messages/CardMsg.tsx": $messages_CardMsg,
+ "./islands/messages/ErrorCardMsg.tsx": $messages_ErrorCardMsg,
},
baseUrl: import.meta.url,
} satisfies Manifest;
diff --git a/islands/CreateSecret.tsx b/islands/CreateSecret.tsx
index c33919e..3dc602c 100644
--- a/islands/CreateSecret.tsx
+++ b/islands/CreateSecret.tsx
@@ -20,8 +20,7 @@ export default function CreateSecret() {
name="hidden"
type="text"
style="display:none;"
- >
-
+ />
-
-
-
-
+
+
+
+
);
diff --git a/islands/FetchSecret.tsx b/islands/FetchSecret.tsx
index b4845c8..8a40ab1 100644
--- a/islands/FetchSecret.tsx
+++ b/islands/FetchSecret.tsx
@@ -38,6 +38,7 @@ export default function FetchSecret(
name="fetchSecretButton"
type="submit"
disabled={fetched.value}
+ class="p-2"
>
Abrufen
diff --git a/islands/Log.tsx b/islands/Log.tsx
index 5129c41..4603ecb 100644
--- a/islands/Log.tsx
+++ b/islands/Log.tsx
@@ -1,35 +1,48 @@
-import { lastMessage } from "../src/utils/log.ts";
+import { lastMessage, RichMessage } from "../src/utils/log.ts";
+import CardMsg from "./messages/CardMsg.tsx";
+import ErrorCardMsg from "./messages/ErrorCardMsg.tsx";
+
+function renderMessage(message: RichMessage | undefined) {
+ if (!message) {
+ return undefined;
+ }
+
+ switch (message.type) {
+ case "string":
+ return (
+
+ {message.text}
+
+ );
+ case "error":
+ return (
+
+ {message.text}
+
+ );
+ case "secretFetch":
+ return (
+
+
+ {message.secret}
+
+
+ );
+ case "secretCreate":
+ return (
+
+
+ {message.secretLink}
+
+
+ );
+ }
+}
export default function Log() {
- return (
- // TODO: enable when tailwind integration is working
- //
-
- 0
- ? "block"
- : "none",
- }}
- >
- {lastMessage}
-
-
- );
+ return
{renderMessage(lastMessage.value)}
;
}
diff --git a/islands/messages/CardMsg.tsx b/islands/messages/CardMsg.tsx
new file mode 100644
index 0000000..538b3fb
--- /dev/null
+++ b/islands/messages/CardMsg.tsx
@@ -0,0 +1,17 @@
+import { JSX } from "preact/jsx-runtime";
+
+export default function CardMsg(
+ props: {
+ header?: string;
+ extraInfo?: string;
+ children: JSX.Element | undefined;
+ },
+) {
+ return (
+
+ {props.header &&
{props.header}
}
+ {props.children}
+ {props.extraInfo &&
{props.extraInfo}
}
+
+ );
+}
diff --git a/islands/messages/ErrorCardMsg.tsx b/islands/messages/ErrorCardMsg.tsx
new file mode 100644
index 0000000..429bce6
--- /dev/null
+++ b/islands/messages/ErrorCardMsg.tsx
@@ -0,0 +1,19 @@
+import { JSX } from "preact/jsx-runtime";
+
+export default function CardMsg(
+ props: {
+ header?: string;
+ extraInfo?: string;
+ children: JSX.Element | undefined;
+ },
+) {
+ return (
+
+ {props.header && (
+
{props.header}
+ )}
+ {props.children}
+ {props.extraInfo &&
{props.extraInfo}
}
+
+ );
+}
diff --git a/routes/create.tsx b/routes/create.tsx
new file mode 100644
index 0000000..ff8b3d5
--- /dev/null
+++ b/routes/create.tsx
@@ -0,0 +1,11 @@
+import CreateSecret from "../islands/CreateSecret.tsx";
+import Log from "../islands/Log.tsx";
+
+export default function CreateSecretPage() {
+ return (
+
+
+
+
+ );
+}
diff --git a/routes/index.tsx b/routes/index.tsx
index 37c0b79..3f76c5e 100644
--- a/routes/index.tsx
+++ b/routes/index.tsx
@@ -1,11 +1,9 @@
-import CreateSecret from "../islands/CreateSecret.tsx";
-import Log from "../islands/Log.tsx";
+import { redirectTo } from "../utils/routing.ts";
-export default function Home() {
- return (
-
-
-
-
- );
+/**
+ * @bjesuiter: "async" is required here, otherwise the redirectTo will not work for some reason
+ * (async pages are handled slightly differently in fresh than sync pages)
+ */
+export default async function Home() {
+ return redirectTo("/create");
}
diff --git a/src/formHandler/create.ts b/src/formHandler/create.ts
index 610a930..da1b388 100644
--- a/src/formHandler/create.ts
+++ b/src/formHandler/create.ts
@@ -10,7 +10,10 @@ export default async function onSubmit(
const secret = formData.get("secret") as string;
if (!secret || secret.length < 1) {
- lastMessage.value = "Bitte geben Sie ein Secret ein!";
+ lastMessage.value = {
+ type: "string",
+ text: "Bitte geben Sie ein Secret ein!",
+ };
return;
}
@@ -32,7 +35,10 @@ export default async function onSubmit(
if (formData.get("usePassphrase") == "on") {
if (!encryptionKey) {
- lastMessage.value = "Bitte geben Sie ein Passphrase ein!";
+ lastMessage.value = {
+ type: "string",
+ text: "Bitte geben Sie ein Passphrase ein!",
+ };
return;
}
} else {
@@ -50,7 +56,10 @@ export default async function onSubmit(
secret,
);
if (encryptedData == undefined) {
- lastMessage.value = "Fehler beim Verschlüsseln des Secrets!";
+ lastMessage.value = {
+ type: "string",
+ text: "Fehler beim Verschlüsseln des Secrets!",
+ };
return;
}
encryptedSecret = encryptedData.encryptedSecret;
@@ -72,7 +81,10 @@ export default async function onSubmit(
body: JSON.stringify({ encryptedSecret, expireIn, hash, allowedViews, iv }),
});
const data = await response.json().catch(() =>
- lastMessage.value = "Fehler beim Erstellen des Secrets!"
+ lastMessage.value = {
+ type: "string",
+ text: "Fehler beim Erstellen des Secrets!",
+ }
);
if (data && data.link) {
const secretUrl = `${location.origin}/secret/${data.link}${
@@ -80,7 +92,11 @@ export default async function onSubmit(
}`;
// copy url to clipboard
navigator.clipboard.writeText(secretUrl);
- lastMessage.value =
- `Link erstellt: \n${secretUrl} \nLink wurde in die Zwischenablage kopiert!`;
+ lastMessage.value = {
+ type: "secretCreate",
+ secretLink: secretUrl,
+ header: `Link erstellt`,
+ extraInfo: `Link wurde in die Zwischenablage kopiert!`,
+ };
}
}
diff --git a/src/formHandler/fetch.ts b/src/formHandler/fetch.ts
index 6550857..7206104 100644
--- a/src/formHandler/fetch.ts
+++ b/src/formHandler/fetch.ts
@@ -16,20 +16,29 @@ export default async function onSubmit(
});
if (response.status >= 400) {
- lastMessage.value =
- "Fehler beim Abrufen des Secrets! Entweder ist der Link abgelaufen oder ungültig.";
+ lastMessage.value = {
+ type: "error",
+ text:
+ "Fehler beim Abrufen des Secrets! Entweder ist der Link abgelaufen oder ungültig.",
+ };
return;
}
const data = await response.json().catch(() =>
- lastMessage.value =
- "Fehler beim Abrufen des Secrets! Entweder ist der Link abgelaufen oder ungültig."
+ lastMessage.value = {
+ type: "error",
+ text:
+ "Fehler beim Abrufen des Secrets! Entweder ist der Link abgelaufen oder ungültig.",
+ }
);
// turn json object iv into Uint8Array
data.iv = new Uint8Array(Object.values(data.iv));
if (data == undefined || data.secret == undefined) {
- lastMessage.value =
- "Fehler beim Abrufen des Secrets! Entweder ist der Link abgelaufen oder ungültig.";
+ lastMessage.value = {
+ type: "error",
+ text:
+ "Fehler beim Abrufen des Secrets! Entweder ist der Link abgelaufen oder ungültig.",
+ };
return;
}
@@ -56,9 +65,16 @@ export default async function onSubmit(
if (hash !== data.hash) {
console.log(`${hash} !== ${data.hash}`);
- lastMessage.value =
- `Verifikation des Secrets fehlgeschlagen. Falsche Passphrase. Verbleibende versuche: ${data.viewsLeft}`;
+ lastMessage.value = {
+ type: "error",
+ text:
+ `Verifikation des Secrets fehlgeschlagen. Falsche Passphrase. Verbleibende versuche: ${data.viewsLeft}`,
+ };
return;
}
- lastMessage.value = `Secret Data: \n${data.secret}`;
+
+ lastMessage.value = {
+ type: "secretFetch",
+ secret: data.secret,
+ };
}
diff --git a/src/utils/crypt.ts b/src/utils/crypt.ts
index 4e84864..aef030c 100644
--- a/src/utils/crypt.ts
+++ b/src/utils/crypt.ts
@@ -7,7 +7,10 @@ export async function encrypt(key: string, secret: string) {
),
);
if (!key || key.length < 1) {
- lastMessage.value = "Bitte geben Sie ein Passphrase ein!";
+ lastMessage.value = {
+ type: "string",
+ text: "Bitte geben Sie eine Passphrase ein!",
+ };
return;
}
const iv = crypto.getRandomValues(new Uint8Array(12));
@@ -38,7 +41,10 @@ export async function decrypt(
key: string,
) {
if (!key || key.length < 1) {
- lastMessage.value = "Bitte geben Sie ein Passphrase ein!";
+ lastMessage.value = {
+ type: "string",
+ text: "Bitte geben Sie eine Passphrase ein!",
+ };
return;
}
@@ -58,7 +64,10 @@ export async function decrypt(
["decrypt"],
).catch((e) => {
console.error(e);
- lastMessage.value = "Fehler beim Entschlüsseln des Secrets!";
+ lastMessage.value = {
+ type: "string",
+ text: "Fehler beim Entschlüsseln des Secrets!",
+ };
return;
});
@@ -82,7 +91,10 @@ export async function decrypt(
secret,
).catch((e: Error) => {
console.error(e);
- lastMessage.value = "Fehler beim Entschlüsseln des Secrets!";
+ lastMessage.value = {
+ type: "string",
+ text: "Fehler beim Entschlüsseln des Secrets!",
+ };
return;
});
diff --git a/src/utils/cssCache.ts b/src/utils/cssCache.ts
index 8e222f3..afc87e5 100644
--- a/src/utils/cssCache.ts
+++ b/src/utils/cssCache.ts
@@ -19,7 +19,9 @@ export async function computeTailwindStyles() {
@import "tailwindcss";
@theme {
- --color-primary: #60c0ff;
+ --color-primary: oklch(0.7751 0.127965 240.0314);
+ --color-primary-dark: oklch(0.5327 0.1152 242.02);
+
}
`;
diff --git a/src/utils/log.ts b/src/utils/log.ts
index e4e31f2..c5b210f 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -1,3 +1,23 @@
import { signal } from "@preact/signals";
-export const lastMessage = signal("");
+export type RichMessage =
+ | {
+ type: "string";
+ text: string;
+ }
+ | {
+ type: "error";
+ text: string;
+ }
+ | {
+ type: "secretFetch";
+ secret: string;
+ }
+ | {
+ type: "secretCreate";
+ secretLink: string;
+ header?: string;
+ extraInfo?: string;
+ };
+
+export const lastMessage = signal(undefined);
diff --git a/static/styles.css b/static/styles.css
index 548c254..c6a4ad6 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -46,12 +46,6 @@ video {
height: auto;
}
-a, a:visited {
- color: black;
- text-decoration: none;
- transition: color 0.15s ease;
-}
-
html {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
diff --git a/utils/routing.ts b/utils/routing.ts
new file mode 100644
index 0000000..20c4339
--- /dev/null
+++ b/utils/routing.ts
@@ -0,0 +1,15 @@
+/**
+ * Usage from a route handler:
+ *
+ * ```ts
+ * return redirectTo("/login");
+ * ```
+ */
+export function redirectTo(relativePath: string) {
+ const headers = new Headers();
+ headers.set("location", relativePath);
+ return new Response(null, {
+ status: 303,
+ headers,
+ });
+}