mirror of
https://github.com/walkxcode/dashboard-icons.git
synced 2025-10-27 05:29:03 +08:00
chore: format codebase
This commit is contained in:
@@ -7,10 +7,7 @@
|
|||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"ignoreUnknown": false,
|
"ignoreUnknown": false,
|
||||||
"includes": [
|
"includes": ["src/**", "!src/components/ui"]
|
||||||
"src/**",
|
|
||||||
"!src/components/ui"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"lineWidth": 140,
|
"lineWidth": 140,
|
||||||
@@ -22,6 +19,8 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true,
|
"recommended": true,
|
||||||
"suspicious": {
|
"suspicious": {
|
||||||
|
"noExplicitAny": "off",
|
||||||
|
"noUnknownAtRules": "off",
|
||||||
"noArrayIndexKey": "off"
|
"noArrayIndexKey": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,4 +38,4 @@
|
|||||||
"quoteStyle": "double"
|
"quoteStyle": "double"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { AlertTriangle, ArrowLeft, RefreshCcw } from "lucide-react"
|
import { AlertTriangle, ArrowLeft, RefreshCcw } from "lucide-react"
|
||||||
import Link from "next/link"
|
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
||||||
export default function ErrorPage({
|
export default function ErrorPage({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
|
||||||
error,
|
|
||||||
reset,
|
|
||||||
}: {
|
|
||||||
error: Error & { digest?: string }
|
|
||||||
reset: () => void
|
|
||||||
}) {
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -125,20 +125,20 @@
|
|||||||
|
|
||||||
--background: oklch(0.99 0 0);
|
--background: oklch(0.99 0 0);
|
||||||
--foreground: oklch(0.32 0 0);
|
--foreground: oklch(0.32 0 0);
|
||||||
--card: oklch(1.0 0 0);
|
--card: oklch(1 0 0);
|
||||||
--card-foreground: oklch(0.32 0 0);
|
--card-foreground: oklch(0.32 0 0);
|
||||||
--popover: oklch(1.0 0 0);
|
--popover: oklch(1 0 0);
|
||||||
--popover-foreground: oklch(0.32 0 0);
|
--popover-foreground: oklch(0.32 0 0);
|
||||||
--primary: oklch(0.67 0.2 23.8);
|
--primary: oklch(0.67 0.2 23.8);
|
||||||
--primary-foreground: oklch(1.0 0 0);
|
--primary-foreground: oklch(1 0 0);
|
||||||
--secondary: oklch(0.97 0.0 264.54);
|
--secondary: oklch(0.97 0 264.54);
|
||||||
--secondary-foreground: oklch(0.45 0.03 256.8);
|
--secondary-foreground: oklch(0.45 0.03 256.8);
|
||||||
--muted: oklch(0.98 0.0 247.84);
|
--muted: oklch(0.98 0 247.84);
|
||||||
--muted-foreground: oklch(0.55 0.02 264.36);
|
--muted-foreground: oklch(0.55 0.02 264.36);
|
||||||
--accent: oklch(0.967 0.001 286.375);
|
--accent: oklch(0.967 0.001 286.375);
|
||||||
--accent-foreground: oklch(0.21 0.006 285.885);
|
--accent-foreground: oklch(0.21 0.006 285.885);
|
||||||
--destructive: oklch(0.64 0.21 25.33);
|
--destructive: oklch(0.64 0.21 25.33);
|
||||||
--destructive-foreground: oklch(1.0 0 0);
|
--destructive-foreground: oklch(1 0 0);
|
||||||
--border: oklch(0.9 0.01 247.88);
|
--border: oklch(0.9 0.01 247.88);
|
||||||
|
|
||||||
--input: oklch(0.92 0.004 286.32);
|
--input: oklch(0.92 0.004 286.32);
|
||||||
@@ -159,16 +159,11 @@
|
|||||||
|
|
||||||
--shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
--shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||||
--shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
--shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||||
--shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px
|
--shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px hsl(0 0% 0% / 0.1);
|
||||||
hsl(0 0% 0% / 0.1);
|
--shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px hsl(0 0% 0% / 0.1);
|
||||||
--shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px
|
--shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 2px 4px -1px hsl(0 0% 0% / 0.1);
|
||||||
hsl(0 0% 0% / 0.1);
|
--shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 4px 6px -1px hsl(0 0% 0% / 0.1);
|
||||||
--shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 2px 4px -1px
|
--shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 8px 10px -1px hsl(0 0% 0% / 0.1);
|
||||||
hsl(0 0% 0% / 0.1);
|
|
||||||
--shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 4px 6px -1px
|
|
||||||
hsl(0 0% 0% / 0.1);
|
|
||||||
--shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 8px 10px -1px
|
|
||||||
hsl(0 0% 0% / 0.1);
|
|
||||||
--shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.25);
|
--shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.25);
|
||||||
|
|
||||||
--magic-gradient-color: oklch(0.67 0.2 23.8 / 15%);
|
--magic-gradient-color: oklch(0.67 0.2 23.8 / 15%);
|
||||||
@@ -182,7 +177,7 @@
|
|||||||
--popover: oklch(0.29 0.02 268.4);
|
--popover: oklch(0.29 0.02 268.4);
|
||||||
--popover-foreground: oklch(0.92 0 0);
|
--popover-foreground: oklch(0.92 0 0);
|
||||||
--primary: oklch(0.67 0.2 23.8);
|
--primary: oklch(0.67 0.2 23.8);
|
||||||
--primary-foreground: oklch(1.0 0 0);
|
--primary-foreground: oklch(1 0 0);
|
||||||
--secondary: oklch(0.31 0.03 266.71);
|
--secondary: oklch(0.31 0.03 266.71);
|
||||||
--secondary-foreground: oklch(0.92 0 0);
|
--secondary-foreground: oklch(0.92 0 0);
|
||||||
--muted: oklch(0.31 0.03 266.71);
|
--muted: oklch(0.31 0.03 266.71);
|
||||||
@@ -190,7 +185,7 @@
|
|||||||
--accent: oklch(0.34 0.06 267.59);
|
--accent: oklch(0.34 0.06 267.59);
|
||||||
--accent-foreground: oklch(0.88 0.06 254.13);
|
--accent-foreground: oklch(0.88 0.06 254.13);
|
||||||
--destructive: oklch(0.64 0.21 25.33);
|
--destructive: oklch(0.64 0.21 25.33);
|
||||||
--destructive-foreground: oklch(1.0 0 0);
|
--destructive-foreground: oklch(1 0 0);
|
||||||
--border: oklch(0.38 0.03 269.73);
|
--border: oklch(0.38 0.03 269.73);
|
||||||
|
|
||||||
--input: oklch(1 0 0 / 15%);
|
--input: oklch(1 0 0 / 15%);
|
||||||
@@ -211,16 +206,11 @@
|
|||||||
|
|
||||||
--shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
--shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||||
--shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
--shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||||
--shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px
|
--shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px hsl(0 0% 0% / 0.1);
|
||||||
hsl(0 0% 0% / 0.1);
|
--shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px hsl(0 0% 0% / 0.1);
|
||||||
--shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 1px 2px -1px
|
--shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 2px 4px -1px hsl(0 0% 0% / 0.1);
|
||||||
hsl(0 0% 0% / 0.1);
|
--shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 4px 6px -1px hsl(0 0% 0% / 0.1);
|
||||||
--shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 2px 4px -1px
|
--shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 8px 10px -1px hsl(0 0% 0% / 0.1);
|
||||||
hsl(0 0% 0% / 0.1);
|
|
||||||
--shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 4px 6px -1px
|
|
||||||
hsl(0 0% 0% / 0.1);
|
|
||||||
--shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.1), 0px 8px 10px -1px
|
|
||||||
hsl(0 0% 0% / 0.1);
|
|
||||||
--shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.25);
|
--shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.25);
|
||||||
|
|
||||||
--magic-gradient-color: oklch(0.27 0 0);
|
--magic-gradient-color: oklch(0.27 0 0);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { readFile } from "node:fs/promises"
|
import { readFile } from "node:fs/promises"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
import { getAllIcons } from "@/lib/api"
|
|
||||||
import { ImageResponse } from "next/og"
|
import { ImageResponse } from "next/og"
|
||||||
|
import { getAllIcons } from "@/lib/api"
|
||||||
|
|
||||||
export const dynamic = "force-static"
|
export const dynamic = "force-static"
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ export default async function Image({ params }: { params: { icon: string } }) {
|
|||||||
const iconPath = join(process.cwd(), `../png/${icon}.png`)
|
const iconPath = join(process.cwd(), `../png/${icon}.png`)
|
||||||
console.log(`Generating opengraph image for ${icon} (${index + 1} / ${totalIcons}) from path ${iconPath}`)
|
console.log(`Generating opengraph image for ${icon} (${index + 1} / ${totalIcons}) from path ${iconPath}`)
|
||||||
iconData = await readFile(iconPath)
|
iconData = await readFile(iconPath)
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
console.error(`Icon ${icon} was not found locally`)
|
console.error(`Icon ${icon} was not found locally`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import type { Metadata, ResolvingMetadata } from "next"
|
||||||
|
import { notFound } from "next/navigation"
|
||||||
import { IconDetails } from "@/components/icon-details"
|
import { IconDetails } from "@/components/icon-details"
|
||||||
import { BASE_URL, WEB_URL } from "@/constants"
|
import { BASE_URL, WEB_URL } from "@/constants"
|
||||||
import { getAllIcons, getAuthorData } from "@/lib/api"
|
import { getAllIcons, getAuthorData } from "@/lib/api"
|
||||||
import type { Metadata, ResolvingMetadata } from "next"
|
|
||||||
import { notFound } from "next/navigation"
|
|
||||||
export const dynamicParams = false
|
export const dynamicParams = false
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
@@ -19,7 +19,7 @@ type Props = {
|
|||||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({ params, searchParams }: Props, parent: ResolvingMetadata): Promise<Metadata> {
|
export async function generateMetadata({ params, searchParams }: Props, _parent: ResolvingMetadata): Promise<Metadata> {
|
||||||
const { icon } = await params
|
const { icon } = await params
|
||||||
const iconsData = await getAllIcons()
|
const iconsData = await getAllIcons()
|
||||||
if (!iconsData[icon]) {
|
if (!iconsData[icon]) {
|
||||||
@@ -76,13 +76,14 @@ export async function generateMetadata({ params, searchParams }: Props, parent:
|
|||||||
type: "website",
|
type: "website",
|
||||||
url: pageUrl,
|
url: pageUrl,
|
||||||
siteName: "Dashboard Icons",
|
siteName: "Dashboard Icons",
|
||||||
images: [{
|
images: [
|
||||||
url: `${BASE_URL}/webp/${icon}.webp`,
|
{
|
||||||
width: 512,
|
url: `${BASE_URL}/webp/${icon}.webp`,
|
||||||
height: 512,
|
width: 512,
|
||||||
alt: `${formattedIconName} icon`,
|
height: 512,
|
||||||
}]
|
alt: `${formattedIconName} icon`,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { cn } from "@/lib/utils"
|
|
||||||
import type React from "react"
|
import type React from "react"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
interface BackgroundWrapperProps {
|
interface BackgroundWrapperProps {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { getAllIcons } from "@/lib/api"
|
|
||||||
import { ImageResponse } from "next/og"
|
import { ImageResponse } from "next/og"
|
||||||
|
import { getAllIcons } from "@/lib/api"
|
||||||
|
|
||||||
export const dynamic = "force-static"
|
export const dynamic = "force-static"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import type { Metadata } from "next"
|
||||||
import { IconSearch } from "@/components/icon-search"
|
import { IconSearch } from "@/components/icon-search"
|
||||||
import { BASE_URL } from "@/constants"
|
import { BASE_URL } from "@/constants"
|
||||||
import { getIconsArray } from "@/lib/api"
|
import { getIconsArray } from "@/lib/api"
|
||||||
import type { Metadata } from "next"
|
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const icons = await getIconsArray()
|
const icons = await getIconsArray()
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { PostHogProvider } from "@/components/PostHogProvider"
|
|
||||||
import { Footer } from "@/components/footer"
|
|
||||||
import { HeaderWrapper } from "@/components/header-wrapper"
|
|
||||||
import { LicenseNotice } from "@/components/license-notice"
|
|
||||||
import { BASE_URL, WEB_URL, getDescription, websiteTitle } from "@/constants"
|
|
||||||
import { getTotalIcons } from "@/lib/api"
|
|
||||||
import type { Metadata, Viewport } from "next"
|
import type { Metadata, Viewport } from "next"
|
||||||
import { Inter } from "next/font/google"
|
import { Inter } from "next/font/google"
|
||||||
import { Toaster } from "sonner"
|
import { Toaster } from "sonner"
|
||||||
|
import { Footer } from "@/components/footer"
|
||||||
|
import { HeaderWrapper } from "@/components/header-wrapper"
|
||||||
|
import { LicenseNotice } from "@/components/license-notice"
|
||||||
|
import { PostHogProvider } from "@/components/PostHogProvider"
|
||||||
|
import { BASE_URL, getDescription, WEB_URL, websiteTitle } from "@/constants"
|
||||||
|
import { getTotalIcons } from "@/lib/api"
|
||||||
import "./globals.css"
|
import "./globals.css"
|
||||||
import { ThemeProvider } from "./theme-provider"
|
import { ThemeProvider } from "./theme-provider"
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
|
import { AlertTriangle, ArrowLeft } from "lucide-react"
|
||||||
|
import Link from "next/link"
|
||||||
import { IconSubmissionContent } from "@/components/icon-submission-form"
|
import { IconSubmissionContent } from "@/components/icon-submission-form"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { AlertTriangle, ArrowLeft, PlusCircle } from "lucide-react"
|
|
||||||
import Link from "next/link"
|
|
||||||
|
|
||||||
export default function NotFound({
|
export default function NotFound({ error }: { error: Error & { digest?: string } }) {
|
||||||
error,
|
|
||||||
}: {
|
|
||||||
error: Error & { digest?: string }
|
|
||||||
}) {
|
|
||||||
return (
|
return (
|
||||||
<div className="py-16 flex items-center justify-center">
|
<div className="py-16 flex items-center justify-center">
|
||||||
<div className="text-center space-y-8 max-w-2xl mx-auto">
|
<div className="text-center space-y-8 max-w-2xl mx-auto">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import type { MetadataRoute } from "next"
|
||||||
import { BASE_URL, WEB_URL } from "@/constants"
|
import { BASE_URL, WEB_URL } from "@/constants"
|
||||||
import { getAllIcons } from "@/lib/api"
|
import { getAllIcons } from "@/lib/api"
|
||||||
import type { MetadataRoute } from "next"
|
|
||||||
|
|
||||||
export const dynamic = "force-static"
|
export const dynamic = "force-static"
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import { useEffect, useRef } from "react"
|
import { useEffect, useRef } from "react"
|
||||||
export function Carbon() {
|
export function Carbon() {
|
||||||
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
||||||
const ref = useRef<HTMLDivElement>(null!)
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const serve = "CW7IKKQM"
|
const serve = "CW7IKKQM"
|
||||||
const placement = "dashboardiconscom"
|
const placement = "dashboardiconscom"
|
||||||
@@ -16,6 +10,11 @@ export function Carbon() {
|
|||||||
ref.current.appendChild(s)
|
ref.current.appendChild(s)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null!)
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Badge } from "@/components/ui/badge"
|
|
||||||
import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"
|
|
||||||
import { useMediaQuery } from "@/hooks/use-media-query"
|
|
||||||
import { filterAndSortIcons, formatIconName, fuzzySearch } from "@/lib/utils"
|
|
||||||
import type { IconWithName } from "@/types/icons"
|
|
||||||
import { Info, Search as SearchIcon, Tag } from "lucide-react"
|
import { Info, Search as SearchIcon, Tag } from "lucide-react"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||||
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"
|
||||||
|
import { useMediaQuery } from "@/hooks/use-media-query"
|
||||||
|
import { filterAndSortIcons, formatIconName } from "@/lib/utils"
|
||||||
|
import type { IconWithName } from "@/types/icons"
|
||||||
|
|
||||||
interface CommandMenuProps {
|
interface CommandMenuProps {
|
||||||
icons: IconWithName[]
|
icons: IconWithName[]
|
||||||
@@ -20,7 +20,7 @@ export function CommandMenu({ icons, open: externalOpen, onOpenChange: externalO
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [internalOpen, setInternalOpen] = useState(false)
|
const [internalOpen, setInternalOpen] = useState(false)
|
||||||
const [query, setQuery] = useState("")
|
const [query, setQuery] = useState("")
|
||||||
const isDesktop = useMediaQuery("(min-width: 768px)")
|
const _isDesktop = useMediaQuery("(min-width: 768px)")
|
||||||
|
|
||||||
// Use either external or internal state for controlling open state
|
// Use either external or internal state for controlling open state
|
||||||
const isOpen = externalOpen !== undefined ? externalOpen : internalOpen
|
const isOpen = externalOpen !== undefined ? externalOpen : internalOpen
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { REPO_PATH } from "@/constants"
|
|
||||||
import { ExternalLink } from "lucide-react"
|
import { ExternalLink } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
import { REPO_PATH } from "@/constants"
|
||||||
import { HeartEasterEgg } from "./heart"
|
import { HeartEasterEgg } from "./heart"
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { usePathname } from "next/navigation"
|
import { usePathname } from "next/navigation"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
export function HeaderNav() {
|
export function HeaderNav() {
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { Github, PlusCircle, Search } from "lucide-react"
|
||||||
|
import Link from "next/link"
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
import { IconSubmissionForm } from "@/components/icon-submission-form"
|
import { IconSubmissionForm } from "@/components/icon-submission-form"
|
||||||
import { ThemeSwitcher } from "@/components/theme-switcher"
|
import { ThemeSwitcher } from "@/components/theme-switcher"
|
||||||
import { REPO_PATH } from "@/constants"
|
import { REPO_PATH } from "@/constants"
|
||||||
import { getIconsArray } from "@/lib/api"
|
import { getIconsArray } from "@/lib/api"
|
||||||
import type { IconWithName } from "@/types/icons"
|
import type { IconWithName } from "@/types/icons"
|
||||||
import { Github, PlusCircle, Search } from "lucide-react"
|
|
||||||
import Link from "next/link"
|
|
||||||
import { useEffect, useState } from "react"
|
|
||||||
import { CommandMenu } from "./command-menu"
|
import { CommandMenu } from "./command-menu"
|
||||||
import { HeaderNav } from "./header-nav"
|
import { HeaderNav } from "./header-nav"
|
||||||
import { Button } from "./ui/button"
|
import { Button } from "./ui/button"
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Heart } from "lucide-react"
|
|
||||||
|
|
||||||
import { motion } from "framer-motion"
|
import { motion } from "framer-motion"
|
||||||
|
import { Heart } from "lucide-react"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
export function HeartEasterEgg() {
|
export function HeartEasterEgg() {
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { Card } from "@/components/ui/card"
|
|
||||||
import { Input } from "@/components/ui/input"
|
|
||||||
import { cn } from "@/lib/utils"
|
|
||||||
import { Separator } from "@radix-ui/react-dropdown-menu"
|
import { Separator } from "@radix-ui/react-dropdown-menu"
|
||||||
import { motion, useAnimation, useInView } from "framer-motion"
|
import { motion, useAnimation, useInView } from "framer-motion"
|
||||||
import {
|
import {
|
||||||
@@ -25,6 +21,10 @@ import {
|
|||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useEffect, useRef, useState } from "react"
|
import { useEffect, useRef, useState } from "react"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Card } from "@/components/ui/card"
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
import { AuroraText } from "./magicui/aurora-text"
|
import { AuroraText } from "./magicui/aurora-text"
|
||||||
import { InteractiveHoverButton } from "./magicui/interactive-hover-button"
|
import { InteractiveHoverButton } from "./magicui/interactive-hover-button"
|
||||||
import { NumberTicker } from "./magicui/number-ticker"
|
import { NumberTicker } from "./magicui/number-ticker"
|
||||||
@@ -35,7 +35,7 @@ interface IconCardProps {
|
|||||||
imageUrl: string
|
imageUrl: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function IconCard({ name, imageUrl }: IconCardProps) {
|
function _IconCard({ name, imageUrl }: IconCardProps) {
|
||||||
return (
|
return (
|
||||||
<Card className="p-4 flex flex-col items-center gap-2 cursor-pointer group hover-lift card-hover">
|
<Card className="p-4 flex flex-col items-center gap-2 cursor-pointer group hover-lift card-hover">
|
||||||
<div className="w-16 h-16 flex items-center justify-center">
|
<div className="w-16 h-16 flex items-center justify-center">
|
||||||
|
|||||||
@@ -1,122 +1,109 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Check, Copy, Download, Github, Link as LinkIcon } from "lucide-react"
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
import Link from "next/link"
|
||||||
import { Check, Copy, Download, Github, Link as LinkIcon } from "lucide-react";
|
import type React from "react"
|
||||||
import Link from "next/link";
|
import { Button } from "@/components/ui/button"
|
||||||
import type React from "react";
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
|
|
||||||
export type IconActionsProps = {
|
export type IconActionsProps = {
|
||||||
imageUrl: string;
|
imageUrl: string
|
||||||
githubUrl: string;
|
githubUrl: string
|
||||||
iconName: string;
|
iconName: string
|
||||||
format: string;
|
format: string
|
||||||
variantKey: string;
|
variantKey: string
|
||||||
copiedUrlKey: string | null;
|
copiedUrlKey: string | null
|
||||||
copiedImageKey: string | null;
|
copiedImageKey: string | null
|
||||||
handleDownload: (event: React.MouseEvent, url: string, filename: string) => Promise<void>;
|
handleDownload: (event: React.MouseEvent, url: string, filename: string) => Promise<void>
|
||||||
handleCopyUrl: (url: string, variantKey: string, event?: React.MouseEvent) => void;
|
handleCopyUrl: (url: string, variantKey: string, event?: React.MouseEvent) => void
|
||||||
handleCopyImage: (imageUrl: string, format: string, variantKey: string, event?: React.MouseEvent) => Promise<void>;
|
handleCopyImage: (imageUrl: string, format: string, variantKey: string, event?: React.MouseEvent) => Promise<void>
|
||||||
};
|
}
|
||||||
|
|
||||||
export function IconActions({
|
export function IconActions({
|
||||||
imageUrl,
|
imageUrl,
|
||||||
githubUrl,
|
githubUrl,
|
||||||
iconName,
|
iconName,
|
||||||
format,
|
format,
|
||||||
variantKey,
|
variantKey,
|
||||||
copiedUrlKey,
|
copiedUrlKey,
|
||||||
copiedImageKey,
|
copiedImageKey,
|
||||||
handleDownload,
|
handleDownload,
|
||||||
handleCopyUrl,
|
handleCopyUrl,
|
||||||
handleCopyImage,
|
handleCopyImage,
|
||||||
}: IconActionsProps) {
|
}: IconActionsProps) {
|
||||||
const downloadFilename = `${iconName}.${format}`;
|
const downloadFilename = `${iconName}.${format}`
|
||||||
const isUrlCopied = copiedUrlKey === variantKey;
|
const isUrlCopied = copiedUrlKey === variantKey
|
||||||
const isImageCopied = copiedImageKey === variantKey;
|
const isImageCopied = copiedImageKey === variantKey
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TooltipProvider delayDuration={300}>
|
<TooltipProvider delayDuration={300}>
|
||||||
<div className="flex gap-2 mt-3 w-full justify-center">
|
<div className="flex gap-2 mt-3 w-full justify-center">
|
||||||
{/* Download Button */}
|
{/* Download Button */}
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-8 w-8 rounded-lg cursor-pointer"
|
className="h-8 w-8 rounded-lg cursor-pointer"
|
||||||
onClick={(e) => handleDownload(e, imageUrl, downloadFilename)}
|
onClick={(e) => handleDownload(e, imageUrl, downloadFilename)}
|
||||||
aria-label={`Download ${iconName} as ${format.toUpperCase()}`}
|
aria-label={`Download ${iconName} as ${format.toUpperCase()}`}
|
||||||
>
|
>
|
||||||
<Download className="w-4 h-4" />
|
<Download className="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Download {format.toUpperCase()}</p>
|
<p>Download {format.toUpperCase()}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
{/* Copy Image Button */}
|
{/* Copy Image Button */}
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-8 w-8 rounded-lg cursor-pointer"
|
className="h-8 w-8 rounded-lg cursor-pointer"
|
||||||
onClick={(e) => handleCopyImage(imageUrl, format, variantKey, e)}
|
onClick={(e) => handleCopyImage(imageUrl, format, variantKey, e)}
|
||||||
aria-label={`Copy ${iconName} image as ${format.toUpperCase()}`}
|
aria-label={`Copy ${iconName} image as ${format.toUpperCase()}`}
|
||||||
>
|
>
|
||||||
{isImageCopied ? (
|
{isImageCopied ? <Check className="w-4 h-4 text-green-500" /> : <Copy className="w-4 h-4" />}
|
||||||
<Check className="w-4 h-4 text-green-500" />
|
</Button>
|
||||||
) : (
|
</TooltipTrigger>
|
||||||
<Copy className="w-4 h-4" />
|
<TooltipContent>
|
||||||
)}
|
<p>Copy image to clipboard</p>
|
||||||
</Button>
|
</TooltipContent>
|
||||||
</TooltipTrigger>
|
</Tooltip>
|
||||||
<TooltipContent>
|
|
||||||
<p>Copy image to clipboard</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
{/* Copy URL Button */}
|
{/* Copy URL Button */}
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-8 w-8 rounded-lg cursor-pointer"
|
className="h-8 w-8 rounded-lg cursor-pointer"
|
||||||
onClick={(e) => handleCopyUrl(imageUrl, variantKey, e)}
|
onClick={(e) => handleCopyUrl(imageUrl, variantKey, e)}
|
||||||
aria-label={`Copy direct URL for ${iconName} ${format.toUpperCase()}`}
|
aria-label={`Copy direct URL for ${iconName} ${format.toUpperCase()}`}
|
||||||
>
|
>
|
||||||
{isUrlCopied ? (
|
{isUrlCopied ? <Check className="w-4 h-4 text-green-500" /> : <LinkIcon className="w-4 h-4" />}
|
||||||
<Check className="w-4 h-4 text-green-500" />
|
</Button>
|
||||||
) : (
|
</TooltipTrigger>
|
||||||
<LinkIcon className="w-4 h-4" />
|
<TooltipContent>
|
||||||
)}
|
<p>Copy direct URL</p>
|
||||||
</Button>
|
</TooltipContent>
|
||||||
</TooltipTrigger>
|
</Tooltip>
|
||||||
<TooltipContent>
|
|
||||||
<p>Copy direct URL</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
{/* View on GitHub Button */}
|
{/* View on GitHub Button */}
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button variant="outline" size="icon" className="h-8 w-8 rounded-lg" asChild>
|
<Button variant="outline" size="icon" className="h-8 w-8 rounded-lg" asChild>
|
||||||
<Link
|
<Link href={githubUrl} target="_blank" rel="noopener noreferrer" aria-label={`View ${iconName} ${format} file on GitHub`}>
|
||||||
href={githubUrl}
|
<Github className="w-4 h-4" />
|
||||||
target="_blank"
|
</Link>
|
||||||
rel="noopener noreferrer"
|
</Button>
|
||||||
aria-label={`View ${iconName} ${format} file on GitHub`}
|
</TooltipTrigger>
|
||||||
>
|
<TooltipContent>
|
||||||
<Github className="w-4 h-4" />
|
<p>View on GitHub</p>
|
||||||
</Link>
|
</TooltipContent>
|
||||||
</Button>
|
</Tooltip>
|
||||||
</TooltipTrigger>
|
</div>
|
||||||
<TooltipContent>
|
</TooltipProvider>
|
||||||
<p>View on GitHub</p>
|
)
|
||||||
</TooltipContent>
|
}
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
|
import Image from "next/image"
|
||||||
|
import Link from "next/link"
|
||||||
import { MagicCard } from "@/components/magicui/magic-card"
|
import { MagicCard } from "@/components/magicui/magic-card"
|
||||||
import { BASE_URL } from "@/constants"
|
import { BASE_URL } from "@/constants"
|
||||||
import { formatIconName } from "@/lib/utils"
|
import { formatIconName } from "@/lib/utils"
|
||||||
import type { Icon } from "@/types/icons"
|
import type { Icon } from "@/types/icons"
|
||||||
import Image from "next/image"
|
|
||||||
import Link from "next/link"
|
|
||||||
|
|
||||||
export function IconCard({
|
export function IconCard({ name, data: iconData, matchedAlias }: { name: string; data: Icon; matchedAlias?: string }) {
|
||||||
name,
|
|
||||||
data: iconData,
|
|
||||||
matchedAlias,
|
|
||||||
}: {
|
|
||||||
name: string
|
|
||||||
data: Icon
|
|
||||||
matchedAlias?: string
|
|
||||||
}) {
|
|
||||||
const formatedIconName = formatIconName(name)
|
const formatedIconName = formatIconName(name)
|
||||||
return (
|
return (
|
||||||
<MagicCard className="rounded-md shadow-md">
|
<MagicCard className="rounded-md shadow-md">
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { IconsGrid } from "@/components/icon-grid"
|
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
|
||||||
import { BASE_URL, REPO_PATH } from "@/constants"
|
|
||||||
import { formatIconName } from "@/lib/utils"
|
|
||||||
import type { AuthorData, Icon, IconFile } from "@/types/icons"
|
|
||||||
import confetti from "canvas-confetti"
|
import confetti from "canvas-confetti"
|
||||||
import { motion } from "framer-motion"
|
import { motion } from "framer-motion"
|
||||||
import { ArrowRight, Check, FileType, Github, Moon, PaletteIcon, Sun, Type } from "lucide-react"
|
import { ArrowRight, Check, FileType, Github, Moon, PaletteIcon, Sun, Type } from "lucide-react"
|
||||||
@@ -16,16 +8,20 @@ import Link from "next/link"
|
|||||||
import type React from "react"
|
import type React from "react"
|
||||||
import { useCallback, useState } from "react"
|
import { useCallback, useState } from "react"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
|
import { IconsGrid } from "@/components/icon-grid"
|
||||||
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
|
import { BASE_URL, REPO_PATH } from "@/constants"
|
||||||
|
import { formatIconName } from "@/lib/utils"
|
||||||
|
import type { AuthorData, Icon, IconFile } from "@/types/icons"
|
||||||
import { Carbon } from "./carbon"
|
import { Carbon } from "./carbon"
|
||||||
import { IconActions } from "./icon-actions"
|
import { IconActions } from "./icon-actions"
|
||||||
import { MagicCard } from "./magicui/magic-card"
|
import { MagicCard } from "./magicui/magic-card"
|
||||||
import { Badge } from "./ui/badge"
|
import { Badge } from "./ui/badge"
|
||||||
|
|
||||||
type RenderVariantFn = (
|
type RenderVariantFn = (format: string, iconName: string, theme?: "light" | "dark") => React.ReactNode
|
||||||
format: string,
|
|
||||||
iconName: string,
|
|
||||||
theme?: "light" | "dark"
|
|
||||||
) => React.ReactNode
|
|
||||||
|
|
||||||
type IconVariantsSectionProps = {
|
type IconVariantsSectionProps = {
|
||||||
title: string
|
title: string
|
||||||
@@ -76,11 +72,7 @@ type WordmarkSectionProps = {
|
|||||||
renderVariant: RenderVariantFn
|
renderVariant: RenderVariantFn
|
||||||
}
|
}
|
||||||
|
|
||||||
function WordmarkSection({
|
function WordmarkSection({ iconData, aavailableFormats, renderVariant }: WordmarkSectionProps) {
|
||||||
iconData,
|
|
||||||
aavailableFormats,
|
|
||||||
renderVariant,
|
|
||||||
}: WordmarkSectionProps) {
|
|
||||||
if (!iconData.wordmark) return null
|
if (!iconData.wordmark) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -89,9 +81,7 @@ function WordmarkSection({
|
|||||||
<Type className="w-4 h-4 text-green-500" />
|
<Type className="w-4 h-4 text-green-500" />
|
||||||
Wordmark Variants
|
Wordmark Variants
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
<p className="text-sm text-muted-foreground mb-4">Icon variants that include the brand name. Click to copy URL.</p>
|
||||||
Icon variants that include the brand name. Click to copy URL.
|
|
||||||
</p>
|
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{iconData.wordmark.light && (
|
{iconData.wordmark.light && (
|
||||||
<div>
|
<div>
|
||||||
@@ -135,14 +125,14 @@ export type IconDetailsProps = {
|
|||||||
|
|
||||||
export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetailsProps) {
|
export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetailsProps) {
|
||||||
const authorName = authorData.name || authorData.login || ""
|
const authorName = authorData.name || authorData.login || ""
|
||||||
const iconColorVariants = iconData.colors
|
const _iconColorVariants = iconData.colors
|
||||||
const iconWordmarkVariants = iconData.wordmark
|
const _iconWordmarkVariants = iconData.wordmark
|
||||||
const formattedDate = new Date(iconData.update.timestamp).toLocaleDateString("en-GB", {
|
const formattedDate = new Date(iconData.update.timestamp).toLocaleDateString("en-GB", {
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
})
|
})
|
||||||
|
|
||||||
const getAvailableFormats = () => {
|
const getAvailableFormats = () => {
|
||||||
switch (iconData.base) {
|
switch (iconData.base) {
|
||||||
case "svg":
|
case "svg":
|
||||||
@@ -155,7 +145,7 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
|
|||||||
}
|
}
|
||||||
|
|
||||||
const availableFormats = getAvailableFormats()
|
const availableFormats = getAvailableFormats()
|
||||||
const [copiedVariants, setCopiedVariants] = useState<Record<string, boolean>>({})
|
const [copiedVariants, _setCopiedVariants] = useState<Record<string, boolean>>({})
|
||||||
const [copiedUrlKey, setCopiedUrlKey] = useState<string | null>(null)
|
const [copiedUrlKey, setCopiedUrlKey] = useState<string | null>(null)
|
||||||
const [copiedImageKey, setCopiedImageKey] = useState<string | null>(null)
|
const [copiedImageKey, setCopiedImageKey] = useState<string | null>(null)
|
||||||
|
|
||||||
@@ -207,16 +197,11 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCopyImage = async (
|
const handleCopyImage = async (imageUrl: string, format: string, variantKey: string, event?: React.MouseEvent) => {
|
||||||
imageUrl: string,
|
|
||||||
format: string,
|
|
||||||
variantKey: string,
|
|
||||||
event?: React.MouseEvent
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
toast.loading("Copying image...")
|
toast.loading("Copying image...")
|
||||||
|
|
||||||
if (format === 'svg') {
|
if (format === "svg") {
|
||||||
const response = await fetch(imageUrl)
|
const response = await fetch(imageUrl)
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to fetch SVG: ${response.statusText}`)
|
throw new Error(`Failed to fetch SVG: ${response.statusText}`)
|
||||||
@@ -240,8 +225,7 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
|
|||||||
toast.success("SVG Markup Copied", {
|
toast.success("SVG Markup Copied", {
|
||||||
description: "The SVG code has been copied to your clipboard.",
|
description: "The SVG code has been copied to your clipboard.",
|
||||||
})
|
})
|
||||||
|
} else if (format === "png" || format === "webp") {
|
||||||
} else if (format === 'png' || format === 'webp') {
|
|
||||||
const mimeType = `image/${format}`
|
const mimeType = `image/${format}`
|
||||||
const response = await fetch(imageUrl)
|
const response = await fetch(imageUrl)
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -250,10 +234,10 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
|
|||||||
const blob = await response.blob()
|
const blob = await response.blob()
|
||||||
|
|
||||||
if (!blob) {
|
if (!blob) {
|
||||||
throw new Error('Failed to generate image blob')
|
throw new Error("Failed to generate image blob")
|
||||||
}
|
}
|
||||||
|
|
||||||
await navigator.clipboard.write([new ClipboardItem({ [mimeType]: blob })]);
|
await navigator.clipboard.write([new ClipboardItem({ [mimeType]: blob })])
|
||||||
|
|
||||||
setCopiedImageKey(variantKey)
|
setCopiedImageKey(variantKey)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -270,11 +254,9 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
|
|||||||
toast.success("Image copied", {
|
toast.success("Image copied", {
|
||||||
description: `The ${format.toUpperCase()} image has been copied to your clipboard.`,
|
description: `The ${format.toUpperCase()} image has been copied to your clipboard.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unsupported format for image copy: ${format}`)
|
throw new Error(`Unsupported format for image copy: ${format}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Copy error:", error)
|
console.error("Copy error:", error)
|
||||||
toast.dismiss()
|
toast.dismiss()
|
||||||
@@ -445,9 +427,7 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
|
|||||||
{authorName}
|
{authorName}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{!authorData.html_url && (
|
{!authorData.html_url && <span className="text-sm">{authorName}</span>}
|
||||||
<span className="text-sm">{authorName}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -696,6 +676,7 @@ export function IconDetails({ icon, iconData, authorData, allIcons }: IconDetail
|
|||||||
<Card className="bg-background/50 border shadow-lg">
|
<Card className="bg-background/50 border shadow-lg">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>
|
<CardTitle>
|
||||||
|
{/** biome-ignore lint/correctness/useUniqueElementIds: I want the ID to be fixed */}
|
||||||
<h2 id="related-icons-title">Related Icons</h2>
|
<h2 id="related-icons-title">Related Icons</h2>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { Icon } from "@/types/icons"
|
|
||||||
|
|
||||||
import { useWindowVirtualizer } from "@tanstack/react-virtual"
|
import { useWindowVirtualizer } from "@tanstack/react-virtual"
|
||||||
import { useEffect, useMemo, useRef, useState } from "react"
|
import { useEffect, useMemo, useRef, useState } from "react"
|
||||||
|
import type { Icon } from "@/types/icons"
|
||||||
import { IconCard } from "./icon-card"
|
import { IconCard } from "./icon-card"
|
||||||
|
|
||||||
interface IconsGridProps {
|
interface IconsGridProps {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { ArrowDownAZ, ArrowUpZA, Calendar, Filter, Search, SortAsc, X } from "lucide-react"
|
||||||
|
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
||||||
|
import { useTheme } from "next-themes"
|
||||||
|
import posthog from "posthog-js"
|
||||||
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||||
|
import { toast } from "sonner"
|
||||||
import { VirtualizedIconsGrid } from "@/components/icon-grid"
|
import { VirtualizedIconsGrid } from "@/components/icon-grid"
|
||||||
import { IconSubmissionContent } from "@/components/icon-submission-form"
|
import { IconSubmissionContent } from "@/components/icon-submission-form"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
@@ -17,14 +23,8 @@ import {
|
|||||||
} from "@/components/ui/dropdown-menu"
|
} from "@/components/ui/dropdown-menu"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import { type SortOption, filterAndSortIcons } from "@/lib/utils"
|
import { filterAndSortIcons, type SortOption } from "@/lib/utils"
|
||||||
import type { IconSearchProps } from "@/types/icons"
|
import type { IconSearchProps } from "@/types/icons"
|
||||||
import { ArrowDownAZ, ArrowUpZA, Calendar, Filter, Search, SortAsc, X } from "lucide-react"
|
|
||||||
import { useTheme } from "next-themes"
|
|
||||||
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
|
||||||
import posthog from "posthog-js"
|
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
|
||||||
import { toast } from "sonner"
|
|
||||||
|
|
||||||
export function IconSearch({ icons }: IconSearchProps) {
|
export function IconSearch({ icons }: IconSearchProps) {
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
@@ -359,6 +359,7 @@ export function IconSearch({ icons }: IconSearchProps) {
|
|||||||
<p className="text-lg text-muted-foreground mt-2">Help us expand our collection</p>
|
<p className="text-lg text-muted-foreground mt-2">Help us expand our collection</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4 items-center w-full">
|
<div className="flex flex-col gap-4 items-center w-full">
|
||||||
|
{/** biome-ignore lint/correctness/useUniqueElementIds: I want the ID to be fixed */}
|
||||||
<div id="icon-submission-content" className="w-full">
|
<div id="icon-submission-content" className="w-full">
|
||||||
<IconSubmissionContent />
|
<IconSubmissionContent />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
|
|
||||||
import { REPO_PATH } from "@/constants"
|
|
||||||
import { DialogDescription } from "@radix-ui/react-dialog"
|
import { DialogDescription } from "@radix-ui/react-dialog"
|
||||||
import { ExternalLink, PlusCircle } from "lucide-react"
|
import { ExternalLink, PlusCircle } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
|
||||||
|
import { REPO_PATH } from "@/constants"
|
||||||
|
|
||||||
export const ISSUE_TEMPLATES = [
|
export const ISSUE_TEMPLATES = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { REPO_PATH } from "@/constants"
|
|
||||||
import { AnimatePresence, motion } from "framer-motion"
|
import { AnimatePresence, motion } from "framer-motion"
|
||||||
import { X } from "lucide-react"
|
import { X } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { REPO_PATH } from "@/constants"
|
||||||
|
|
||||||
const LOCAL_STORAGE_KEY = "licenseNoticeDismissed"
|
const LOCAL_STORAGE_KEY = "licenseNoticeDismissed"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { cn } from "@/lib/utils"
|
|
||||||
import { ArrowRight } from "lucide-react"
|
import { ArrowRight } from "lucide-react"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
import { Button } from "../ui/button"
|
import { Button } from "../ui/button"
|
||||||
|
|
||||||
interface InteractiveHoverButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
interface InteractiveHoverButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { cn } from "@/lib/utils"
|
|
||||||
import type { ComponentPropsWithoutRef } from "react"
|
import type { ComponentPropsWithoutRef } from "react"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
interface MarqueeProps extends ComponentPropsWithoutRef<"div"> {
|
interface MarqueeProps extends ComponentPropsWithoutRef<"div"> {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Marquee } from "@/components/magicui/marquee"
|
|
||||||
import { BASE_URL } from "@/constants"
|
|
||||||
import { cn, formatIconName } from "@/lib/utils"
|
|
||||||
import type { Icon, IconWithName } from "@/types/icons"
|
|
||||||
import { format, isToday, isYesterday } from "date-fns"
|
import { format, isToday, isYesterday } from "date-fns"
|
||||||
import { ArrowRight, Clock, ExternalLink } from "lucide-react"
|
import { ArrowRight, Clock, ExternalLink } from "lucide-react"
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
import { Marquee } from "@/components/magicui/marquee"
|
||||||
|
import { BASE_URL } from "@/constants"
|
||||||
|
import { cn, formatIconName } from "@/lib/utils"
|
||||||
|
import type { Icon, IconWithName } from "@/types/icons"
|
||||||
|
|
||||||
function formatIconDate(timestamp: string): string {
|
function formatIconDate(timestamp: string): string {
|
||||||
const date = new Date(timestamp)
|
const date = new Date(timestamp)
|
||||||
@@ -71,13 +71,7 @@ export function RecentlyAddedIcons({ icons }: { icons: IconWithName[] }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Marquee-compatible icon card
|
// Marquee-compatible icon card
|
||||||
function RecentIconCard({
|
function RecentIconCard({ name, data }: { name: string; data: Icon }) {
|
||||||
name,
|
|
||||||
data,
|
|
||||||
}: {
|
|
||||||
name: string
|
|
||||||
data: Icon
|
|
||||||
}) {
|
|
||||||
const formattedIconName = formatIconName(name)
|
const formattedIconName = formatIconName(name)
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
import { Moon, Sun } from "lucide-react"
|
import { Moon, Sun } from "lucide-react"
|
||||||
import { useTheme } from "next-themes"
|
import { useTheme } from "next-themes"
|
||||||
|
import { useState } from "react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
import { useState } from "react"
|
|
||||||
|
|
||||||
export function ThemeSwitcher() {
|
export function ThemeSwitcher() {
|
||||||
const { setTheme } = useTheme()
|
const { setTheme } = useTheme()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { IconWithName } from "@/types/icons"
|
|
||||||
import { type ClassValue, clsx } from "clsx"
|
import { type ClassValue, clsx } from "clsx"
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge"
|
||||||
|
import type { IconWithName } from "@/types/icons"
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs))
|
||||||
|
|||||||
Reference in New Issue
Block a user