aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/Callout.astro
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/Callout.astro')
-rw-r--r--src/components/Callout.astro183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/components/Callout.astro b/src/components/Callout.astro
new file mode 100644
index 0000000..98ef07d
--- /dev/null
+++ b/src/components/Callout.astro
@@ -0,0 +1,183 @@
+---
+import { cn } from '@/lib/utils'
+import { Icon } from 'astro-icon/components'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+const calloutConfig = {
+ note: {
+ style: 'border-blue-500 dark:bg-blue-950/5',
+ textColor: 'text-blue-700 dark:text-blue-300',
+ icon: 'lucide:info',
+ },
+ tip: {
+ style: 'border-green-500 dark:bg-green-950/5',
+ textColor: 'text-green-700 dark:text-green-300',
+ icon: 'lucide:lightbulb',
+ },
+ warning: {
+ style: 'border-amber-500 dark:bg-amber-950/5',
+ textColor: 'text-amber-700 dark:text-amber-300',
+ icon: 'lucide:alert-triangle',
+ },
+ danger: {
+ style: 'border-red-500 dark:bg-red-950/5',
+ textColor: 'text-red-700 dark:text-red-300',
+ icon: 'lucide:shield-alert',
+ },
+ important: {
+ style: 'border-purple-500 dark:bg-purple-950/5',
+ textColor: 'text-purple-700 dark:text-purple-300',
+ icon: 'lucide:message-square-warning',
+ },
+ definition: {
+ style: 'border-purple-500 dark:bg-purple-950/5',
+ textColor: 'text-purple-700 dark:text-purple-300',
+ icon: 'lucide:book-open',
+ },
+ theorem: {
+ style: 'border-teal-500 dark:bg-teal-950/5',
+ textColor: 'text-teal-700 dark:text-teal-300',
+ icon: 'lucide:check-circle',
+ },
+ lemma: {
+ style: 'border-sky-400 dark:bg-sky-950/5',
+ textColor: 'text-sky-700 dark:text-sky-300',
+ icon: 'lucide:puzzle',
+ },
+ proof: {
+ style: 'border-gray-500 dark:bg-gray-950/5',
+ textColor: 'text-gray-700 dark:text-gray-300',
+ icon: 'lucide:check-square',
+ },
+ corollary: {
+ style: 'border-cyan-500 dark:bg-cyan-950/5',
+ textColor: 'text-cyan-700 dark:text-cyan-300',
+ icon: 'lucide:git-branch',
+ },
+ proposition: {
+ style: 'border-slate-500 dark:bg-slate-950/5',
+ textColor: 'text-slate-700 dark:text-slate-300',
+ icon: 'lucide:file-text',
+ },
+ axiom: {
+ style: 'border-violet-600 dark:bg-violet-950/5',
+ textColor: 'text-violet-700 dark:text-violet-300',
+ icon: 'lucide:anchor',
+ },
+ conjecture: {
+ style: 'border-pink-500 dark:bg-pink-950/5',
+ textColor: 'text-pink-700 dark:text-pink-300',
+ icon: 'lucide:help-circle',
+ },
+ notation: {
+ style: 'border-slate-400 dark:bg-slate-950/5',
+ textColor: 'text-slate-700 dark:text-slate-300',
+ icon: 'lucide:pen-tool',
+ },
+ remark: {
+ style: 'border-gray-400 dark:bg-gray-950/5',
+ textColor: 'text-gray-700 dark:text-gray-300',
+ icon: 'lucide:message-circle',
+ },
+ intuition: {
+ style: 'border-yellow-500 dark:bg-yellow-950/5',
+ textColor: 'text-yellow-700 dark:text-yellow-300',
+ icon: 'lucide:lightbulb',
+ },
+ recall: {
+ style: 'border-blue-300 dark:bg-blue-950/5',
+ textColor: 'text-blue-600 dark:text-blue-300',
+ icon: 'lucide:rotate-ccw',
+ },
+ explanation: {
+ style: 'border-lime-500 dark:bg-lime-950/5',
+ textColor: 'text-lime-700 dark:text-lime-300',
+ icon: 'lucide:help-circle',
+ },
+ example: {
+ style: 'border-emerald-500 dark:bg-emerald-950/5',
+ textColor: 'text-emerald-700 dark:text-emerald-300',
+ icon: 'lucide:code',
+ },
+ exercise: {
+ style: 'border-indigo-500 dark:bg-indigo-950/5',
+ textColor: 'text-indigo-700 dark:text-indigo-300',
+ icon: 'lucide:dumbbell',
+ },
+ problem: {
+ style: 'border-orange-600 dark:bg-orange-950/5',
+ textColor: 'text-orange-700 dark:text-orange-300',
+ icon: 'lucide:alert-circle',
+ },
+ answer: {
+ style: 'border-teal-500 dark:bg-teal-950/5',
+ textColor: 'text-teal-700 dark:text-teal-300',
+ icon: 'lucide:check',
+ },
+ solution: {
+ style: 'border-emerald-600 dark:bg-emerald-950/5',
+ textColor: 'text-emerald-700 dark:text-emerald-300',
+ icon: 'lucide:check-circle-2',
+ },
+ summary: {
+ style: 'border-sky-500 dark:bg-sky-950/5',
+ textColor: 'text-sky-700 dark:text-sky-300',
+ icon: 'lucide:list',
+ },
+} as const
+
+const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1)
+
+const calloutVariants = cva('relative px-4 py-3 my-6 border-l-4 text-sm', {
+ variants: {
+ variant: Object.fromEntries(
+ Object.entries(calloutConfig).map(([key, config]) => [key, config.style]),
+ ),
+ },
+ defaultVariants: {
+ variant: 'note',
+ },
+})
+
+interface Props extends VariantProps<typeof calloutVariants> {
+ title?: string
+ class?: string
+ variant?: keyof typeof calloutConfig
+ defaultOpen?: boolean
+}
+
+const { title, variant = 'note', defaultOpen = true, ...rest } = Astro.props
+---
+
+<details
+ class={cn(
+ calloutVariants({ variant }),
+ rest.class,
+ '[&[open]>summary_svg:last-child]:rotate-180 [&[open]>summary]:mb-3',
+ )}
+ {...rest}
+ open={defaultOpen}
+>
+ <summary
+ class="flex cursor-pointer items-center font-medium [&::-webkit-details-marker]:hidden"
+ >
+ <Icon
+ name={calloutConfig[variant].icon}
+ class={cn('mr-2 size-4 shrink-0', calloutConfig[variant].textColor)}
+ />
+ <span class={cn('font-medium mr-2', calloutConfig[variant].textColor)}>
+ {capitalize(variant)}
+ {title && <span class="font-normal opacity-70"> ({title})</span>}
+ </span>
+ <Icon
+ name="lucide:chevron-down"
+ class={cn(
+ 'ml-auto h-4 w-4 shrink-0 transition-transform duration-200',
+ calloutConfig[variant].textColor,
+ )}
+ />
+ </summary>
+ <div>
+ <slot />
+ </div>
+</details>