From 593bb2556abe16132e2db70474d859de24d525eb Mon Sep 17 00:00:00 2001 From: Shreyans Jain Date: Thu, 4 Sep 2025 16:50:55 -0700 Subject: more stuff --- apps/web/app/ref/[code]/page.tsx | 117 ++++++++++++++++++++++++++++++++------- apps/web/app/ref/page.tsx | 113 ++++++++++++++++++++++++------------- apps/web/middleware.ts | 2 +- apps/web/next.config.ts | 68 +++++++++++------------ bun.lock | 3 + package.json | 1 + packages/ui/text/heading.tsx | 63 +++++++++++++++++++++ packages/ui/text/label.tsx | 68 +++++++++++++++++++++++ packages/ui/text/title.tsx | 65 ++++++++++++++++++++++ 9 files changed, 407 insertions(+), 93 deletions(-) create mode 100644 packages/ui/text/heading.tsx create mode 100644 packages/ui/text/label.tsx create mode 100644 packages/ui/text/title.tsx diff --git a/apps/web/app/ref/[code]/page.tsx b/apps/web/app/ref/[code]/page.tsx index 8d7bc6fe..9d3b9b87 100644 --- a/apps/web/app/ref/[code]/page.tsx +++ b/apps/web/app/ref/[code]/page.tsx @@ -11,13 +11,20 @@ import { CardTitle, } from "@ui/components/card" import { Avatar, AvatarFallback, AvatarImage } from "@ui/components/avatar" -import { ShareIcon, LoaderIcon } from "lucide-react" +import { ShareIcon, LoaderIcon, ArrowRightIcon } from "lucide-react" import Link from "next/link" -import { useParams } from "next/navigation" +import { useParams, useRouter } from "next/navigation" +import { labelVariants } from "@ui/text/label" +import { cn } from "@lib/utils" +import { headingVariants } from "@ui/text/heading" +import { titleVariants } from "@ui/text/title" +import { useSession } from "@lib/auth" export default function ReferralInvitePage() { const params = useParams() const code = params.code as string + const router = useRouter() + const session = useSession() const { data: referrerData, @@ -48,6 +55,10 @@ export default function ReferralInvitePage() { retry: 1, }) + if (session.data) { + router.push("/") + } + const referrer = referrerData?.referrer if (isLoading) { @@ -55,7 +66,13 @@ export default function ReferralInvitePage() {
-

Loading invitation...

+

+ Loading invitation... +

) @@ -64,15 +81,22 @@ export default function ReferralInvitePage() { if (error || !code) { return (
- +
- + Invalid Referral Link - + {error instanceof Error ? error.message : "Invalid referral code"}
@@ -80,10 +104,17 @@ export default function ReferralInvitePage() {
- Learn more about supermemory + Learn more
@@ -95,7 +126,7 @@ export default function ReferralInvitePage() { return (
- +
@@ -105,10 +136,17 @@ export default function ReferralInvitePage() {
- + You've been invited! - + {referrer?.name} {" "} @@ -117,29 +155,66 @@ export default function ReferralInvitePage() {
-
-

+
+ You and {referrer?.name} both get a free month of{" "} + supermemory pro +
+
+

What is supermemory?

-

+

supermemory is an AI-powered personal knowledge base that helps you store, organize, and interact with all your digital memories.

- - - +
- Learn more about supermemory + Learn more

diff --git a/apps/web/app/ref/page.tsx b/apps/web/app/ref/page.tsx index 78373693..ed10d0aa 100644 --- a/apps/web/app/ref/page.tsx +++ b/apps/web/app/ref/page.tsx @@ -1,56 +1,95 @@ -"use client"; +"use client" -import { Button } from "@ui/components/button"; +import { Button } from "@ui/components/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from "@ui/components/card"; -import { ShareIcon } from "lucide-react"; -import Link from "next/link"; +} from "@ui/components/card" +import { ArrowRightIcon, HeartIcon, ShareIcon } from "lucide-react" +import Link from "next/link" +import { labelVariants } from "@ui/text/label" +import { cn } from "@lib/utils" +import { headingVariants } from "@ui/text/heading" +import { titleVariants } from "@ui/text/title" export default function ReferralHomePage() { return (
- - -
- + + +
+ +
+
+ + Missing Referral Code? + + + It looks like you're missing a referral code. Get one from a + friend or join directly! +
- - Missing Referral Code - - - It looks like you're missing a referral code. Get one from a friend - or join directly! -
- -
-
-

- What is supermemory? -

-

- supermemory is an AI-powered personal knowledge base that helps - you store, organize, and interact with all your digital - memories. -

-
+ +
+

+ What is supermemory? +

+

+ supermemory is an AI-powered personal knowledge base that helps + you store, organize, and interact with all your digital memories. +

+
+ + -
- - Learn more about supermemory - -
+
+ + Learn more +
- ); + ) } diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index 9862462d..59a3e856 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -47,6 +47,6 @@ export default async function middleware(request: Request) { export const config = { matcher: [ - "/((?!_next/static|_next/image|images|icon.png|monitoring|opengraph-image.png|ingest|api|login|api/emails).*)", + "/((?!_next/static|_next/image|images|icon.png|monitoring|opengraph-image.png|ingest|api|login|api/emails|ref).*)", ], } diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index a6ee01f3..5b9db494 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -1,63 +1,63 @@ -import { withSentryConfig } from "@sentry/nextjs"; -import type { NextConfig } from "next"; +import { withSentryConfig } from "@sentry/nextjs" +import type { NextConfig } from "next" const nextConfig: NextConfig = { - experimental: { - reactCompiler: true, - viewTransition: true, - }, - eslint: { - ignoreDuringBuilds: true, - }, - poweredByHeader: false, - async rewrites() { - return [ - { - source: "/ingest/static/:path*", - destination: "https://us-assets.i.posthog.com/static/:path*", - }, - { - source: "/ingest/:path*", - destination: "https://us.i.posthog.com/:path*", - }, - ]; - }, - skipTrailingSlashRedirect: true, -}; + experimental: { + reactCompiler: true, + viewTransition: true, + }, + eslint: { + ignoreDuringBuilds: true, + }, + poweredByHeader: false, + async rewrites() { + return [ + { + source: "/ingest/static/:path*", + destination: "https://us-assets.i.posthog.com/static/:path*", + }, + { + source: "/ingest/:path*", + destination: "https://us.i.posthog.com/:path*", + }, + ] + }, + skipTrailingSlashRedirect: true, +} export default withSentryConfig(nextConfig, { - // For all available options, see: + // For all available options, see: // https://www.npmjs.com/package/@sentry/webpack-plugin#options org: "supermemory", - project: "consumer-app", + project: "consumer-app", - // Only print logs for uploading source maps in CI + // Only print logs for uploading source maps in CI silent: !process.env.CI, - // For all available options, see: + // For all available options, see: // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ // Upload a larger set of source maps for prettier stack traces (increases build time) widenClientFileUpload: true, - // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers. + // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers. // This can increase your server load as well as your hosting bill. // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client- // side errors will fail. tunnelRoute: "/monitoring", - // Automatically tree-shake Sentry logger statements to reduce bundle size + // Automatically tree-shake Sentry logger statements to reduce bundle size disableLogger: true, - // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) + // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) // See the following for more information: // https://docs.sentry.io/product/crons/ // https://vercel.com/docs/cron-jobs automaticVercelMonitors: true, -}); +}) -import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare"; +import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare" -initOpenNextCloudflareForDev(); \ No newline at end of file +initOpenNextCloudflareForDev() diff --git a/bun.lock b/bun.lock index 00818471..06d015e1 100644 --- a/bun.lock +++ b/bun.lock @@ -20,6 +20,7 @@ "boxen": "^8.0.1", "cloudflare": "^4.5.0", "compromise": "^14.14.4", + "cva": "^1.0.0-beta.4", "dedent": "^1.6.0", "destr": "^2.0.5", "drizzle-orm": "^0.44.3", @@ -2002,6 +2003,8 @@ "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "cva": ["cva@1.0.0-beta.4", "", { "dependencies": { "clsx": "^2.1.1" }, "peerDependencies": { "typescript": ">= 4.5.5" }, "optionalPeers": ["typescript"] }, "sha512-F/JS9hScapq4DBVQXcK85l9U91M6ePeXoBMSp7vypzShoefUBxjQTo3g3935PUHgQd+IW77DjbPRIxugy4/GCQ=="], + "cytoscape": ["cytoscape@3.33.1", "", {}, "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ=="], "cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="], diff --git a/package.json b/package.json index a7cc83e7..e8e5a70b 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "boxen": "^8.0.1", "cloudflare": "^4.5.0", "compromise": "^14.14.4", + "cva": "^1.0.0-beta.4", "dedent": "^1.6.0", "destr": "^2.0.5", "drizzle-orm": "^0.44.3", diff --git a/packages/ui/text/heading.tsx b/packages/ui/text/heading.tsx new file mode 100644 index 00000000..04324421 --- /dev/null +++ b/packages/ui/text/heading.tsx @@ -0,0 +1,63 @@ +import { Root } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "cva" +import { cn } from "../../lib/utils" + +export const headingVariants = cva({ + base: "tracking-[-0.4px]", + variants: { + level: { + h1: "text-sm sm:text-base md:text-lg lg:text-xl leading-[32px]", + h2: "text-xs sm:text-sm md:text-base lg:text-lg leading-[30px]", + h3: "text-[0.625rem] sm:text-xs md:text-sm lg:text-base leading-[28px]", + h4: "text-[0.5rem] sm:text-[0.625rem] md:text-xs lg:text-sm leading-[24px]", + }, + weight: { + bold: "font-bold", + medium: "font-medium", + }, + }, + defaultVariants: { + level: "h1", + weight: "medium", + }, +}) + +export interface HeadingProps + extends React.HTMLAttributes, + VariantProps { + asChild?: boolean +} + +export function Heading({ + className, + level = "h1", + weight = "medium", + asChild, + ...props +}: HeadingProps) { + const Comp = asChild ? Root : level + return ( + + ) +} + +// Export individual variant classes for compatibility +export const headingH1Bold = () => + headingVariants({ level: "h1", weight: "bold" }) +export const headingH1Medium = () => + headingVariants({ level: "h1", weight: "medium" }) +export const headingH2Bold = () => + headingVariants({ level: "h2", weight: "bold" }) +export const headingH2Medium = () => + headingVariants({ level: "h2", weight: "medium" }) +export const headingH3Bold = () => + headingVariants({ level: "h3", weight: "bold" }) +export const headingH3Medium = () => + headingVariants({ level: "h3", weight: "medium" }) +export const headingH4Bold = () => + headingVariants({ level: "h4", weight: "bold" }) +export const headingH4Medium = () => + headingVariants({ level: "h4", weight: "medium" }) diff --git a/packages/ui/text/label.tsx b/packages/ui/text/label.tsx new file mode 100644 index 00000000..5c20b12d --- /dev/null +++ b/packages/ui/text/label.tsx @@ -0,0 +1,68 @@ +import { Root } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "cva" +import { cn } from "../../lib/utils" + +export const labelVariants = cva({ + base: "tracking-[-0.4px]", + variants: { + level: { + 1: "text-[0.875rem] md:text-[1rem] leading-[1.5rem]", + 2: "text-[0.25rem] sm:text-[0.375rem] md:text-[0.5rem] lg:text-[0.625rem] leading-[18px]", + 3: "text-[0.125rem] sm:text-[0.25rem] md:text-[0.375rem] lg:text-[0.5rem] leading-[16px] tracking-[-0.2px]", + }, + weight: { + medium: "font-medium", + regular: "font-normal", + }, + color: { + default: "", + muted: "text-sm-silver-chalice", + }, + }, + compoundVariants: [ + { + level: [2, 3], + color: "default", + class: "text-sm-silver-chalice", + }, + ], + defaultVariants: { + level: 1, + weight: "regular", + color: "default", + }, +}) + +export interface LabelProps + extends Omit, "color">, + VariantProps { + asChild?: boolean +} + +export function Label({ + className, + level = 1, + weight = "regular", + color = "default", + asChild, + ...props +}: LabelProps) { + const Comp = asChild ? Root : "p" + return ( + + ) +} + +// Export individual variant classes for compatibility +export const label1Medium = () => labelVariants({ level: 1, weight: "medium" }) +export const label1Regular = () => + labelVariants({ level: 1, weight: "regular" }) +export const label2Medium = () => labelVariants({ level: 2, weight: "medium" }) +export const label2Regular = () => + labelVariants({ level: 2, weight: "regular" }) +export const label3Medium = () => labelVariants({ level: 3, weight: "medium" }) +export const label3Regular = () => + labelVariants({ level: 3, weight: "regular" }) diff --git a/packages/ui/text/title.tsx b/packages/ui/text/title.tsx new file mode 100644 index 00000000..5a6c5f5a --- /dev/null +++ b/packages/ui/text/title.tsx @@ -0,0 +1,65 @@ +import { Root } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "cva" +import { cn } from "../../lib/utils" + +export const titleVariants = cva({ + base: "tracking-[-0.4px]", + variants: { + level: { + 1: "text-xl sm:text-2xl md:text-3xl lg:text-4xl leading-[70px] tracking-[-0.8px]", + 2: "text-lg sm:text-xl md:text-2xl lg:text-3xl leading-[48px]", + 3: "text-base sm:text-lg md:text-xl lg:text-2xl leading-[40px]", + }, + weight: { + bold: "font-bold", + medium: "font-medium", + }, + }, + compoundVariants: [ + { + level: 2, + weight: "medium", + class: "leading-[32px] md:leading-[48px]", + }, + ], + defaultVariants: { + level: 1, + weight: "medium", + }, +}) + +export interface TitleProps + extends React.HTMLAttributes, + VariantProps { + asChild?: boolean +} + +export function Title({ + className, + level = 1, + weight = "medium", + asChild, + ...props +}: TitleProps) { + const levelMap = { + 1: "h1", + 2: "h2", + 3: "h3", + } as const + + const Comp = asChild ? Root : levelMap[level] + return ( + + ) +} + +// Export individual variant classes for compatibility +export const title1Bold = () => titleVariants({ level: 1, weight: "bold" }) +export const title1Medium = () => titleVariants({ level: 1, weight: "medium" }) +export const title2Bold = () => titleVariants({ level: 2, weight: "bold" }) +export const title2Medium = () => titleVariants({ level: 2, weight: "medium" }) +export const title3Bold = () => titleVariants({ level: 3, weight: "bold" }) +export const title3Medium = () => titleVariants({ level: 3, weight: "medium" }) -- cgit v1.2.3