aboutsummaryrefslogtreecommitdiff
path: root/apps/web/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/lib')
-rw-r--r--apps/web/lib/constants.ts43
-rw-r--r--apps/web/lib/get-metadata.ts40
-rw-r--r--apps/web/lib/get-theme-button.tsx11
-rw-r--r--apps/web/lib/handle-errors.ts25
-rw-r--r--apps/web/lib/searchParams.ts26
5 files changed, 145 insertions, 0 deletions
diff --git a/apps/web/lib/constants.ts b/apps/web/lib/constants.ts
new file mode 100644
index 00000000..7a9485cf
--- /dev/null
+++ b/apps/web/lib/constants.ts
@@ -0,0 +1,43 @@
+export const LIMITS = {
+ page: 100,
+ tweet: 1000,
+ note: 1000,
+};
+
+export const codeLanguageSubset = [
+ "python",
+ "javascript",
+ "java",
+ "go",
+ "bash",
+ "c",
+ "cpp",
+ "csharp",
+ "css",
+ "diff",
+ "graphql",
+ "json",
+ "kotlin",
+ "less",
+ "lua",
+ "makefile",
+ "markdown",
+ "objectivec",
+ "perl",
+ "php",
+ "php-template",
+ "plaintext",
+ "python-repl",
+ "r",
+ "ruby",
+ "rust",
+ "scss",
+ "shell",
+ "sql",
+ "swift",
+ "typescript",
+ "vbnet",
+ "wasm",
+ "xml",
+ "yaml",
+];
diff --git a/apps/web/lib/get-metadata.ts b/apps/web/lib/get-metadata.ts
new file mode 100644
index 00000000..4609e49b
--- /dev/null
+++ b/apps/web/lib/get-metadata.ts
@@ -0,0 +1,40 @@
+"use server";
+import * as cheerio from "cheerio";
+
+// TODO: THIS SHOULD PROBABLY ALSO FETCH THE OG-IMAGE
+export async function getMetaData(url: string) {
+ const response = await fetch(url);
+ const html = await response.text();
+
+ const $ = cheerio.load(html);
+
+ // Extract the base URL
+ const baseUrl = new URL(url).origin;
+
+ // Extract title
+ const title = $("title").text().trim();
+
+ const description = $("meta[name=description]").attr("content") ?? "";
+
+ const _favicon =
+ $("link[rel=icon]").attr("href") ?? "https://supermemory.dhr.wtf/web.svg";
+
+ let favicon =
+ _favicon.trim().length > 0
+ ? _favicon.trim()
+ : "https://supermemory.dhr.wtf/web.svg";
+ if (favicon.startsWith("/")) {
+ favicon = baseUrl + favicon;
+ } else if (favicon.startsWith("./")) {
+ favicon = baseUrl + favicon.slice(1);
+ }
+
+ // Prepare the metadata object
+ const metadata = {
+ title,
+ description,
+ image: favicon,
+ baseUrl,
+ };
+ return metadata;
+}
diff --git a/apps/web/lib/get-theme-button.tsx b/apps/web/lib/get-theme-button.tsx
new file mode 100644
index 00000000..020cc976
--- /dev/null
+++ b/apps/web/lib/get-theme-button.tsx
@@ -0,0 +1,11 @@
+// Theming that works perfectly with app router (no flicker, jumps etc!)
+
+import dynamic from "next/dynamic";
+
+// Don't SSR the toggle since the value on the server will be different than the client
+export const getThemeToggler = () =>
+ dynamic(() => import("@repo/ui/shadcn/theme-toggle"), {
+ ssr: false,
+ // Make sure to code a placeholder so the UI doesn't jump when the component loads
+ loading: () => <div className="w-6 h-6" />,
+ });
diff --git a/apps/web/lib/handle-errors.ts b/apps/web/lib/handle-errors.ts
new file mode 100644
index 00000000..42cae589
--- /dev/null
+++ b/apps/web/lib/handle-errors.ts
@@ -0,0 +1,25 @@
+import { isRedirectError } from "next/dist/client/components/redirect";
+import { toast } from "sonner";
+import { z } from "zod";
+
+export function getErrorMessage(err: unknown) {
+ const unknownError = "Something went wrong, please try again later.";
+
+ if (err instanceof z.ZodError) {
+ const errors = err.issues.map((issue) => {
+ return issue.message;
+ });
+ return errors.join("\n");
+ } else if (err instanceof Error) {
+ return err.message;
+ } else if (isRedirectError(err)) {
+ throw err;
+ } else {
+ return unknownError;
+ }
+}
+
+export function showErrorToast(err: unknown) {
+ const errorMessage = getErrorMessage(err);
+ return toast.error(errorMessage);
+}
diff --git a/apps/web/lib/searchParams.ts b/apps/web/lib/searchParams.ts
new file mode 100644
index 00000000..9899eaf7
--- /dev/null
+++ b/apps/web/lib/searchParams.ts
@@ -0,0 +1,26 @@
+import {
+ createSearchParamsCache,
+ parseAsInteger,
+ parseAsString,
+ parseAsBoolean,
+ parseAsArrayOf,
+ parseAsJson,
+} from "nuqs/server";
+import { z } from "zod";
+
+export const homeSearchParamsCache = createSearchParamsCache({
+ firstTime: parseAsBoolean.withDefault(false),
+});
+
+export const chatSearchParamsCache = createSearchParamsCache({
+ firstTime: parseAsBoolean.withDefault(false),
+ q: parseAsString.withDefault(""),
+ spaces: parseAsArrayOf(
+ parseAsJson(() =>
+ z.object({
+ id: z.string(),
+ name: z.string(),
+ }),
+ ),
+ ).withDefault([]),
+});