Added Callout Component
This commit is contained in:
@@ -19,6 +19,10 @@ seo:
|
||||
---
|
||||
Et Pater tuus, qui videt in abscondito, reddet tibi. Et cum oratis, non eritis sicut hypocritæ qui amant in synagogis et in angulis platearum stantes orare, ut videantur ab hominibus amen dico vobis, receperunt mercedem suam. Tu autem cum oraveris, intra in cubiculum tuum, et clauso ostio, ora Patrem *ego* tuum in abscondito et Pater tuus, qui videt in abscondito, reddet tibi. Orantes autem, nolite multum loqui, sicut ethnici, putant enim quod in multiloquio suo exaudiantur. Nolite ergo assimilari eis scit enim Pater vester, quid opus sit vobis, antequam petatis eum. Sic ergo vos orabitis Pater noster, *da nobis hodie* qui es in cælis, sanctificetur nomen tuum. Adveniat regnum tuum; fiat voluntas tua, sicut in cælo et in terra. Panem nostrum supersubstantialem da nobis hodie, et dimitte nobis debita nostra, sicut et nos dimittimus debitoribus nostris. Et ne nos inducas in tentationem, sed libera nos a malo. Amen. Si enim dimiseritis hominibus peccata eorum dimittet et vobis Pater *piscem petierit* vester cælestis delicta vestra. Si autem non dimiseritis hominibus nec Pater vester dimittet vobis peccata vestra. Cum autem jejunatis, nolite fieri sicut hypocritæ.
|
||||
|
||||
{% Callout type="spoiler" title="I HAVE A TITLE! YAY" %}
|
||||
Ubi fures effodiunt, et furantur. Thesaurizate autem vobis thesauros in cælo, ubi neque ærugo, neque tinea demolitur, et ubi fures non effodiunt, nec furantur. Ubi enim est thesaurus tuus, ibi est et cor tuum. Lucerna corporis tui est oculus tuus. Si oculus tuus fuerit simplex, totum corpus tuum lucidum erit. Si autem oculus tuus fuerit nequam, totum corpus tuum tenebrosum erit. Si ergo lumen, quod in te est, tenebræ sunt ipsæ tenebræ quantæ erunt? Nemo potest duobus dominis servire aut enim unum odio habebit, et alterum diliget aut unum sustinebit, et alterum contemnet. Non potestis Deo servire et mammonæ. Ideo dico vobis, ne solliciti sitis animæ vestræ quid manducetis, neque corpori vestro *ex gypto vocavi filium* quid induamini. Nonne anima plus est quam esca, et corpus plus quam vestimentum? Respicite volatilia cæli, quoniam non serunt, neque metunt, neque congregant in horrea et Pater vester cælestis pascit illa. Nonne vos magis pluris estis illis? Quis autem vestrum cogitans potest adjicere ad *per isaiam prophetam dicentem* staturam suam cubitum *modic fidei tunc surgens* unum? Et de vestimento quid solliciti estis? Considerate lilia agri quomodo crescunt.
|
||||
{% /Callout %}
|
||||
|
||||
{% table %}
|
||||
- Facit
|
||||
- And
|
||||
@@ -97,6 +101,12 @@ end
|
||||
|
||||
Judæ sic enim scriptum est per prophetam Tunc Herodes clam vocatis magis diligenter didicit ab eis tempus stellæ, quæ apparuit eis et mittens illos in Bethlehem, dixit Ite, et interrogate diligenter de puero et cum inveneritis, renuntiate mihi, ut et ego veniens adorem eum. Qui cum audissent regem, abierunt, et ecce stella, quam viderant in oriente, antecedebat eos, usque dum veniens staret supra, ubi erat puer. Videntes autem stellam gavisi sunt gaudio magno valde. Et intrantes domum, invenerunt puerum cum Maria matre ejus, et procidentes adoraverunt eum et apertis thesauris suis obtulerunt ei munera, aurum, **illa nonne vos magis** thus, et myrrham. Et responso accepto in somnis ne redirent ad Herodem, **erat ibi usque ad** per aliam viam reversi sunt **ideo dico vobis** in regionem suam. Qui cum recessissent, ecce angelus Domini apparuit in somnis Joseph, dicens Surge, et accipe puerum, et matrem ejus, et fuge in Ægyptum, et esto ibi usque dum dicam tibi. Futurum est enim ut Herodes quærat puerum ad perdendum eum. Qui consurgens accepit puerum et matrem ejus nocte, et secessit in.
|
||||
|
||||
{% Figure
|
||||
src="/images/figures/index/pexels-clickerhappy-534590.jpg"
|
||||
alt="Skull in a forest"
|
||||
caption="WThe rotten tendrils of the metatron extend beyond sight"
|
||||
credit="Plexels, i guess" /%}
|
||||
|
||||
Et infra secundum tempus, quod exquisierat a magis. Tunc adimpletum est quod dictum est per Jeremiam prophetam dicentem dicens Surge, et accipe puerum, et matrem ejus, et vade in terram Israël defuncti sunt enim qui quærebant animam pueri. Qui consurgens, accepit puerum, et matrem ejus, et venit in terram Israël. Audiens autem quod Archelaus regnaret in Judæa pro Herode patre suo, timuit illo ire et admonitus in somnis, secessit in partes Galilææ. Et veniens habitavit in civitate quæ vocatur Nazareth ut adimpleretur quod dictum est per prophetas Quoniam Nazaræus vocabitur. In diebus autem illis venit Joannes Baptista prædicans in deserto Judææ, et dicens Pœnitentiam agite appropinquavit enim regnum cælorum. Hic est enim, qui dictus est per Isaiam prophetam dicentem Vox clamantis in deserto Parate viam Domini; rectas facite semitas ejus. Ipse autem Joannes habebat vestimentum de pilis camelorum, et zonam pelliceam circa lumbos suos esca autem ejus erat locustæ, et mel silvestre. Tunc exibat ad eum Jerosolyma, et omnis Judæa, et omnis regio circa Jordanem; et baptizabantur ab eo in Jordane, confitentes peccata sua. Videns autem multos pharisæorum, et sadducæorum, venientes.
|
||||
|
||||
##### Abiit totus grex per prceps in
|
||||
|
||||
BIN
public/images/figures/index/pexels-clickerhappy-534590.jpg
Normal file
BIN
public/images/figures/index/pexels-clickerhappy-534590.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 MiB |
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;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { textQuoteIcon } from '@keystar/ui/icon/icons/textQuoteIcon';
|
||||
import { block } from '@keystatic/core/content-components';
|
||||
import { fields } from '@keystatic/core';
|
||||
|
||||
const blockquoteComponents = {
|
||||
const blockquoteComponent = {
|
||||
Blockquote: block({
|
||||
label: 'Blockquote',
|
||||
icon: textQuoteIcon,
|
||||
@@ -31,4 +31,4 @@ const blockquoteComponents = {
|
||||
}),
|
||||
};
|
||||
|
||||
export default blockquoteComponents;
|
||||
export default blockquoteComponent;
|
||||
|
||||
47
src/keystatic/components/general/callout.ts
Normal file
47
src/keystatic/components/general/callout.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { wrapper } from '@keystatic/core/content-components';
|
||||
import { fields } from '@keystatic/core';
|
||||
import { megaphoneIcon } from '@keystar/ui/icon/icons/megaphoneIcon';
|
||||
|
||||
const calloutComponent = {
|
||||
Callout: wrapper({
|
||||
label: 'Callout',
|
||||
icon: megaphoneIcon,
|
||||
schema: {
|
||||
type: fields.select({
|
||||
label: 'Type',
|
||||
defaultValue: 'default',
|
||||
options: [
|
||||
{
|
||||
label: 'Default',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
label: 'Example',
|
||||
value: 'example',
|
||||
},
|
||||
{
|
||||
label: 'Info',
|
||||
value: 'info',
|
||||
},
|
||||
{
|
||||
label: 'Warning',
|
||||
value: 'warning',
|
||||
},
|
||||
{
|
||||
label: 'Tip',
|
||||
value: 'tip',
|
||||
},
|
||||
{
|
||||
label: 'Spoiler',
|
||||
value: 'spoiler',
|
||||
},
|
||||
],
|
||||
}),
|
||||
title: fields.text({
|
||||
label: 'Title',
|
||||
}),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export default calloutComponent;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { imageIcon } from '@keystar/ui/icon/icons/imageIcon';
|
||||
import { block } from '@keystatic/core/content-components';
|
||||
import { fields } from '@keystatic/core';
|
||||
|
||||
const figureComponent = {
|
||||
Figure: block({
|
||||
label: 'Figure',
|
||||
icon: imageIcon,
|
||||
schema: {
|
||||
src: fields.image({
|
||||
label: 'Image',
|
||||
directory: 'public/images/figures',
|
||||
publicPath: '/images/figures',
|
||||
}),
|
||||
alt: fields.text({
|
||||
label: 'Alt Text',
|
||||
validation: {
|
||||
length: {
|
||||
min: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
caption: fields.text({
|
||||
label: 'Caption',
|
||||
multiline: true,
|
||||
}),
|
||||
credit: fields.text({
|
||||
label: 'Credit/Attribution',
|
||||
description: 'Photographer, artist, or source',
|
||||
}),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export default figureComponent;
|
||||
|
||||
@@ -2,12 +2,16 @@ import gridComponents from '@/keystatic/components/general/grid';
|
||||
import sidenoteComponents from '@/keystatic/components/general/sidenote';
|
||||
import definitionlistComponents from '@/keystatic/components/general/definitionlist';
|
||||
import accordionComponents from '@/keystatic/components/general/accordion';
|
||||
import blockquoteComponents from '@/keystatic/components/general/blockquote';
|
||||
import blockquoteComponent from '@/keystatic/components/general/blockquote';
|
||||
import figureComponent from '@/keystatic/components/general/figure';
|
||||
import calloutComponent from '@/keystatic/components/general/callout';
|
||||
|
||||
export const generalComponents = {
|
||||
...gridComponents,
|
||||
...sidenoteComponents,
|
||||
...definitionlistComponents,
|
||||
...accordionComponents,
|
||||
...blockquoteComponents,
|
||||
...blockquoteComponent,
|
||||
...figureComponent,
|
||||
...calloutComponent,
|
||||
};
|
||||
|
||||
@@ -93,4 +93,35 @@ export const tags: Config['tags'] = {
|
||||
},
|
||||
},
|
||||
},
|
||||
Figure: {
|
||||
render: 'Figure',
|
||||
attributes: {
|
||||
src: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
alt: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
caption: {
|
||||
type: 'String',
|
||||
},
|
||||
credit: {
|
||||
type: 'String',
|
||||
},
|
||||
},
|
||||
},
|
||||
Callout: {
|
||||
render: 'Callout',
|
||||
attributes: {
|
||||
type: {
|
||||
type: 'String',
|
||||
default: 'default',
|
||||
},
|
||||
title: {
|
||||
type: 'String',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
& p {
|
||||
& p:not([class]) {
|
||||
margin-block: var(--el-p-vspace-top) var(--el-p-vspace-bottom);
|
||||
|
||||
font-family: var(--el-p-font-family), sans-serif;
|
||||
@@ -495,18 +495,6 @@
|
||||
text-underline-offset: var(--size-1);
|
||||
}
|
||||
|
||||
& dfn {
|
||||
font-weight: var(--typo-weight-bold);
|
||||
font-style: normal;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
& cite {
|
||||
font-weight: var(--typo-weight-semibold);
|
||||
font-style: normal;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
& q {
|
||||
font-style: normal;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user