diff --git a/src/components/dashboard/advanced-url-form-card.tsx b/src/app/(admin)/dashboard/_components/advanced-url-form-card.tsx similarity index 100% rename from src/components/dashboard/advanced-url-form-card.tsx rename to src/app/(admin)/dashboard/_components/advanced-url-form-card.tsx diff --git a/src/components/dashboard/sidebar-theme-toggle.tsx b/src/app/(admin)/dashboard/_components/sidebar-theme-toggle.tsx similarity index 100% rename from src/components/dashboard/sidebar-theme-toggle.tsx rename to src/app/(admin)/dashboard/_components/sidebar-theme-toggle.tsx diff --git a/src/components/dashboard/sidebar-user-dropdown.tsx b/src/app/(admin)/dashboard/_components/sidebar-user-dropdown.tsx similarity index 100% rename from src/components/dashboard/sidebar-user-dropdown.tsx rename to src/app/(admin)/dashboard/_components/sidebar-user-dropdown.tsx diff --git a/src/components/dashboard/sidebar.tsx b/src/app/(admin)/dashboard/_components/sidebar.tsx similarity index 100% rename from src/components/dashboard/sidebar.tsx rename to src/app/(admin)/dashboard/_components/sidebar.tsx diff --git a/src/components/dashboard/stats-card.tsx b/src/app/(admin)/dashboard/_components/stats-card.tsx similarity index 100% rename from src/components/dashboard/stats-card.tsx rename to src/app/(admin)/dashboard/_components/stats-card.tsx diff --git a/src/components/dashboard/url-form-card.tsx b/src/app/(admin)/dashboard/_components/url-form-card.tsx similarity index 100% rename from src/components/dashboard/url-form-card.tsx rename to src/app/(admin)/dashboard/_components/url-form-card.tsx diff --git a/src/components/dashboard/urls-data-table.tsx b/src/app/(admin)/dashboard/_components/urls-data-table.tsx similarity index 100% rename from src/components/dashboard/urls-data-table.tsx rename to src/app/(admin)/dashboard/_components/urls-data-table.tsx diff --git a/src/app/(admin)/dashboard/create/page.tsx b/src/app/(admin)/dashboard/create/page.tsx index 7982003..18660d1 100644 --- a/src/app/(admin)/dashboard/create/page.tsx +++ b/src/app/(admin)/dashboard/create/page.tsx @@ -1,4 +1,4 @@ -import { AdvancedUrlFormCard } from "@/components/dashboard/advanced-url-form-card" +import { AdvancedUrlFormCard } from "@/app/(admin)/dashboard/_components/advanced-url-form-card" import { getSession } from "@/lib/auth/session" export default async function DashboardCreatePage() { diff --git a/src/app/(admin)/dashboard/layout.tsx b/src/app/(admin)/dashboard/layout.tsx index d7860b0..f566888 100644 --- a/src/app/(admin)/dashboard/layout.tsx +++ b/src/app/(admin)/dashboard/layout.tsx @@ -1,4 +1,4 @@ -import { DashboardSidebar } from "@/components/dashboard/sidebar" +import { DashboardSidebar } from "@/app/(admin)/dashboard/_components/sidebar" import { SidebarProvider } from "@/components/ui/sidebar" import { ReactNode } from "react" diff --git a/src/app/(admin)/dashboard/list/page.tsx b/src/app/(admin)/dashboard/list/page.tsx index 5c7d1fb..a87bd9f 100644 --- a/src/app/(admin)/dashboard/list/page.tsx +++ b/src/app/(admin)/dashboard/list/page.tsx @@ -1,4 +1,4 @@ -import { UrlsDataTable } from "@/components/dashboard/urls-data-table" +import { UrlsDataTable } from "@/app/(admin)/dashboard/_components/urls-data-table" import { getSession } from "@/lib/auth/session" import { getAllUrls } from "@/lib/db/urls" diff --git a/src/app/(admin)/dashboard/page.tsx b/src/app/(admin)/dashboard/page.tsx index 601baaa..e21ec4a 100644 --- a/src/app/(admin)/dashboard/page.tsx +++ b/src/app/(admin)/dashboard/page.tsx @@ -1,5 +1,5 @@ -import { StatsCard } from "@/components/dashboard/stats-card" -import { UrlFormCard } from "@/components/dashboard/url-form-card" +import { StatsCard } from "@/app/(admin)/dashboard/_components/stats-card" +import { UrlFormCard } from "@/app/(admin)/dashboard/_components/url-form-card" import { getSession } from "@/lib/auth/session" import { getDashboardStats } from "@/lib/dashboard/stats" import { LinkIcon, MousePointerClick, TrendingUp } from "lucide-react" diff --git a/src/app/(public)/layout.tsx b/src/app/(public)/layout.tsx index 3421e20..ae361c6 100644 --- a/src/app/(public)/layout.tsx +++ b/src/app/(public)/layout.tsx @@ -1,5 +1,5 @@ -import { UserDropdown } from "@/components/auth/user-dropdown" import { ThemeToggle } from "@/components/theme-toggle" +import { UserDropdown } from "@/components/user-dropdown" import Link from "next/link" import { ReactNode } from "react" diff --git a/src/components/auth/signin-button.tsx b/src/app/sign-in/_components/signin-button.tsx similarity index 100% rename from src/components/auth/signin-button.tsx rename to src/app/sign-in/_components/signin-button.tsx diff --git a/src/app/sign-in/page.tsx b/src/app/sign-in/page.tsx index 8a4a5e4..c7ed857 100644 --- a/src/app/sign-in/page.tsx +++ b/src/app/sign-in/page.tsx @@ -1,4 +1,4 @@ -import { OAuthSignInButton } from "@/components/auth/signin-button" +import { OAuthSignInButton } from "@/app/sign-in/_components/signin-button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { getSession } from "@/lib/auth/session" import { LogIn } from "lucide-react" @@ -11,7 +11,7 @@ export default async function SignInPage() { } return ( -
+
diff --git a/src/components/date-picker.tsx b/src/components/date-picker.tsx index 3ae48b5..429971f 100644 --- a/src/components/date-picker.tsx +++ b/src/components/date-picker.tsx @@ -12,7 +12,6 @@ import { cn } from "@/lib/utils" interface DatePickerProps { value?: Date onChange?: (date: Date | undefined) => void - placeholder?: string disabled?: boolean className?: string } @@ -20,7 +19,6 @@ interface DatePickerProps { export function DatePicker({ value, onChange, - placeholder = "Pick a date", disabled = false, className }: DatePickerProps) { @@ -37,7 +35,7 @@ export function DatePicker({ disabled={disabled} > - {value ? format(value, "PPP") : {placeholder}} + {value ? format(value, "PPP") : Pick a date} @@ -45,7 +43,6 @@ export function DatePicker({ mode="single" selected={value} onSelect={onChange} - initialFocus /> diff --git a/src/components/auth/user-dropdown.tsx b/src/components/user-dropdown.tsx similarity index 100% rename from src/components/auth/user-dropdown.tsx rename to src/components/user-dropdown.tsx diff --git a/src/lib/actions/url.ts b/src/lib/actions/url.ts index 6c5b842..73c7aa3 100644 --- a/src/lib/actions/url.ts +++ b/src/lib/actions/url.ts @@ -6,6 +6,7 @@ import { insertUrl } from "../db/urls" import { advancedUrlSchema, urlFormSchema } from "../schema/url" import { deleteUrl as deleteUrlDb } from "../db/urls" import { revalidatePath } from "next/cache" +import { getWebsiteTitle } from "../websiteTitle" type Response = { error: boolean @@ -34,6 +35,7 @@ export async function addUrl(unsafeData: unknown): Promise { await insertUrl({ ...data, slug: data.slug.length === 0 ? undefined : data.slug, + title: await getWebsiteTitle(data.url) }) revalidatePath("/dashboard") @@ -66,7 +68,7 @@ export async function createAdvanceUrl(unsafeData: unknown): Promise { await insertUrl({ ...data, slug: data.slug?.length === 0 ? undefined : data.slug, - title: data.title?.length === 0 ? undefined : data.title, + title: data.title?.length === 0 ? await getWebsiteTitle(data.url) : data.title, maxVisits: data.maxVisits > 0 ? data.maxVisits : undefined, }) diff --git a/src/lib/websiteTitle.ts b/src/lib/websiteTitle.ts new file mode 100644 index 0000000..92e7483 --- /dev/null +++ b/src/lib/websiteTitle.ts @@ -0,0 +1,31 @@ +export async function getWebsiteTitle(url: string): Promise { + const res = await fetch(url, { redirect: 'follow' }) + + if (!res.ok) { + return null + } + + const contentType = res.headers.get('content-type') + if (!contentType || !contentType.includes('text/html')) { + return null + } + + const html = await res.text() + + const titleMatch = html.match(/]*>([^<]*)<\/title>/i) + + if (titleMatch && titleMatch[1]) { + const title = titleMatch[1] + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(/ /g, ' ') + .trim() + + return title || null + } + + return null +} \ No newline at end of file