Added Callout Component
This commit is contained in:
144
src/components/Content/Callout/Callout.module.css
Normal file
144
src/components/Content/Callout/Callout.module.css
Normal file
@@ -0,0 +1,144 @@
|
||||
@layer component {
|
||||
.container {
|
||||
--callout-bg: var(--color-surface-inverse);
|
||||
--callout-fg: var(--color-text-inverse);
|
||||
--callout-symbol: "";
|
||||
--callout-symbol-color: var(--color-text-inverse);
|
||||
|
||||
@mixin my var(--spacing-cozy);
|
||||
|
||||
position: relative;
|
||||
padding: var(--spacing-cozy) var(--spacing-cozy) var(--spacing-cozy) var(--size-12) ;
|
||||
border: var(--size-1) solid var(--color-surface-inverse);
|
||||
box-shadow: 2px 2px 0 oklch(from var(--color-surface-inverse) calc(l - 0.075) c h), 4px 4px 0 oklch(from var(--color-surface-inverse) calc(l - 0.2) c h);
|
||||
|
||||
&::before {
|
||||
@mixin pt 0.425em;
|
||||
|
||||
content: var(--callout-symbol);
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
width: var(--size-8);
|
||||
height: 100%;
|
||||
|
||||
font-size: 1.5em;
|
||||
color: var(--callout-symbol-color);
|
||||
|
||||
background-color: var(--color-surface-inverse);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
@mixin text-xl;
|
||||
|
||||
font-family: var(--font-header);
|
||||
font-weight: var(--typo-weight-black);
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
padding: 0.2em 0.5em;
|
||||
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--typo-size-xs);
|
||||
font-weight: var(--typo-weight-black);
|
||||
color: var(--callout-fg);
|
||||
|
||||
background: var(--callout-bg);
|
||||
}
|
||||
|
||||
.example {
|
||||
--callout-bg: var(--color-palette-fuchsia);
|
||||
--callout-symbol: "◆";
|
||||
}
|
||||
|
||||
.info {
|
||||
--callout-bg: var(--color-state-info);
|
||||
--callout-symbol: "‽";
|
||||
}
|
||||
|
||||
.warning {
|
||||
--callout-bg: var(--color-state-warning);
|
||||
--callout-symbol: "‼";
|
||||
}
|
||||
|
||||
.tip {
|
||||
--callout-bg: var(--color-palette-lime-green);
|
||||
--callout-symbol: "★";
|
||||
}
|
||||
|
||||
.spoiler {
|
||||
& .label {
|
||||
@mixin text-xl;
|
||||
|
||||
font-family: var(--font-header);
|
||||
font-weight: var(--typo-weight-black);
|
||||
|
||||
&::before {
|
||||
content: "[REDACTED] ";
|
||||
color: var(--color-state-error);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
& .content {
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
min-height: 3em;
|
||||
|
||||
&::after {
|
||||
content: '████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████';
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
font-family: var(--font-mono);
|
||||
line-height: inherit;
|
||||
color: var(--color-text-primary);
|
||||
letter-spacing: -0.15em;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
|
||||
background: var(--color-text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
& .toggle {
|
||||
@util hide-visually;
|
||||
|
||||
&:checked {
|
||||
& ~ .label {
|
||||
&::before {
|
||||
content: '[REVEALED] ';
|
||||
color: var(--color-state-success);
|
||||
}
|
||||
}
|
||||
|
||||
& ~ .content {
|
||||
&::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/components/Content/Callout/index.tsx
Normal file
32
src/components/Content/Callout/index.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
|
||||
import styles from './Callout.module.css';
|
||||
|
||||
interface CalloutProps {
|
||||
type: 'default' | 'example' | 'info' | 'warning' | 'tip' | 'spoiler';
|
||||
title?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function Callout({ type, title, children }: CalloutProps) {
|
||||
const isSpoiler = type === 'spoiler';
|
||||
const spoilerID = isSpoiler
|
||||
? `spoiler-${Math.random().toString(36).substr(2, 9)}`
|
||||
: undefined;
|
||||
return (
|
||||
<div className={`${styles.container} ${styles[type]}`}>
|
||||
{isSpoiler ? (
|
||||
<>
|
||||
<input type="checkbox" id={spoilerID} className={styles.toggle} />
|
||||
<label htmlFor={spoilerID} className={styles.label}>
|
||||
{title || 'Show spoiler'}
|
||||
</label>
|
||||
</>
|
||||
) : (
|
||||
<p className={styles.title}>{title}</p>
|
||||
)}
|
||||
<span className={styles.badge}>{type.toUpperCase()}</span>
|
||||
<div className={`${styles.content}`}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
.figure {
|
||||
position: relative;
|
||||
border: var(--size-2) solid var(--color-surface-inverse);
|
||||
clip-path: polygon(0 var(--size-12), var(--size-12) 0, 100% 0, 100% 100%, 0 100%);
|
||||
}
|
||||
|
||||
.caption {
|
||||
padding: var(--spacing-snug);
|
||||
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--typo-size-sm);
|
||||
line-height: var(--typo-leading-relaxed);
|
||||
color: var(--color-text-inverse);
|
||||
|
||||
background: var(--color-surface-inverse);
|
||||
}
|
||||
|
||||
.credit {
|
||||
display: block;
|
||||
|
||||
margin-top: var(--spacing-tight);
|
||||
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--typo-size-xs);
|
||||
font-style: normal;
|
||||
color: var(--color-text-inverse);
|
||||
text-align: right;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import Image from 'next/image';
|
||||
|
||||
import styles from './Figure.module.css';
|
||||
|
||||
interface FigureProps {
|
||||
src: string;
|
||||
alt: string;
|
||||
caption?: string;
|
||||
credit?: string;
|
||||
}
|
||||
|
||||
export default function Figure({ src, alt, caption, credit }: FigureProps) {
|
||||
const hasCaption = !!caption;
|
||||
const hasCredit = !!credit;
|
||||
const showFigcaption = hasCaption || hasCredit;
|
||||
|
||||
return (
|
||||
<figure className={styles.figure}>
|
||||
<Image
|
||||
src={src}
|
||||
alt={alt}
|
||||
width={800}
|
||||
height={600}
|
||||
className={styles.image}
|
||||
/>
|
||||
{showFigcaption && (
|
||||
<figcaption className={styles.caption}>
|
||||
{hasCaption && <span className={styles.text}>{caption}</span>}
|
||||
{hasCredit && <cite className={styles.credit}>[{credit}]</cite>}
|
||||
</figcaption>
|
||||
)}
|
||||
</figure>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import DefinitionItem from '@/components/Content/DefinitionList/DefinitionItem';
|
||||
import Accordion from '@/components/Content/Accordion';
|
||||
import AccordionItem from '@/components/Content/Accordion/AccordionItem';
|
||||
import Blockquote from '@/components/Content/Blockquote';
|
||||
import Figure from '@/components/Content/Figure';
|
||||
import Callout from '@/components/Content/Callout';
|
||||
|
||||
const ContentComponents = {
|
||||
Column,
|
||||
@@ -16,6 +18,8 @@ const ContentComponents = {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
Blockquote,
|
||||
Figure,
|
||||
Callout,
|
||||
};
|
||||
|
||||
export default ContentComponents;
|
||||
|
||||
Reference in New Issue
Block a user