This commit is contained in:
parent
844d31754d
commit
36870785bc
35 changed files with 1344 additions and 1330 deletions
|
@ -1,20 +1,20 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://ui.shadcn.com/schema.json",
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
"style": "new-york",
|
"style": "new-york",
|
||||||
"rsc": false,
|
"rsc": false,
|
||||||
"tsx": true,
|
"tsx": true,
|
||||||
"tailwind": {
|
"tailwind": {
|
||||||
"config": "tailwind.config.ts",
|
"config": "tailwind.config.ts",
|
||||||
"css": "src/styles/global.css",
|
"css": "src/styles/global.css",
|
||||||
"baseColor": "neutral",
|
"baseColor": "neutral",
|
||||||
"cssVariables": true,
|
"cssVariables": true,
|
||||||
"prefix": ""
|
"prefix": ""
|
||||||
},
|
},
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"components": "@/components",
|
"components": "@/components",
|
||||||
"utils": "@/lib/utils",
|
"utils": "@/lib/utils",
|
||||||
"ui": "@/components/ui",
|
"ui": "@/components/ui",
|
||||||
"lib": "@/lib",
|
"lib": "@/lib",
|
||||||
"hooks": "@/hooks"
|
"hooks": "@/hooks"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
122
package.json
122
package.json
|
@ -1,63 +1,63 @@
|
||||||
{
|
{
|
||||||
"name": "astro-erudite",
|
"name": "astro-erudite",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
"prettier": "prettier --write .",
|
"prettier": "prettier --write .",
|
||||||
"postinstall": "patch-package"
|
"postinstall": "patch-package"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/markdown-remark": "^6.3.1",
|
"@astrojs/markdown-remark": "^6.3.1",
|
||||||
"@astrojs/partytown": "^2.1.4",
|
"@astrojs/partytown": "^2.1.4",
|
||||||
"@astrojs/react": "^4.2.5",
|
"@astrojs/react": "^4.2.5",
|
||||||
"@astrojs/rss": "^4.0.11",
|
"@astrojs/rss": "^4.0.11",
|
||||||
"@astrojs/sitemap": "^3.3.1",
|
"@astrojs/sitemap": "^3.3.1",
|
||||||
"@expressive-code/plugin-collapsible-sections": "^0.40.2",
|
"@expressive-code/plugin-collapsible-sections": "^0.40.2",
|
||||||
"@expressive-code/plugin-line-numbers": "^0.40.2",
|
"@expressive-code/plugin-line-numbers": "^0.40.2",
|
||||||
"@fontsource-variable/geist": "^5.2.5",
|
"@fontsource-variable/geist": "^5.2.5",
|
||||||
"@fontsource-variable/geist-mono": "^5.2.5",
|
"@fontsource-variable/geist-mono": "^5.2.5",
|
||||||
"@iconify-json/lucide": "^1.2.39",
|
"@iconify-json/lucide": "^1.2.39",
|
||||||
"@iconify-json/simple-icons": "^1.2.33",
|
"@iconify-json/simple-icons": "^1.2.33",
|
||||||
"@r4ai/remark-callout": "^0.6.2",
|
"@r4ai/remark-callout": "^0.6.2",
|
||||||
"@radix-ui/react-avatar": "^1.1.7",
|
"@radix-ui/react-avatar": "^1.1.7",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.6",
|
"@radix-ui/react-scroll-area": "^1.2.6",
|
||||||
"@radix-ui/react-separator": "^1.1.4",
|
"@radix-ui/react-separator": "^1.1.4",
|
||||||
"@radix-ui/react-slot": "^1.2.0",
|
"@radix-ui/react-slot": "^1.2.0",
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
"@types/react": "19.0.0",
|
"@types/react": "19.0.0",
|
||||||
"@types/react-dom": "19.0.0",
|
"@types/react-dom": "19.0.0",
|
||||||
"@yeskunall/astro-umami": "^0.0.5",
|
"@yeskunall/astro-umami": "^0.0.5",
|
||||||
"astro": "^5.7.5",
|
"astro": "^5.7.5",
|
||||||
"astro-expressive-code": "^0.40.2",
|
"astro-expressive-code": "^0.40.2",
|
||||||
"astro-icon": "^1.1.5",
|
"astro-icon": "^1.1.5",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.469.0",
|
"lucide-react": "^0.469.0",
|
||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"rehype-document": "^7.0.3",
|
"rehype-document": "^7.0.3",
|
||||||
"rehype-external-links": "^3.0.0",
|
"rehype-external-links": "^3.0.0",
|
||||||
"rehype-katex": "^7.0.1",
|
"rehype-katex": "^7.0.1",
|
||||||
"rehype-pretty-code": "^0.14.1",
|
"rehype-pretty-code": "^0.14.1",
|
||||||
"remark-emoji": "^5.0.1",
|
"remark-emoji": "^5.0.1",
|
||||||
"remark-math": "^6.0.0",
|
"remark-math": "^6.0.0",
|
||||||
"remark-sectionize": "^2.1.0",
|
"remark-sectionize": "^2.1.0",
|
||||||
"remark-toc": "^9.0.0",
|
"remark-toc": "^9.0.0",
|
||||||
"tailwind-merge": "^3.2.0",
|
"tailwind-merge": "^3.2.0",
|
||||||
"tailwindcss": "^4.1.4",
|
"tailwindcss": "^4.1.4",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.9.4"
|
"@biomejs/biome": "^1.9.4"
|
||||||
},
|
},
|
||||||
"trustedDependencies": ["@biomejs/biome", "esbuild", "sharp"]
|
"trustedDependencies": ["@biomejs/biome", "esbuild", "sharp"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
---
|
---
|
||||||
import { Separator } from '@/components/ui/separator'
|
import { Image } from "astro:assets";
|
||||||
import { formatDate, readingTime } from '@/lib/utils'
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { Image } from 'astro:assets'
|
import { Separator } from "@/components/ui/separator";
|
||||||
import type { CollectionEntry } from 'astro:content'
|
import { formatDate, readingTime } from "@/lib/utils";
|
||||||
import Link from './Link.astro'
|
import Link from "./Link.astro";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
entry: CollectionEntry<'blog'>
|
entry: CollectionEntry<"blog">;
|
||||||
}
|
};
|
||||||
|
|
||||||
const { entry } = Astro.props as {
|
const { entry } = Astro.props as {
|
||||||
entry: CollectionEntry<'blog'>
|
entry: CollectionEntry<"blog">;
|
||||||
}
|
};
|
||||||
|
|
||||||
const formattedDate = formatDate(entry.data.date)
|
const formattedDate = formatDate(entry.data.date);
|
||||||
const readTime = readingTime(entry.body!)
|
const readTime = readingTime(entry.body!);
|
||||||
---
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
---
|
---
|
||||||
import {
|
import {
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
BreadcrumbList,
|
BreadcrumbList,
|
||||||
BreadcrumbPage,
|
BreadcrumbPage,
|
||||||
BreadcrumbSeparator,
|
BreadcrumbSeparator,
|
||||||
} from '@/components/ui/breadcrumb'
|
} from "@/components/ui/breadcrumb";
|
||||||
import { Icon } from 'astro-icon/components'
|
import { Icon } from "astro-icon/components";
|
||||||
|
|
||||||
export interface BreadcrumbItem {
|
export interface BreadcrumbItem {
|
||||||
href?: string
|
href?: string;
|
||||||
label: string
|
label: string;
|
||||||
icon?: string
|
icon?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
items: BreadcrumbItem[]
|
items: BreadcrumbItem[];
|
||||||
class?: string
|
class?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { items, class: className } = Astro.props
|
const { items, class: className } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<Breadcrumb className={className}>
|
<Breadcrumb className={className}>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
class?: string
|
class?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { class: className } = Astro.props
|
const { class: className } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class={cn('mx-auto max-w-(--breakpoint-md) px-4', className)}>
|
<div class={cn('mx-auto max-w-(--breakpoint-md) px-4', className)}>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
import Container from '@/components/Container.astro'
|
import Container from "@/components/Container.astro";
|
||||||
import { Separator } from '@/components/ui/separator'
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { SOCIAL_LINKS } from '@/consts'
|
import { SOCIAL_LINKS } from "@/consts";
|
||||||
import SocialIcons from './SocialIcons.astro'
|
import SocialIcons from "./SocialIcons.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<footer class="py-4">
|
<footer class="py-4">
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
---
|
---
|
||||||
import '@fontsource-variable/geist'
|
import "@fontsource-variable/geist";
|
||||||
import '@fontsource-variable/geist-mono'
|
import "@fontsource-variable/geist-mono";
|
||||||
import '../styles/callout.css'
|
import "../styles/callout.css";
|
||||||
import '../styles/global.css'
|
import "../styles/global.css";
|
||||||
import '../styles/typography.css'
|
import "../styles/typography.css";
|
||||||
|
|
||||||
import { SITE } from '@/consts'
|
import { ClientRouter } from "astro:transitions";
|
||||||
import { ClientRouter } from 'astro:transitions'
|
import { SITE } from "@/consts";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string
|
title: string;
|
||||||
description: string
|
description: string;
|
||||||
image?: string
|
image?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site)
|
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||||
|
|
||||||
const { title, description, image = '/static/twitter-card.png' } = Astro.props
|
const { title, description, image = "/static/twitter-card.png" } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
import Container from '@/components/Container.astro'
|
import Container from "@/components/Container.astro";
|
||||||
import Link from '@/components/Link.astro'
|
import Link from "@/components/Link.astro";
|
||||||
import { ModeToggle } from '@/components/ui/mode-toggle'
|
import { ModeToggle } from "@/components/ui/mode-toggle";
|
||||||
import { SITE } from '@/consts'
|
import { SITE } from "@/consts";
|
||||||
---
|
---
|
||||||
|
|
||||||
<header
|
<header
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
---
|
---
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
href: string
|
href: string;
|
||||||
external?: boolean
|
external?: boolean;
|
||||||
class?: string
|
class?: string;
|
||||||
underline?: boolean
|
underline?: boolean;
|
||||||
[key: string]: any
|
[key: string]: any;
|
||||||
}
|
};
|
||||||
|
|
||||||
const { href, external, class: className, underline, ...rest } = Astro.props
|
const { href, external, class: className, underline, ...rest } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<a
|
<a
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
import Link from '@/components/Link.astro'
|
import Link from "@/components/Link.astro";
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import { Icon } from 'astro-icon/components'
|
import { Icon } from "astro-icon/components";
|
||||||
|
|
||||||
const { prevPost, nextPost } = Astro.props
|
const { prevPost, nextPost } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="col-start-2 grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div class="col-start-2 grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
---
|
---
|
||||||
import Link from '@/components/Link.astro'
|
import Link from "@/components/Link.astro";
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ICON_MAP } from '@/consts'
|
import { ICON_MAP } from "@/consts";
|
||||||
import type { SocialLink } from '@/types'
|
import type { SocialLink } from "@/types";
|
||||||
import { Icon } from 'astro-icon/components'
|
import { Icon } from "astro-icon/components";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
links: SocialLink[]
|
links: SocialLink[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { links } = Astro.props
|
const { links } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<ul class="flex flex-wrap gap-2" role="list">
|
<ul class="flex flex-wrap gap-2" role="list">
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
---
|
---
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
import type { MarkdownHeading } from 'astro'
|
import type { MarkdownHeading } from "astro";
|
||||||
import { Icon } from 'astro-icon/components'
|
import { Icon } from "astro-icon/components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
headings: MarkdownHeading[]
|
headings: MarkdownHeading[];
|
||||||
}
|
};
|
||||||
|
|
||||||
const { headings } = Astro.props
|
const { headings } = Astro.props;
|
||||||
|
|
||||||
function getHeadingMargin(depth: number): string {
|
function getHeadingMargin(depth: number): string {
|
||||||
const margins: Record<number, string> = {
|
const margins: Record<number, string> = {
|
||||||
3: 'ml-4',
|
3: "ml-4",
|
||||||
4: 'ml-8',
|
4: "ml-8",
|
||||||
5: 'ml-12',
|
5: "ml-12",
|
||||||
6: 'ml-16',
|
6: "ml-16",
|
||||||
}
|
};
|
||||||
return margins[depth] || ''
|
return margins[depth] || "";
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
import Link from './Link.astro'
|
import Link from "./Link.astro";
|
||||||
import type { Heading } from './TableOfContents.astro'
|
import type { Heading } from "./TableOfContents.astro";
|
||||||
|
|
||||||
const { heading } = Astro.props
|
const { heading } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<li
|
<li
|
||||||
|
|
|
@ -1,74 +1,74 @@
|
||||||
import * as React from 'react'
|
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
||||||
import * as AvatarPrimitive from '@radix-ui/react-avatar'
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Avatar({
|
function Avatar({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
||||||
return (
|
return (
|
||||||
<AvatarPrimitive.Root
|
<AvatarPrimitive.Root
|
||||||
data-slot="avatar"
|
data-slot="avatar"
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex size-8 shrink-0 overflow-hidden rounded-full',
|
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AvatarImage({
|
function AvatarImage({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
||||||
return (
|
return (
|
||||||
<AvatarPrimitive.Image
|
<AvatarPrimitive.Image
|
||||||
data-slot="avatar-image"
|
data-slot="avatar-image"
|
||||||
className={cn('aspect-square size-full', className)}
|
className={cn("aspect-square size-full", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AvatarFallback({
|
function AvatarFallback({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
||||||
return (
|
return (
|
||||||
<AvatarPrimitive.Fallback
|
<AvatarPrimitive.Fallback
|
||||||
data-slot="avatar-fallback"
|
data-slot="avatar-fallback"
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-muted flex size-full items-center justify-center rounded-full',
|
"bg-muted flex size-full items-center justify-center rounded-full",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AvatarComponent: React.FC<AvatarComponentProps> = ({
|
const AvatarComponent: React.FC<AvatarComponentProps> = ({
|
||||||
src,
|
src,
|
||||||
alt,
|
alt,
|
||||||
fallback,
|
fallback,
|
||||||
className,
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Avatar className={className}>
|
<Avatar className={className}>
|
||||||
<AvatarImage src={src} alt={alt} />
|
<AvatarImage src={src} alt={alt} />
|
||||||
<AvatarFallback>{fallback}</AvatarFallback>
|
<AvatarFallback>{fallback}</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default AvatarComponent
|
export default AvatarComponent;
|
||||||
|
|
||||||
interface AvatarComponentProps {
|
interface AvatarComponentProps {
|
||||||
src?: string
|
src?: string;
|
||||||
alt?: string
|
alt?: string;
|
||||||
fallback: string
|
fallback: string;
|
||||||
className?: string
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Avatar, AvatarImage, AvatarFallback }
|
export { Avatar, AvatarImage, AvatarFallback };
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
import * as React from 'react'
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import { Slot } from '@radix-ui/react-slot'
|
import { type VariantProps, cva } from "class-variance-authority";
|
||||||
import { cva, type VariantProps } from 'class-variance-authority'
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const badgeVariants = cva(
|
const badgeVariants = cva(
|
||||||
'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
|
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default:
|
||||||
'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
|
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
||||||
secondary:
|
secondary:
|
||||||
'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
|
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
||||||
destructive:
|
destructive:
|
||||||
'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70',
|
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70",
|
||||||
outline:
|
outline:
|
||||||
'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
|
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: 'default',
|
variant: "default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
function Badge({
|
function Badge({
|
||||||
className,
|
className,
|
||||||
variant,
|
variant,
|
||||||
asChild = false,
|
asChild = false,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<'span'> &
|
}: React.ComponentProps<"span"> &
|
||||||
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
||||||
const Comp = asChild ? Slot : 'span'
|
const Comp = asChild ? Slot : "span";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
data-slot="badge"
|
data-slot="badge"
|
||||||
className={cn(badgeVariants({ variant }), className)}
|
className={cn(badgeVariants({ variant }), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Badge, badgeVariants }
|
export { Badge, badgeVariants };
|
||||||
|
|
|
@ -1,108 +1,108 @@
|
||||||
import * as React from 'react'
|
import { cn } from "@/lib/utils";
|
||||||
import { Slot } from '@radix-ui/react-slot'
|
import { ChevronRightIcon, DotsHorizontalIcon } from "@radix-ui/react-icons";
|
||||||
import { cn } from '@/lib/utils'
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import { ChevronRightIcon, DotsHorizontalIcon } from '@radix-ui/react-icons'
|
import type * as React from "react";
|
||||||
|
|
||||||
function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
|
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
|
||||||
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
|
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
|
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
|
||||||
return (
|
return (
|
||||||
<ol
|
<ol
|
||||||
data-slot="breadcrumb-list"
|
data-slot="breadcrumb-list"
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5',
|
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
|
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
data-slot="breadcrumb-item"
|
data-slot="breadcrumb-item"
|
||||||
className={cn('inline-flex items-center gap-1.5', className)}
|
className={cn("inline-flex items-center gap-1.5", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BreadcrumbLink({
|
function BreadcrumbLink({
|
||||||
asChild,
|
asChild,
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<'a'> & {
|
}: React.ComponentProps<"a"> & {
|
||||||
asChild?: boolean
|
asChild?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const Comp = asChild ? Slot : 'a'
|
const Comp = asChild ? Slot : "a";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
data-slot="breadcrumb-link"
|
data-slot="breadcrumb-link"
|
||||||
className={cn('hover:text-foreground transition-colors', className)}
|
className={cn("hover:text-foreground transition-colors", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
|
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
data-slot="breadcrumb-page"
|
data-slot="breadcrumb-page"
|
||||||
role="link"
|
role="link"
|
||||||
aria-disabled="true"
|
aria-disabled="true"
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
className={cn('text-foreground font-normal', className)}
|
className={cn("text-foreground font-normal", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BreadcrumbSeparator({
|
function BreadcrumbSeparator({
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<'li'>) {
|
}: React.ComponentProps<"li">) {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
data-slot="breadcrumb-separator"
|
data-slot="breadcrumb-separator"
|
||||||
role="presentation"
|
role="presentation"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className={cn('[&>svg]:size-3.5', className)}
|
className={cn("[&>svg]:size-3.5", className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children ?? <ChevronRightIcon />}
|
{children ?? <ChevronRightIcon />}
|
||||||
</li>
|
</li>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BreadcrumbEllipsis({
|
function BreadcrumbEllipsis({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<'span'>) {
|
}: React.ComponentProps<"span">) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
data-slot="breadcrumb-ellipsis"
|
data-slot="breadcrumb-ellipsis"
|
||||||
role="presentation"
|
role="presentation"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className={cn('flex size-9 items-center justify-center', className)}
|
className={cn("flex size-9 items-center justify-center", className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<DotsHorizontalIcon className="size-4" />
|
<DotsHorizontalIcon className="size-4" />
|
||||||
<span className="sr-only">More</span>
|
<span className="sr-only">More</span>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
BreadcrumbList,
|
BreadcrumbList,
|
||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
BreadcrumbPage,
|
BreadcrumbPage,
|
||||||
BreadcrumbSeparator,
|
BreadcrumbSeparator,
|
||||||
BreadcrumbEllipsis,
|
BreadcrumbEllipsis,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,92 +1,92 @@
|
||||||
import * as React from 'react'
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Card({ className, ...props }: React.ComponentProps<'div'>) {
|
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card"
|
data-slot="card"
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
|
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-header"
|
data-slot="card-header"
|
||||||
className={cn(
|
className={cn(
|
||||||
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
|
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-title"
|
data-slot="card-title"
|
||||||
className={cn('leading-none font-medium', className)}
|
className={cn("leading-none font-medium", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-description"
|
data-slot="card-description"
|
||||||
className={cn('text-muted-foreground text-sm', className)}
|
className={cn("text-muted-foreground text-sm", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-action"
|
data-slot="card-action"
|
||||||
className={cn(
|
className={cn(
|
||||||
'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
|
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-content"
|
data-slot="card-content"
|
||||||
className={cn('px-6', className)}
|
className={cn("px-6", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-footer"
|
data-slot="card-footer"
|
||||||
className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
|
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Card,
|
Card,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardFooter,
|
CardFooter,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
CardAction,
|
CardAction,
|
||||||
CardDescription,
|
CardDescription,
|
||||||
CardContent,
|
CardContent,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,255 +1,255 @@
|
||||||
import * as React from 'react'
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||||
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
|
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
||||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react'
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function DropdownMenu({
|
function DropdownMenu({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
||||||
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuPortal({
|
function DropdownMenuPortal({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuTrigger({
|
function DropdownMenuTrigger({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.Trigger
|
<DropdownMenuPrimitive.Trigger
|
||||||
data-slot="dropdown-menu-trigger"
|
data-slot="dropdown-menu-trigger"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuContent({
|
function DropdownMenuContent({
|
||||||
className,
|
className,
|
||||||
sideOffset = 4,
|
sideOffset = 4,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.Portal>
|
<DropdownMenuPrimitive.Portal>
|
||||||
<DropdownMenuPrimitive.Content
|
<DropdownMenuPrimitive.Content
|
||||||
data-slot="dropdown-menu-content"
|
data-slot="dropdown-menu-content"
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-popover text-popover-foreground z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
|
"bg-popover text-popover-foreground z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuPrimitive.Portal>
|
</DropdownMenuPrimitive.Portal>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuGroup({
|
function DropdownMenuGroup({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuItem({
|
function DropdownMenuItem({
|
||||||
className,
|
className,
|
||||||
inset,
|
inset,
|
||||||
variant = 'default',
|
variant = "default",
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
variant?: 'default' | 'destructive'
|
variant?: "default" | "destructive";
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.Item
|
<DropdownMenuPrimitive.Item
|
||||||
data-slot="dropdown-menu-item"
|
data-slot="dropdown-menu-item"
|
||||||
data-inset={inset}
|
data-inset={inset}
|
||||||
data-variant={variant}
|
data-variant={variant}
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuCheckboxItem({
|
function DropdownMenuCheckboxItem({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
checked,
|
checked,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.CheckboxItem
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
data-slot="dropdown-menu-checkbox-item"
|
data-slot="dropdown-menu-checkbox-item"
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||||
<DropdownMenuPrimitive.ItemIndicator>
|
<DropdownMenuPrimitive.ItemIndicator>
|
||||||
<CheckIcon className="size-4" />
|
<CheckIcon className="size-4" />
|
||||||
</DropdownMenuPrimitive.ItemIndicator>
|
</DropdownMenuPrimitive.ItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.CheckboxItem>
|
</DropdownMenuPrimitive.CheckboxItem>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuRadioGroup({
|
function DropdownMenuRadioGroup({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.RadioGroup
|
<DropdownMenuPrimitive.RadioGroup
|
||||||
data-slot="dropdown-menu-radio-group"
|
data-slot="dropdown-menu-radio-group"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuRadioItem({
|
function DropdownMenuRadioItem({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.RadioItem
|
<DropdownMenuPrimitive.RadioItem
|
||||||
data-slot="dropdown-menu-radio-item"
|
data-slot="dropdown-menu-radio-item"
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||||
<DropdownMenuPrimitive.ItemIndicator>
|
<DropdownMenuPrimitive.ItemIndicator>
|
||||||
<CircleIcon className="size-2 fill-current" />
|
<CircleIcon className="size-2 fill-current" />
|
||||||
</DropdownMenuPrimitive.ItemIndicator>
|
</DropdownMenuPrimitive.ItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.RadioItem>
|
</DropdownMenuPrimitive.RadioItem>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuLabel({
|
function DropdownMenuLabel({
|
||||||
className,
|
className,
|
||||||
inset,
|
inset,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.Label
|
<DropdownMenuPrimitive.Label
|
||||||
data-slot="dropdown-menu-label"
|
data-slot="dropdown-menu-label"
|
||||||
data-inset={inset}
|
data-inset={inset}
|
||||||
className={cn(
|
className={cn(
|
||||||
'px-2 py-1.5 text-sm font-medium data-[inset]:pl-8',
|
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuSeparator({
|
function DropdownMenuSeparator({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.Separator
|
<DropdownMenuPrimitive.Separator
|
||||||
data-slot="dropdown-menu-separator"
|
data-slot="dropdown-menu-separator"
|
||||||
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuShortcut({
|
function DropdownMenuShortcut({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<'span'>) {
|
}: React.ComponentProps<"span">) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
data-slot="dropdown-menu-shortcut"
|
data-slot="dropdown-menu-shortcut"
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-muted-foreground ml-auto text-xs tracking-widest',
|
"text-muted-foreground ml-auto text-xs tracking-widest",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuSub({
|
function DropdownMenuSub({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
||||||
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuSubTrigger({
|
function DropdownMenuSubTrigger({
|
||||||
className,
|
className,
|
||||||
inset,
|
inset,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.SubTrigger
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
data-slot="dropdown-menu-sub-trigger"
|
data-slot="dropdown-menu-sub-trigger"
|
||||||
data-inset={inset}
|
data-inset={inset}
|
||||||
className={cn(
|
className={cn(
|
||||||
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8',
|
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<ChevronRightIcon className="ml-auto size-4" />
|
<ChevronRightIcon className="ml-auto size-4" />
|
||||||
</DropdownMenuPrimitive.SubTrigger>
|
</DropdownMenuPrimitive.SubTrigger>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuSubContent({
|
function DropdownMenuSubContent({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.SubContent
|
<DropdownMenuPrimitive.SubContent
|
||||||
data-slot="dropdown-menu-sub-content"
|
data-slot="dropdown-menu-sub-content"
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-popover text-popover-foreground z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
|
"bg-popover text-popover-foreground z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuPortal,
|
DropdownMenuPortal,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuGroup,
|
DropdownMenuGroup,
|
||||||
DropdownMenuLabel,
|
DropdownMenuLabel,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuCheckboxItem,
|
DropdownMenuCheckboxItem,
|
||||||
DropdownMenuRadioGroup,
|
DropdownMenuRadioGroup,
|
||||||
DropdownMenuRadioItem,
|
DropdownMenuRadioItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuShortcut,
|
DropdownMenuShortcut,
|
||||||
DropdownMenuSub,
|
DropdownMenuSub,
|
||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
DropdownMenuSubContent,
|
DropdownMenuSubContent,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,70 +1,70 @@
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu'
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { Laptop, Moon, Sun } from 'lucide-react'
|
import { Laptop, Moon, Sun } from "lucide-react";
|
||||||
import * as React from 'react'
|
import * as React from "react";
|
||||||
|
|
||||||
export function ModeToggle() {
|
export function ModeToggle() {
|
||||||
const [theme, setThemeState] = React.useState<
|
const [theme, setThemeState] = React.useState<
|
||||||
'theme-light' | 'dark' | 'system'
|
"theme-light" | "dark" | "system"
|
||||||
>('theme-light')
|
>("theme-light");
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const isDarkMode = document.documentElement.classList.contains('dark')
|
const isDarkMode = document.documentElement.classList.contains("dark");
|
||||||
setThemeState(isDarkMode ? 'dark' : 'theme-light')
|
setThemeState(isDarkMode ? "dark" : "theme-light");
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const isDark =
|
const isDark =
|
||||||
theme === 'dark' ||
|
theme === "dark" ||
|
||||||
(theme === 'system' &&
|
(theme === "system" &&
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').matches)
|
window.matchMedia("(prefers-color-scheme: dark)").matches);
|
||||||
|
|
||||||
document.documentElement.classList.add('disable-transitions')
|
document.documentElement.classList.add("disable-transitions");
|
||||||
|
|
||||||
document.documentElement.classList[isDark ? 'add' : 'remove']('dark')
|
document.documentElement.classList[isDark ? "add" : "remove"]("dark");
|
||||||
|
|
||||||
window
|
window
|
||||||
.getComputedStyle(document.documentElement)
|
.getComputedStyle(document.documentElement)
|
||||||
.getPropertyValue('opacity')
|
.getPropertyValue("opacity");
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
document.documentElement.classList.remove('disable-transitions')
|
document.documentElement.classList.remove("disable-transitions");
|
||||||
})
|
});
|
||||||
}, [theme])
|
}, [theme]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu modal={false}>
|
<DropdownMenu modal={false}>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="group"
|
className="group"
|
||||||
title="Toggle theme"
|
title="Toggle theme"
|
||||||
>
|
>
|
||||||
<Sun className="size-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
|
<Sun className="size-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
|
||||||
<Moon className="absolute size-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
|
<Moon className="absolute size-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
|
||||||
<span className="sr-only">Toggle theme</span>
|
<span className="sr-only">Toggle theme</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="bg-background">
|
<DropdownMenuContent align="end" className="bg-background">
|
||||||
<DropdownMenuItem onClick={() => setThemeState('theme-light')}>
|
<DropdownMenuItem onClick={() => setThemeState("theme-light")}>
|
||||||
<Sun className="mr-2 size-4" />
|
<Sun className="mr-2 size-4" />
|
||||||
<span>Light</span>
|
<span>Light</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => setThemeState('dark')}>
|
<DropdownMenuItem onClick={() => setThemeState("dark")}>
|
||||||
<Moon className="mr-2 size-4" />
|
<Moon className="mr-2 size-4" />
|
||||||
<span>Dark</span>
|
<span>Dark</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => setThemeState('system')}>
|
<DropdownMenuItem onClick={() => setThemeState("system")}>
|
||||||
<Laptop className="mr-2 size-4" />
|
<Laptop className="mr-2 size-4" />
|
||||||
<span>System</span>
|
<span>System</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,195 +1,194 @@
|
||||||
import * as React from 'react'
|
|
||||||
import {
|
import {
|
||||||
ChevronLeftIcon,
|
ChevronLeftIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
MoreHorizontalIcon,
|
MoreHorizontalIcon,
|
||||||
} from 'lucide-react'
|
} from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { type Button, buttonVariants } from "@/components/ui/button";
|
||||||
import { Button, buttonVariants } from '@/components/ui/button'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
|
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
||||||
return (
|
return (
|
||||||
<nav
|
<nav
|
||||||
role="navigation"
|
aria-label="pagination"
|
||||||
aria-label="pagination"
|
data-slot="pagination"
|
||||||
data-slot="pagination"
|
className={cn("mx-auto flex w-full justify-center", className)}
|
||||||
className={cn('mx-auto flex w-full justify-center', className)}
|
{...props}
|
||||||
{...props}
|
/>
|
||||||
/>
|
);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function PaginationContent({
|
function PaginationContent({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<'ul'>) {
|
}: React.ComponentProps<"ul">) {
|
||||||
return (
|
return (
|
||||||
<ul
|
<ul
|
||||||
data-slot="pagination-content"
|
data-slot="pagination-content"
|
||||||
className={cn('flex flex-row items-center gap-1', className)}
|
className={cn("flex flex-row items-center gap-1", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PaginationItem({ ...props }: React.ComponentProps<'li'>) {
|
function PaginationItem({ ...props }: React.ComponentProps<"li">) {
|
||||||
return <li data-slot="pagination-item" {...props} />
|
return <li data-slot="pagination-item" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaginationLinkProps = {
|
type PaginationLinkProps = {
|
||||||
isActive?: boolean
|
isActive?: boolean;
|
||||||
isDisabled?: boolean
|
isDisabled?: boolean;
|
||||||
} & Pick<React.ComponentProps<typeof Button>, 'size'> &
|
} & Pick<React.ComponentProps<typeof Button>, "size"> &
|
||||||
React.ComponentProps<'a'>
|
React.ComponentProps<"a">;
|
||||||
|
|
||||||
function PaginationLink({
|
function PaginationLink({
|
||||||
className,
|
className,
|
||||||
isActive,
|
isActive,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
size = 'icon',
|
size = "icon",
|
||||||
...props
|
...props
|
||||||
}: PaginationLinkProps) {
|
}: PaginationLinkProps) {
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
aria-current={isActive ? 'page' : undefined}
|
aria-current={isActive ? "page" : undefined}
|
||||||
data-slot="pagination-link"
|
data-slot="pagination-link"
|
||||||
data-active={isActive}
|
data-active={isActive}
|
||||||
data-disabled={isDisabled}
|
data-disabled={isDisabled}
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: isActive ? 'outline' : 'ghost',
|
variant: isActive ? "outline" : "ghost",
|
||||||
size,
|
size,
|
||||||
}),
|
}),
|
||||||
isDisabled && 'pointer-events-none opacity-50',
|
isDisabled && "pointer-events-none opacity-50",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PaginationPrevious({
|
function PaginationPrevious({
|
||||||
className,
|
className,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof PaginationLink>) {
|
}: React.ComponentProps<typeof PaginationLink>) {
|
||||||
return (
|
return (
|
||||||
<PaginationLink
|
<PaginationLink
|
||||||
aria-label="Go to previous page"
|
aria-label="Go to previous page"
|
||||||
size="default"
|
size="default"
|
||||||
className={cn('gap-1 px-2.5 sm:pl-2.5', className)}
|
className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ChevronLeftIcon />
|
<ChevronLeftIcon />
|
||||||
<span className="hidden sm:block">Previous</span>
|
<span className="hidden sm:block">Previous</span>
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PaginationNext({
|
function PaginationNext({
|
||||||
className,
|
className,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof PaginationLink>) {
|
}: React.ComponentProps<typeof PaginationLink>) {
|
||||||
return (
|
return (
|
||||||
<PaginationLink
|
<PaginationLink
|
||||||
aria-label="Go to next page"
|
aria-label="Go to next page"
|
||||||
size="default"
|
size="default"
|
||||||
className={cn('gap-1 px-2.5 sm:pr-2.5', className)}
|
className={cn("gap-1 px-2.5 sm:pr-2.5", className)}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span className="hidden sm:block">Next</span>
|
<span className="hidden sm:block">Next</span>
|
||||||
<ChevronRightIcon />
|
<ChevronRightIcon />
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PaginationEllipsis({
|
function PaginationEllipsis({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<'span'>) {
|
}: React.ComponentProps<"span">) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
aria-hidden
|
aria-hidden
|
||||||
data-slot="pagination-ellipsis"
|
data-slot="pagination-ellipsis"
|
||||||
className={cn('flex size-9 items-center justify-center', className)}
|
className={cn("flex size-9 items-center justify-center", className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<MoreHorizontalIcon className="size-4" />
|
<MoreHorizontalIcon className="size-4" />
|
||||||
<span className="sr-only">More pages</span>
|
<span className="sr-only">More pages</span>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PaginationComponent: React.FC<PaginationProps> = ({
|
const PaginationComponent: React.FC<PaginationProps> = ({
|
||||||
currentPage,
|
currentPage,
|
||||||
totalPages,
|
totalPages,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
}) => {
|
}) => {
|
||||||
const pages = Array.from({ length: totalPages }, (_, i) => i + 1)
|
const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
|
||||||
|
|
||||||
const getPageUrl = (page: number) => {
|
const getPageUrl = (page: number) => {
|
||||||
if (page === 1) return baseUrl
|
if (page === 1) return baseUrl;
|
||||||
return `${baseUrl}${page}`
|
return `${baseUrl}${page}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pagination>
|
<Pagination>
|
||||||
<PaginationContent className="flex-wrap">
|
<PaginationContent className="flex-wrap">
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
<PaginationPrevious
|
<PaginationPrevious
|
||||||
href={currentPage > 1 ? getPageUrl(currentPage - 1) : undefined}
|
href={currentPage > 1 ? getPageUrl(currentPage - 1) : undefined}
|
||||||
isDisabled={currentPage === 1}
|
isDisabled={currentPage === 1}
|
||||||
/>
|
/>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
|
|
||||||
{pages.map((page) => (
|
{pages.map((page) => (
|
||||||
<PaginationItem key={page}>
|
<PaginationItem key={page}>
|
||||||
<PaginationLink
|
<PaginationLink
|
||||||
href={getPageUrl(page)}
|
href={getPageUrl(page)}
|
||||||
isActive={page === currentPage}
|
isActive={page === currentPage}
|
||||||
>
|
>
|
||||||
{page}
|
{page}
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{totalPages > 5 && (
|
{totalPages > 5 && (
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
<PaginationEllipsis />
|
<PaginationEllipsis />
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
<PaginationNext
|
<PaginationNext
|
||||||
href={
|
href={
|
||||||
currentPage < totalPages ? getPageUrl(currentPage + 1) : undefined
|
currentPage < totalPages ? getPageUrl(currentPage + 1) : undefined
|
||||||
}
|
}
|
||||||
isDisabled={currentPage === totalPages}
|
isDisabled={currentPage === totalPages}
|
||||||
/>
|
/>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
</PaginationContent>
|
</PaginationContent>
|
||||||
</Pagination>
|
</Pagination>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
interface PaginationProps {
|
interface PaginationProps {
|
||||||
currentPage: number
|
currentPage: number;
|
||||||
totalPages: number
|
totalPages: number;
|
||||||
baseUrl: string
|
baseUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PaginationComponent
|
export default PaginationComponent;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Pagination,
|
Pagination,
|
||||||
PaginationContent,
|
PaginationContent,
|
||||||
PaginationLink,
|
PaginationLink,
|
||||||
PaginationItem,
|
PaginationItem,
|
||||||
PaginationPrevious,
|
PaginationPrevious,
|
||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationEllipsis,
|
PaginationEllipsis,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,56 +1,56 @@
|
||||||
import * as React from 'react'
|
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
||||||
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function ScrollArea({
|
function ScrollArea({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
||||||
return (
|
return (
|
||||||
<ScrollAreaPrimitive.Root
|
<ScrollAreaPrimitive.Root
|
||||||
data-slot="scroll-area"
|
data-slot="scroll-area"
|
||||||
className={cn('relative', className)}
|
className={cn("relative", className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ScrollAreaPrimitive.Viewport
|
<ScrollAreaPrimitive.Viewport
|
||||||
data-slot="scroll-area-viewport"
|
data-slot="scroll-area-viewport"
|
||||||
className="ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] focus-visible:ring-4 focus-visible:outline-1"
|
className="ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] focus-visible:ring-4 focus-visible:outline-1"
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ScrollAreaPrimitive.Viewport>
|
</ScrollAreaPrimitive.Viewport>
|
||||||
<ScrollBar />
|
<ScrollBar />
|
||||||
<ScrollAreaPrimitive.Corner />
|
<ScrollAreaPrimitive.Corner />
|
||||||
</ScrollAreaPrimitive.Root>
|
</ScrollAreaPrimitive.Root>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ScrollBar({
|
function ScrollBar({
|
||||||
className,
|
className,
|
||||||
orientation = 'vertical',
|
orientation = "vertical",
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
||||||
return (
|
return (
|
||||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||||
data-slot="scroll-area-scrollbar"
|
data-slot="scroll-area-scrollbar"
|
||||||
orientation={orientation}
|
orientation={orientation}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex touch-none p-px transition-colors select-none',
|
"flex touch-none p-px transition-colors select-none",
|
||||||
orientation === 'vertical' &&
|
orientation === "vertical" &&
|
||||||
'h-full w-2.5 border-l border-l-transparent',
|
"h-full w-2.5 border-l border-l-transparent",
|
||||||
orientation === 'horizontal' &&
|
orientation === "horizontal" &&
|
||||||
'h-2.5 flex-col border-t border-t-transparent',
|
"h-2.5 flex-col border-t border-t-transparent",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ScrollAreaPrimitive.ScrollAreaThumb
|
<ScrollAreaPrimitive.ScrollAreaThumb
|
||||||
data-slot="scroll-area-thumb"
|
data-slot="scroll-area-thumb"
|
||||||
className="bg-border relative flex-1 rounded-full"
|
className="bg-border relative flex-1 rounded-full"
|
||||||
/>
|
/>
|
||||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ScrollArea, ScrollBar }
|
export { ScrollArea, ScrollBar };
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import * as React from 'react'
|
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
||||||
import * as SeparatorPrimitive from '@radix-ui/react-separator'
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Separator({
|
function Separator({
|
||||||
className,
|
className,
|
||||||
orientation = 'horizontal',
|
orientation = "horizontal",
|
||||||
decorative = true,
|
decorative = true,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
||||||
return (
|
return (
|
||||||
<SeparatorPrimitive.Root
|
<SeparatorPrimitive.Root
|
||||||
data-slot="separator-root"
|
data-slot="separator-root"
|
||||||
decorative={decorative}
|
decorative={decorative}
|
||||||
orientation={orientation}
|
orientation={orientation}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
|
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Separator }
|
export { Separator };
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { glob } from 'astro/loaders'
|
import { defineCollection, z } from "astro:content";
|
||||||
import { defineCollection, z } from 'astro:content'
|
import { glob } from "astro/loaders";
|
||||||
|
|
||||||
const blog = defineCollection({
|
const blog = defineCollection({
|
||||||
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content' }),
|
loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content" }),
|
||||||
schema: ({ image }) =>
|
schema: ({ image }) =>
|
||||||
z.object({
|
z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
date: z.coerce.date(),
|
date: z.coerce.date(),
|
||||||
image: image().optional(),
|
image: image().optional(),
|
||||||
tags: z.array(z.string()).optional(),
|
tags: z.array(z.string()).optional(),
|
||||||
authors: z.array(z.string()).optional(),
|
authors: z.array(z.string()).optional(),
|
||||||
draft: z.boolean().optional(),
|
draft: z.boolean().optional(),
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
|
|
||||||
export const collections = { blog }
|
export const collections = { blog };
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
---
|
---
|
||||||
import Footer from '@/components/Footer.astro'
|
import Footer from "@/components/Footer.astro";
|
||||||
import Head from '@/components/Head.astro'
|
import Head from "@/components/Head.astro";
|
||||||
import Header from '@/components/Header.astro'
|
import Header from "@/components/Header.astro";
|
||||||
import { SITE } from '@/consts'
|
import { SITE } from "@/consts";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string
|
title: string;
|
||||||
description: string
|
description: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const { title, description } = Astro.props
|
const { title, description } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
import { getEntry } from 'astro:content'
|
import { getEntry } from "astro:content";
|
||||||
|
|
||||||
export async function parseAuthors(authors: string[]) {
|
export async function parseAuthors(authors: string[]) {
|
||||||
if (!authors || authors.length === 0) return []
|
if (!authors || authors.length === 0) return [];
|
||||||
|
|
||||||
const parseAuthor = async (id: string) => {
|
const parseAuthor = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
const author = await getEntry('authors', id)
|
const author = await getEntry("authors", id);
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
name: author?.data?.name || id,
|
name: author?.data?.name || id,
|
||||||
avatar: author?.data?.avatar || '/static/logo.png',
|
avatar: author?.data?.avatar || "/static/logo.png",
|
||||||
isRegistered: !!author,
|
isRegistered: !!author,
|
||||||
}
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error fetching author with id ${id}:`, error)
|
console.error(`Error fetching author with id ${id}:`, error);
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
name: id,
|
name: id,
|
||||||
avatar: '/static/logo.png',
|
avatar: "/static/logo.png",
|
||||||
isRegistered: false,
|
isRegistered: false,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return await Promise.all(authors.map(parseAuthor))
|
return await Promise.all(authors.map(parseAuthor));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
import { type ClassValue, clsx } from 'clsx'
|
import { type ClassValue, clsx } from "clsx";
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatDate(date: Date) {
|
export function formatDate(date: Date) {
|
||||||
return Intl.DateTimeFormat('en-US', {
|
return Intl.DateTimeFormat("en-US", {
|
||||||
year: 'numeric',
|
year: "numeric",
|
||||||
month: 'long',
|
month: "long",
|
||||||
day: 'numeric',
|
day: "numeric",
|
||||||
}).format(date)
|
}).format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readingTime(html: string) {
|
export function readingTime(html: string) {
|
||||||
const textOnly = html.replace(/<[^>]+>/g, '')
|
const textOnly = html.replace(/<[^>]+>/g, "");
|
||||||
const wordCount = textOnly.split(/\s+/).length
|
const wordCount = textOnly.split(/\s+/).length;
|
||||||
const readingTimeMinutes = (wordCount / 200 + 1).toFixed()
|
const readingTimeMinutes = (wordCount / 200 + 1).toFixed();
|
||||||
return `${readingTimeMinutes} min read`
|
return `${readingTimeMinutes} min read`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs.astro'
|
import Breadcrumbs from "@/components/Breadcrumbs.astro";
|
||||||
import Container from '@/components/Container.astro'
|
import Container from "@/components/Container.astro";
|
||||||
import Link from '@/components/Link.astro'
|
import Link from "@/components/Link.astro";
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { SITE } from '@/consts'
|
import { SITE } from "@/consts";
|
||||||
import Layout from '@/layouts/Layout.astro'
|
import Layout from "@/layouts/Layout.astro";
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from "@/lib/utils";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="404" description={SITE.description}>
|
<Layout title="404" description={SITE.description}>
|
||||||
|
|
|
@ -1,37 +1,39 @@
|
||||||
---
|
---
|
||||||
import BlogCard from '@/components/BlogCard.astro'
|
import { type CollectionEntry, getCollection } from "astro:content";
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs.astro'
|
import BlogCard from "@/components/BlogCard.astro";
|
||||||
import Container from '@/components/Container.astro'
|
import Breadcrumbs from "@/components/Breadcrumbs.astro";
|
||||||
import PaginationComponent from '@/components/ui/pagination'
|
import Container from "@/components/Container.astro";
|
||||||
import { SITE } from '@/consts'
|
import PaginationComponent from "@/components/ui/pagination";
|
||||||
import Layout from '@/layouts/Layout.astro'
|
import { SITE } from "@/consts";
|
||||||
import type { PaginateFunction } from 'astro'
|
import Layout from "@/layouts/Layout.astro";
|
||||||
import { type CollectionEntry, getCollection } from 'astro:content'
|
import type { PaginateFunction } from "astro";
|
||||||
|
|
||||||
export async function getStaticPaths({
|
export async function getStaticPaths({
|
||||||
paginate,
|
paginate,
|
||||||
}: {
|
}: {
|
||||||
paginate: PaginateFunction
|
paginate: PaginateFunction;
|
||||||
}) {
|
}) {
|
||||||
const allPosts = await getCollection('blog', ({ data }) => !data.draft)
|
const allPosts = await getCollection("blog", ({ data }) => !data.draft);
|
||||||
return paginate(
|
return paginate(
|
||||||
allPosts.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf()),
|
allPosts.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf()),
|
||||||
{ pageSize: SITE.postsPerPage },
|
{ pageSize: SITE.postsPerPage },
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { page } = Astro.props
|
const { page } = Astro.props;
|
||||||
|
|
||||||
const postsByYear = page.data.reduce(
|
const postsByYear = page.data.reduce(
|
||||||
(acc: Record<string, CollectionEntry<'blog'>[]>, post) => {
|
(acc: Record<string, CollectionEntry<"blog">[]>, post) => {
|
||||||
const year = post.data.date.getFullYear().toString()
|
const year = post.data.date.getFullYear().toString();
|
||||||
;(acc[year] ??= []).push(post)
|
(acc[year] ??= []).push(post);
|
||||||
return acc
|
return acc;
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
)
|
);
|
||||||
|
|
||||||
const years = Object.keys(postsByYear).sort((a, b) => parseInt(b) - parseInt(a))
|
const years = Object.keys(postsByYear).sort(
|
||||||
|
(a, b) => Number.parseInt(b) - Number.parseInt(a),
|
||||||
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Blog" description="Blog">
|
<Layout title="Blog" description="Blog">
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
---
|
---
|
||||||
import BlogCard from '@/components/BlogCard.astro'
|
import { getCollection } from "astro:content";
|
||||||
import Container from '@/components/Container.astro'
|
import BlogCard from "@/components/BlogCard.astro";
|
||||||
import Link from '@/components/Link.astro'
|
import Container from "@/components/Container.astro";
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
import Link from "@/components/Link.astro";
|
||||||
import { SITE } from '@/consts'
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import Layout from '@/layouts/Layout.astro'
|
import { SITE } from "@/consts";
|
||||||
import { getCollection } from 'astro:content'
|
import Layout from "@/layouts/Layout.astro";
|
||||||
|
|
||||||
const blog = (await getCollection('blog'))
|
const blog = (await getCollection("blog"))
|
||||||
.filter((post) => !post.data.draft)
|
.filter((post) => !post.data.draft)
|
||||||
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
|
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
|
||||||
.slice(0, SITE.featuredPostCount)
|
.slice(0, SITE.featuredPostCount);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Home" description={SITE.description}>
|
<Layout title="Home" description={SITE.description}>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { APIRoute } from 'astro'
|
import type { APIRoute } from "astro";
|
||||||
|
|
||||||
const getRobotsTxt = (sitemapURL: URL) => `
|
const getRobotsTxt = (sitemapURL: URL) => `
|
||||||
User-agent: AI2Bot
|
User-agent: AI2Bot
|
||||||
|
@ -49,9 +49,9 @@ User-agent: YouBot
|
||||||
Disallow: /
|
Disallow: /
|
||||||
|
|
||||||
Sitemap: ${sitemapURL.href}
|
Sitemap: ${sitemapURL.href}
|
||||||
`
|
`;
|
||||||
|
|
||||||
export const GET: APIRoute = ({ site }) => {
|
export const GET: APIRoute = ({ site }) => {
|
||||||
const sitemapURL = new URL('sitemap-index.xml', site)
|
const sitemapURL = new URL("sitemap-index.xml", site);
|
||||||
return new Response(getRobotsTxt(sitemapURL))
|
return new Response(getRobotsTxt(sitemapURL));
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import { SITE } from '@/consts'
|
import { getCollection } from "astro:content";
|
||||||
import rss from '@astrojs/rss'
|
import { SITE } from "@/consts";
|
||||||
import type { APIContext } from 'astro'
|
import rss from "@astrojs/rss";
|
||||||
import { getCollection } from 'astro:content'
|
import type { APIContext } from "astro";
|
||||||
|
|
||||||
export async function GET(context: APIContext) {
|
export async function GET(context: APIContext) {
|
||||||
try {
|
try {
|
||||||
const posts = await getCollection('blog', ({ data }) => !data.draft)
|
const posts = await getCollection("blog", ({ data }) => !data.draft);
|
||||||
posts.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
|
posts.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
|
||||||
|
|
||||||
return rss({
|
return rss({
|
||||||
title: SITE.title,
|
title: SITE.title,
|
||||||
description: SITE.description,
|
description: SITE.description,
|
||||||
site: context.site ?? SITE.href,
|
site: context.site ?? SITE.href,
|
||||||
items: posts.map((post) => ({
|
items: posts.map((post) => ({
|
||||||
title: post.data.title,
|
title: post.data.title,
|
||||||
description: post.data.description,
|
description: post.data.description,
|
||||||
pubDate: post.data.date,
|
pubDate: post.data.date,
|
||||||
link: `/blog/${post.id}/`,
|
link: `/blog/${post.id}/`,
|
||||||
})),
|
})),
|
||||||
})
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error generating RSS feed:', error)
|
console.error("Error generating RSS feed:", error);
|
||||||
return new Response('Error generating RSS feed', { status: 500 })
|
return new Response("Error generating RSS feed", { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,386 +1,397 @@
|
||||||
@import 'tailwindcss';
|
@import "tailwindcss";
|
||||||
|
|
||||||
[data-callout] {
|
[data-callout] {
|
||||||
& {
|
& {
|
||||||
@apply my-6 space-y-2 rounded-lg border border-blue-600/20 bg-blue-400/20 p-4 pb-5 dark:border-blue-800/20 dark:bg-blue-600/10;
|
@apply my-6 space-y-2 rounded-lg border border-blue-600/20 bg-blue-400/20 p-4 pb-5 dark:border-blue-800/20 dark:bg-blue-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply flex flex-row items-start gap-2 p-0 font-bold text-blue-500;
|
@apply flex flex-row items-start gap-2 p-0 font-bold text-blue-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not:only-child {
|
&:not:only-child {
|
||||||
@apply mb-2;
|
@apply mb-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:empty::after {
|
&:empty::after {
|
||||||
content: "Note";
|
content: "Note";
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
@apply mt-1 block h-5 w-5 bg-current content-[""];
|
@apply mt-1 block h-5 w-5 bg-current content-[""];
|
||||||
mask-repeat: no-repeat;
|
mask-repeat: no-repeat;
|
||||||
mask-size: cover;
|
mask-size: cover;
|
||||||
|
|
||||||
/* lucide-pencil */
|
/* lucide-pencil */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTE3IDNhMi44NSAyLjgzIDAgMSAxIDQgNEw3LjUgMjAuNUwyIDIybDEuNS01LjVabS0yIDJsNCA0Ii8+PC9zdmc+");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTE3IDNhMi44NSAyLjgzIDAgMSAxIDQgNEw3LjUgMjAuNUwyIDIybDEuNS01LjVabS0yIDJsNCA0Ii8+PC9zdmc+");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-body] {
|
& > [data-callout-body] {
|
||||||
& {
|
& {
|
||||||
@apply space-y-2;
|
@apply space-y-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
@apply m-0;
|
@apply m-0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
details[data-callout] > summary[data-callout-title] {
|
details[data-callout] > summary[data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply cursor-pointer;
|
@apply cursor-pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
@apply w-full bg-right bg-no-repeat;
|
@apply w-full bg-right bg-no-repeat;
|
||||||
content: "";
|
content: "";
|
||||||
|
|
||||||
/* lucide:chevron-right */
|
/* lucide:chevron-right */
|
||||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Im05IDE4bDYtNmwtNi02Ii8+PC9zdmc+");
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Im05IDE4bDYtNmwtNi02Ii8+PC9zdmc+");
|
||||||
background-size: 1.5rem;
|
background-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:empty)::after {
|
&:not(:empty)::after {
|
||||||
@apply my-auto ml-auto h-6 w-6;
|
@apply my-auto ml-auto h-6 w-6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
details[data-callout][open] > summary[data-callout-title]::after {
|
details[data-callout][open] > summary[data-callout-title]::after {
|
||||||
/* lucide:chevron-down */
|
/* lucide:chevron-down */
|
||||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Im02IDlsNiA2bDYtNiIvPjwvc3ZnPg==");
|
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Im02IDlsNiA2bDYtNiIvPjwvc3ZnPg==");
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="info"] {
|
[data-callout][data-callout-type="info"] {
|
||||||
& {
|
& {
|
||||||
@apply border-blue-600/20 bg-blue-400/20 dark:border-blue-800/20 dark:bg-blue-600/10;
|
@apply border-blue-600/20 bg-blue-400/20 dark:border-blue-800/20 dark:bg-blue-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-blue-500;
|
@apply text-blue-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:empty::after {
|
&:empty::after {
|
||||||
content: "Info";
|
content: "Info";
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:info */
|
/* lucide:info */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIi8+PHBhdGggZD0iTTEyIDE2di00bTAtNGguMDEiLz48L2c+PC9zdmc+");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIi8+PHBhdGggZD0iTTEyIDE2di00bTAtNGguMDEiLz48L2c+PC9zdmc+");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="todo"] {
|
[data-callout][data-callout-type="todo"] {
|
||||||
& {
|
& {
|
||||||
@apply border-blue-600/20 bg-blue-400/20 dark:border-blue-800/20 dark:bg-blue-600/10;
|
@apply border-blue-600/20 bg-blue-400/20 dark:border-blue-800/20 dark:bg-blue-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-blue-500;
|
@apply text-blue-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:empty::after {
|
&:empty::after {
|
||||||
content: "ToDo";
|
content: "ToDo";
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:circle-check-big */
|
/* lucide:circle-check-big */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiPjxwYXRoIGQ9Ik0yMiAxMS4wOFYxMmExMCAxMCAwIDEgMS01LjkzLTkuMTQiLz48cGF0aCBkPSJtOSAxMWwzIDNMMjIgNCIvPjwvZz48L3N2Zz4=");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzg4ODg4OCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiPjxwYXRoIGQ9Ik0yMiAxMS4wOFYxMmExMCAxMCAwIDEgMS01LjkzLTkuMTQiLz48cGF0aCBkPSJtOSAxMWwzIDNMMjIgNCIvPjwvZz48L3N2Zz4=");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="abstract"],
|
[data-callout][data-callout-type="abstract"],
|
||||||
[data-callout][data-callout-type="summary"],
|
[data-callout][data-callout-type="summary"],
|
||||||
[data-callout][data-callout-type="tldr"] {
|
[data-callout][data-callout-type="tldr"] {
|
||||||
& {
|
& {
|
||||||
@apply border-cyan-600/20 bg-cyan-400/20 dark:border-cyan-800/20 dark:bg-cyan-600/10;
|
@apply border-cyan-600/20 bg-cyan-400/20 dark:border-cyan-800/20 dark:bg-cyan-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-cyan-500;
|
@apply text-cyan-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:clipboard-list */
|
/* lucide:clipboard-list */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiI+PHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIi8+PHBhdGggZD0iTTE2IDRoMmEyIDIgMCAwIDEgMiAydjE0YTIgMiAwIDAgMS0yIDJINmEyIDIgMCAwIDEtMi0yVjZhMiAyIDAgMCAxIDItMmgybTQgN2g0bS00IDVoNG0tOC01aC4wMU04IDE2aC4wMSIvPjwvZz48L3N2Zz4=");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiI+PHJlY3Qgd2lkdGg9IjgiIGhlaWdodD0iNCIgeD0iOCIgeT0iMiIgcng9IjEiIHJ5PSIxIi8+PHBhdGggZD0iTTE2IDRoMmEyIDIgMCAwIDEgMiAydjE0YTIgMiAwIDAgMS0yIDJINmEyIDIgMCAwIDEtMi0yVjZhMiAyIDAgMCAxIDItMmgybTQgN2g0bS00IDVoNG0tOC01aC4wMU04IDE2aC4wMSIvPjwvZz48L3N2Zz4=");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="abstract"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="abstract"]
|
||||||
content: "Abstract";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Abstract";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="summary"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="summary"]
|
||||||
content: "Summary";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Summary";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="tldr"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="tldr"] > [data-callout-title]:empty::after {
|
||||||
content: "TL;DR";
|
content: "TL;DR";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="tip"],
|
[data-callout][data-callout-type="tip"],
|
||||||
[data-callout][data-callout-type="hint"],
|
[data-callout][data-callout-type="hint"],
|
||||||
[data-callout][data-callout-type="important"] {
|
[data-callout][data-callout-type="important"] {
|
||||||
& {
|
& {
|
||||||
@apply border-cyan-600/20 bg-cyan-400/20 dark:border-cyan-800/20 dark:bg-cyan-600/10;
|
@apply border-cyan-600/20 bg-cyan-400/20 dark:border-cyan-800/20 dark:bg-cyan-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-cyan-500;
|
@apply text-cyan-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:flame */
|
/* lucide:flame */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTguNSAxNC41QTIuNSAyLjUgMCAwIDAgMTEgMTJjMC0xLjM4LS41LTItMS0zYy0xLjA3Mi0yLjE0My0uMjI0LTQuMDU0IDItNmMuNSAyLjUgMiA0LjkgNCA2LjVjMiAxLjYgMyAzLjUgMyA1LjVhNyA3IDAgMSAxLTE0IDBjMC0xLjE1My40MzMtMi4yOTQgMS0zYTIuNSAyLjUgMCAwIDAgMi41IDIuNSIvPjwvc3ZnPg==");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTguNSAxNC41QTIuNSAyLjUgMCAwIDAgMTEgMTJjMC0xLjM4LS41LTItMS0zYy0xLjA3Mi0yLjE0My0uMjI0LTQuMDU0IDItNmMuNSAyLjUgMiA0LjkgNCA2LjVjMiAxLjYgMyAzLjUgMyA1LjVhNyA3IDAgMSAxLTE0IDBjMC0xLjE1My40MzMtMi4yOTQgMS0zYTIuNSAyLjUgMCAwIDAgMi41IDIuNSIvPjwvc3ZnPg==");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="tip"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="tip"] > [data-callout-title]:empty::after {
|
||||||
content: "Tip";
|
content: "Tip";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="hint"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="hint"] > [data-callout-title]:empty::after {
|
||||||
content: "Hint";
|
content: "Hint";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="important"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="important"]
|
||||||
content: "Important";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Important";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="success"],
|
[data-callout][data-callout-type="success"],
|
||||||
[data-callout][data-callout-type="check"],
|
[data-callout][data-callout-type="check"],
|
||||||
[data-callout][data-callout-type="done"] {
|
[data-callout][data-callout-type="done"] {
|
||||||
& {
|
& {
|
||||||
@apply border-green-600/20 bg-green-400/20 dark:border-green-800/20 dark:bg-green-600/10;
|
@apply border-green-600/20 bg-green-400/20 dark:border-green-800/20 dark:bg-green-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-green-500;
|
@apply text-green-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:check */
|
/* lucide:check */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTIwIDZMOSAxN2wtNS01Ii8+PC9zdmc+");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTIwIDZMOSAxN2wtNS01Ii8+PC9zdmc+");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="success"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="success"]
|
||||||
content: "Success";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Success";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="check"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="check"] > [data-callout-title]:empty::after {
|
||||||
content: "Check";
|
content: "Check";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="done"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="done"] > [data-callout-title]:empty::after {
|
||||||
content: "Done";
|
content: "Done";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="question"],
|
[data-callout][data-callout-type="question"],
|
||||||
[data-callout][data-callout-type="help"],
|
[data-callout][data-callout-type="help"],
|
||||||
[data-callout][data-callout-type="faq"] {
|
[data-callout][data-callout-type="faq"] {
|
||||||
& {
|
& {
|
||||||
@apply border-orange-600/20 bg-orange-400/20 dark:border-orange-800/20 dark:bg-orange-600/10;
|
@apply border-orange-600/20 bg-orange-400/20 dark:border-orange-800/20 dark:bg-orange-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-orange-500;
|
@apply text-orange-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:circle-help */
|
/* lucide:circle-help */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48cGF0aCBkPSJNOS4wOSA5YTMgMyAwIDAgMSA1LjgzIDFjMCAyLTMgMy0zIDNtLjA4IDRoLjAxIi8+PC9nPjwvc3ZnPg==");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiI+PGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiLz48cGF0aCBkPSJNOS4wOSA5YTMgMyAwIDAgMSA1LjgzIDFjMCAyLTMgMy0zIDNtLjA4IDRoLjAxIi8+PC9nPjwvc3ZnPg==");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="question"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="question"]
|
||||||
content: "Question";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Question";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="help"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="help"] > [data-callout-title]:empty::after {
|
||||||
content: "Help";
|
content: "Help";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="faq"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="faq"] > [data-callout-title]:empty::after {
|
||||||
content: "FAQ";
|
content: "FAQ";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="warning"],
|
[data-callout][data-callout-type="warning"],
|
||||||
[data-callout][data-callout-type="caution"],
|
[data-callout][data-callout-type="caution"],
|
||||||
[data-callout][data-callout-type="attention"] {
|
[data-callout][data-callout-type="attention"] {
|
||||||
& {
|
& {
|
||||||
@apply border-orange-600/20 bg-orange-400/20 dark:border-orange-800/20 dark:bg-orange-600/10;
|
@apply border-orange-600/20 bg-orange-400/20 dark:border-orange-800/20 dark:bg-orange-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-orange-500;
|
@apply text-orange-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:triangle-alert */
|
/* lucide:triangle-alert */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0ibTIxLjczIDE4bC04LTE0YTIgMiAwIDAgMC0zLjQ4IDBsLTggMTRBMiAyIDAgMCAwIDQgMjFoMTZhMiAyIDAgMCAwIDEuNzMtM00xMiA5djRtMCA0aC4wMSIvPjwvc3ZnPg==");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0ibTIxLjczIDE4bC04LTE0YTIgMiAwIDAgMC0zLjQ4IDBsLTggMTRBMiAyIDAgMCAwIDQgMjFoMTZhMiAyIDAgMCAwIDEuNzMtM00xMiA5djRtMCA0aC4wMSIvPjwvc3ZnPg==");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="warning"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="warning"]
|
||||||
content: "Warning";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Warning";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="caution"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="caution"]
|
||||||
content: "Caution";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Caution";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="attention"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="attention"]
|
||||||
content: "Attention";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Attention";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="failure"],
|
[data-callout][data-callout-type="failure"],
|
||||||
[data-callout][data-callout-type="fail"],
|
[data-callout][data-callout-type="fail"],
|
||||||
[data-callout][data-callout-type="missing"] {
|
[data-callout][data-callout-type="missing"] {
|
||||||
& {
|
& {
|
||||||
@apply border-red-600/20 bg-red-400/20 dark:border-red-800/20 dark:bg-red-600/10;
|
@apply border-red-600/20 bg-red-400/20 dark:border-red-800/20 dark:bg-red-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-red-500;
|
@apply text-red-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:check */
|
/* lucide:check */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTIwIDZMOSAxN2wtNS01Ii8+PC9zdmc+");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTIwIDZMOSAxN2wtNS01Ii8+PC9zdmc+");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="failure"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="failure"]
|
||||||
content: "Failure";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Failure";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="fail"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="fail"] > [data-callout-title]:empty::after {
|
||||||
content: "Fail";
|
content: "Fail";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="missing"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="missing"]
|
||||||
content: "Missing";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Missing";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="danger"],
|
[data-callout][data-callout-type="danger"],
|
||||||
[data-callout][data-callout-type="error"] {
|
[data-callout][data-callout-type="error"] {
|
||||||
& {
|
& {
|
||||||
@apply border-red-600/20 bg-red-400/20 dark:border-red-800/20 dark:bg-red-600/10;
|
@apply border-red-600/20 bg-red-400/20 dark:border-red-800/20 dark:bg-red-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-red-500;
|
@apply text-red-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:zap */
|
/* lucide:zap */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXphcCI+PHBhdGggZD0iTTQgMTRhMSAxIDAgMCAxLS43OC0xLjYzbDkuOS0xMC4yYS41LjUgMCAwIDEgLjg2LjQ2bC0xLjkyIDYuMDJBMSAxIDAgMCAwIDEzIDEwaDdhMSAxIDAgMCAxIC43OCAxLjYzbC05LjkgMTAuMmEuNS41IDAgMCAxLS44Ni0uNDZsMS45Mi02LjAyQTEgMSAwIDAgMCAxMSAxNHoiLz48L3N2Zz4=");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXphcCI+PHBhdGggZD0iTTQgMTRhMSAxIDAgMCAxLS43OC0xLjYzbDkuOS0xMC4yYS41LjUgMCAwIDEgLjg2LjQ2bC0xLjkyIDYuMDJBMSAxIDAgMCAwIDEzIDEwaDdhMSAxIDAgMCAxIC43OCAxLjYzbC05LjkgMTAuMmEuNS41IDAgMCAxLS44Ni0uNDZsMS45Mi02LjAyQTEgMSAwIDAgMCAxMSAxNHoiLz48L3N2Zz4=");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="danger"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="danger"] > [data-callout-title]:empty::after {
|
||||||
content: "Danger";
|
content: "Danger";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="error"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="error"] > [data-callout-title]:empty::after {
|
||||||
content: "Error";
|
content: "Error";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="bug"] {
|
[data-callout][data-callout-type="bug"] {
|
||||||
& {
|
& {
|
||||||
@apply border-red-600/20 bg-red-400/20 dark:border-red-800/20 dark:bg-red-600/10;
|
@apply border-red-600/20 bg-red-400/20 dark:border-red-800/20 dark:bg-red-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-red-500;
|
@apply text-red-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:bug */
|
/* lucide:bug */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiI+PHBhdGggZD0ibTggMmwxLjg4IDEuODhtNC4yNCAwTDE2IDJNOSA3LjEzdi0xYTMuMDAzIDMuMDAzIDAgMSAxIDYgMHYxIi8+PHBhdGggZD0iTTEyIDIwYy0zLjMgMC02LTIuNy02LTZ2LTNhNCA0IDAgMCAxIDQtNGg0YTQgNCAwIDAgMSA0IDR2M2MwIDMuMy0yLjcgNi02IDZtMCAwdi05Ii8+PHBhdGggZD0iTTYuNTMgOUM0LjYgOC44IDMgNy4xIDMgNW0zIDhIMm0xIDhjMC0yLjEgMS43LTMuOSAzLjgtNE0yMC45NyA1YzAgMi4xLTEuNiAzLjgtMy41IDRNMjIgMTNoLTRtLS44IDRjMi4xLjEgMy44IDEuOSAzLjggNCIvPjwvZz48L3N2Zz4=");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiI+PHBhdGggZD0ibTggMmwxLjg4IDEuODhtNC4yNCAwTDE2IDJNOSA3LjEzdi0xYTMuMDAzIDMuMDAzIDAgMSAxIDYgMHYxIi8+PHBhdGggZD0iTTEyIDIwYy0zLjMgMC02LTIuNy02LTZ2LTNhNCA0IDAgMCAxIDQtNGg0YTQgNCAwIDAgMSA0IDR2M2MwIDMuMy0yLjcgNi02IDZtMCAwdi05Ii8+PHBhdGggZD0iTTYuNTMgOUM0LjYgOC44IDMgNy4xIDMgNW0zIDhIMm0xIDhjMC0yLjEgMS43LTMuOSAzLjgtNE0yMC45NyA1YzAgMi4xLTEuNiAzLjgtMy41IDRNMjIgMTNoLTRtLS44IDRjMi4xLjEgMy44IDEuOSAzLjggNCIvPjwvZz48L3N2Zz4=");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="bug"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="bug"] > [data-callout-title]:empty::after {
|
||||||
content: "Bug";
|
content: "Bug";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="example"] {
|
[data-callout][data-callout-type="example"] {
|
||||||
& {
|
& {
|
||||||
@apply border-purple-600/20 bg-purple-400/20 dark:border-purple-800/20 dark:bg-purple-600/10;
|
@apply border-purple-600/20 bg-purple-400/20 dark:border-purple-800/20 dark:bg-purple-600/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-purple-500;
|
@apply text-purple-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:list */
|
/* lucide:list */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTggNmgxM004IDEyaDEzTTggMThoMTNNMyA2aC4wMU0zIDEyaC4wMU0zIDE4aC4wMSIvPjwvc3ZnPg==");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTggNmgxM004IDEyaDEzTTggMThoMTNNMyA2aC4wMU0zIDEyaC4wMU0zIDE4aC4wMSIvPjwvc3ZnPg==");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="example"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="example"]
|
||||||
content: "Example";
|
> [data-callout-title]:empty::after {
|
||||||
|
content: "Example";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="quote"],
|
[data-callout][data-callout-type="quote"],
|
||||||
[data-callout][data-callout-type="cite"] {
|
[data-callout][data-callout-type="cite"] {
|
||||||
& {
|
& {
|
||||||
@apply border-zinc-600/20 bg-zinc-400/20 dark:border-zinc-800/20 dark:bg-zinc-600/15;
|
@apply border-zinc-600/20 bg-zinc-400/20 dark:border-zinc-800/20 dark:bg-zinc-600/15;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > [data-callout-title] {
|
& > [data-callout-title] {
|
||||||
& {
|
& {
|
||||||
@apply text-zinc-500;
|
@apply text-zinc-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* lucide:quote */
|
/* lucide:quote */
|
||||||
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTMgMjFjMyAwIDctMSA3LThWNWMwLTEuMjUtLjc1Ni0yLjAxNy0yLTJINGMtMS4yNSAwLTIgLjc1LTIgMS45NzJWMTFjMCAxLjI1Ljc1IDIgMiAyYzEgMCAxIDAgMSAxdjFjMCAxLTEgMi0yIDJzLTEgLjAwOC0xIDEuMDMxVjIwYzAgMSAwIDEgMSAxbTEyIDBjMyAwIDctMSA3LThWNWMwLTEuMjUtLjc1Ny0yLjAxNy0yLTJoLTRjLTEuMjUgMC0yIC43NS0yIDEuOTcyVjExYzAgMS4yNS43NSAyIDIgMmguNzVjMCAyLjI1LjI1IDQtMi43NSA0djNjMCAxIDAgMSAxIDEiLz48L3N2Zz4=");
|
mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTMgMjFjMyAwIDctMSA3LThWNWMwLTEuMjUtLjc1Ni0yLjAxNy0yLTJINGMtMS4yNSAwLTIgLjc1LTIgMS45NzJWMTFjMCAxLjI1Ljc1IDIgMiAyYzEgMCAxIDAgMSAxdjFjMCAxLTEgMi0yIDJzLTEgLjAwOC0xIDEuMDMxVjIwYzAgMSAwIDEgMSAxbTEyIDBjMyAwIDctMSA3LThWNWMwLTEuMjUtLjc1Ny0yLjAxNy0yLTJoLTRjLTEuMjUgMC0yIC43NS0yIDEuOTcyVjExYzAgMS4yNS43NSAyIDIgMmguNzVjMCAyLjI1LjI1IDQtMi43NSA0djNjMCAxIDAgMSAxIDEiLz48L3N2Zz4=");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="quote"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="quote"] > [data-callout-title]:empty::after {
|
||||||
content: "Quote";
|
content: "Quote";
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-callout][data-callout-type="cite"] > [data-callout-title]:empty::after {
|
[data-callout][data-callout-type="cite"] > [data-callout-title]:empty::after {
|
||||||
content: "Cite";
|
content: "Cite";
|
||||||
}
|
}
|
|
@ -1,91 +1,93 @@
|
||||||
@import 'tailwindcss';
|
@import "tailwindcss";
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--font-sans: 'Geist Variable', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
--font-sans: "Geist Variable", ui-sans-serif, system-ui, sans-serif,
|
||||||
--font-mono: "Geist Mono Variable", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
--font-mono: "Geist Mono Variable", ui-monospace, SFMono-Regular, Menlo,
|
||||||
|
Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
|
|
||||||
--color-primary: var(--primary);
|
--color-primary: var(--primary);
|
||||||
--color-primary-foreground: var(--primary-foreground);
|
--color-primary-foreground: var(--primary-foreground);
|
||||||
|
|
||||||
--color-secondary: var(--secondary);
|
--color-secondary: var(--secondary);
|
||||||
--color-secondary-foreground: var(--secondary-foreground);
|
--color-secondary-foreground: var(--secondary-foreground);
|
||||||
|
|
||||||
--color-muted: var(--muted);
|
--color-muted: var(--muted);
|
||||||
--color-muted-foreground: var(--muted-foreground);
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
|
|
||||||
--color-accent: var(--accent);
|
--color-accent: var(--accent);
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
|
|
||||||
--color-additive: var(--additive);
|
--color-additive: var(--additive);
|
||||||
--color-additive-foreground: var(--additive-foreground);
|
--color-additive-foreground: var(--additive-foreground);
|
||||||
|
|
||||||
--color-destructive: var(--destructive);
|
--color-destructive: var(--destructive);
|
||||||
--color-destructive-foreground: var(--destructive-foreground);
|
--color-destructive-foreground: var(--destructive-foreground);
|
||||||
|
|
||||||
--color-border: var(--border);
|
--color-border: var(--border);
|
||||||
--color-ring: var(--ring);
|
--color-ring: var(--ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--background: oklch(1 0 0);
|
--background: oklch(1 0 0);
|
||||||
--foreground: oklch(0.145 0 0);
|
--foreground: oklch(0.145 0 0);
|
||||||
--primary: oklch(0.205 0 0);
|
--primary: oklch(0.205 0 0);
|
||||||
--primary-foreground: oklch(0.985 0 0);
|
--primary-foreground: oklch(0.985 0 0);
|
||||||
--secondary: oklch(0.97 0 0);
|
--secondary: oklch(0.97 0 0);
|
||||||
--secondary-foreground: oklch(0.205 0 0);
|
--secondary-foreground: oklch(0.205 0 0);
|
||||||
--muted: oklch(0.97 0 0);
|
--muted: oklch(0.97 0 0);
|
||||||
--muted-foreground: oklch(0.556 0 0);
|
--muted-foreground: oklch(0.556 0 0);
|
||||||
--accent: oklch(0.97 0 0);
|
--accent: oklch(0.97 0 0);
|
||||||
--accent-foreground: oklch(0.205 0 0);
|
--accent-foreground: oklch(0.205 0 0);
|
||||||
--destructive: oklch(0.577 0.245 27.325);
|
--destructive: oklch(0.577 0.245 27.325);
|
||||||
--border: oklch(0.922 0 0);
|
--border: oklch(0.922 0 0);
|
||||||
--ring: oklch(0.708 0 0);
|
--ring: oklch(0.708 0 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--background: oklch(0.145 0 0);
|
--background: oklch(0.145 0 0);
|
||||||
--foreground: oklch(0.985 0 0);
|
--foreground: oklch(0.985 0 0);
|
||||||
--primary: oklch(0.922 0 0);
|
--primary: oklch(0.922 0 0);
|
||||||
--primary-foreground: oklch(0.205 0 0);
|
--primary-foreground: oklch(0.205 0 0);
|
||||||
--secondary: oklch(0.269 0 0);
|
--secondary: oklch(0.269 0 0);
|
||||||
--secondary-foreground: oklch(0.985 0 0);
|
--secondary-foreground: oklch(0.985 0 0);
|
||||||
--muted: oklch(0.269 0 0);
|
--muted: oklch(0.269 0 0);
|
||||||
--muted-foreground: oklch(0.708 0 0);
|
--muted-foreground: oklch(0.708 0 0);
|
||||||
--accent: oklch(0.269 0 0);
|
--accent: oklch(0.269 0 0);
|
||||||
--accent-foreground: oklch(0.985 0 0);
|
--accent-foreground: oklch(0.985 0 0);
|
||||||
--destructive: oklch(0.704 0.191 22.216);
|
--destructive: oklch(0.704 0.191 22.216);
|
||||||
--border: oklch(1 0 0 / 10%);
|
--border: oklch(1 0 0 / 10%);
|
||||||
--ring: oklch(0.556 0 0);
|
--ring: oklch(0.556 0 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
*,
|
*,
|
||||||
::after,
|
::after,
|
||||||
::before,
|
::before,
|
||||||
::backdrop,
|
::backdrop,
|
||||||
::file-selector-button {
|
::file-selector-button {
|
||||||
@apply border-border outline-ring/50 tracking-tight;
|
@apply border-border outline-ring/50 tracking-tight;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@apply bg-background text-foreground scheme-light;
|
@apply bg-background text-foreground scheme-light;
|
||||||
|
|
||||||
&.dark {
|
&.dark {
|
||||||
@apply scheme-dark;
|
@apply scheme-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-corner {
|
::-webkit-scrollbar-corner {
|
||||||
@apply bg-transparent;
|
@apply bg-transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.disable-transitions,
|
.disable-transitions,
|
||||||
.disable-transitions * {
|
.disable-transitions * {
|
||||||
@apply transition-none!;
|
@apply transition-none!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
src/types.ts
22
src/types.ts
|
@ -1,16 +1,16 @@
|
||||||
export type Site = {
|
export type Site = {
|
||||||
title: string
|
title: string;
|
||||||
description: string
|
description: string;
|
||||||
href: string
|
href: string;
|
||||||
featuredPostCount: number
|
featuredPostCount: number;
|
||||||
postsPerPage: number
|
postsPerPage: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type SocialLink = {
|
export type SocialLink = {
|
||||||
href: string
|
href: string;
|
||||||
label: string
|
label: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type IconMap = {
|
export type IconMap = {
|
||||||
[key: string]: string
|
[key: string]: string;
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"extends": "astro/tsconfigs/strict",
|
"extends": "astro/tsconfigs/strict",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
},
|
},
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "react"
|
"jsxImportSource": "react"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue