Skip to content

Commit c616ba8

Browse files
committed
feat(terracotta): add Galley Proof reader variant + theme-aware contact modal
- New letterpress galley reader: running head, slip header, drop cap, crosshairs, imprimatur footer - Wire 'galley' into BlogPostPage, VisualSettingsContext, and all three settings pages - Guard useVisualSettings() in Toast (ToastProvider sits above VisualSettingsProvider) - Terracotta variant for ContactModal: dictionary-row channels with terra hover rail
1 parent 2cf581a commit c616ba8

8 files changed

Lines changed: 658 additions & 16 deletions

File tree

src/components/ContactModal.jsx

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,39 +24,67 @@ const ContactModal = ({ isOpen, onClose }) => {
2424
const { config } = useSiteConfig();
2525
const { fezcodexTheme } = useVisualSettings();
2626
const isLuxe = fezcodexTheme === 'luxe';
27+
const isTerracotta = fezcodexTheme === 'terracotta';
28+
29+
const title = (() => {
30+
if (isLuxe) return 'Establish Contact';
31+
if (isTerracotta) return 'Correspondence';
32+
return 'Contact';
33+
})();
2734

2835
return (
29-
<GenericModal
30-
isOpen={isOpen}
31-
onClose={onClose}
32-
title={isLuxe ? 'Establish Contact' : 'Contact'}
33-
>
36+
<GenericModal isOpen={isOpen} onClose={onClose} title={title}>
3437
<div className="flex flex-col gap-6">
35-
{isLuxe ? (
38+
{isLuxe && (
3639
<p className="font-outfit text-sm text-[#1A1A1A]/60 italic leading-relaxed mb-2">
3740
Choose a preferred channel to initiate communication with the
3841
primary node.
3942
</p>
40-
) : (
43+
)}
44+
{isTerracotta && (
45+
<div className="mb-1 flex items-center gap-3">
46+
<span className="h-[2px] w-[36px] bg-[#C96442]" />
47+
<p className="font-ibm-plex-mono text-[9.5px] uppercase tracking-[0.28em] text-[#2E2620]/70">
48+
Channels · open for letters
49+
</p>
50+
</div>
51+
)}
52+
{!isLuxe && !isTerracotta && (
4153
<p className="text-gray-400 mb-2 font-mono uppercase tracking-widest text-[10px]">
4254
{'//'} Establish connection via established protocols:
4355
</p>
4456
)}
4557

46-
<div className={`grid grid-cols-1 ${isLuxe ? 'gap-4' : 'gap-3'}`}>
58+
<div
59+
className={`grid grid-cols-1 ${
60+
isLuxe ? 'gap-4' : isTerracotta ? 'gap-0 border-t border-[#1A161320]' : 'gap-3'
61+
}`}
62+
>
4763
{config?.socials &&
4864
config.socials.map((link) => {
4965
const Icon = socialIcons[link.icon] || GlobeIcon;
66+
const cleaned = link.url
67+
.replace(/^mailto:/, '')
68+
.replace(/^https?:\/\//, '');
5069
if (isLuxe) {
5170
return (
5271
<LuxeContactLink
5372
key={link.id}
5473
href={link.url}
5574
icon={Icon}
5675
label={link.label}
57-
value={link.url
58-
.replace(/^mailto:/, '')
59-
.replace(/^https?:\/\//, '')}
76+
value={cleaned}
77+
/>
78+
);
79+
}
80+
if (isTerracotta) {
81+
return (
82+
<TerracottaContactLink
83+
key={link.id}
84+
href={link.url}
85+
icon={Icon}
86+
label={link.label}
87+
value={cleaned}
6088
/>
6189
);
6290
}
@@ -66,9 +94,7 @@ const ContactModal = ({ isOpen, onClose }) => {
6694
href={link.url}
6795
icon={Icon}
6896
label={link.label}
69-
value={link.url
70-
.replace(/^mailto:/, '')
71-
.replace(/^https?:\/\//, '')}
97+
value={cleaned}
7298
/>
7399
);
74100
})}
@@ -78,6 +104,34 @@ const ContactModal = ({ isOpen, onClose }) => {
78104
);
79105
};
80106

107+
const TerracottaContactLink = ({ href, icon: Icon, label, value }) => (
108+
<a
109+
href={href}
110+
target="_blank"
111+
rel="noopener noreferrer"
112+
className="group relative grid grid-cols-[52px_140px_1fr_auto] items-center gap-4 px-4 py-4 border-b border-[#1A161320] hover:bg-[#E8DECE]/60 transition-colors"
113+
>
114+
<span
115+
aria-hidden="true"
116+
className="absolute left-0 top-0 bottom-0 w-[2px] bg-[#C96442] opacity-0 group-hover:opacity-100 transition-opacity"
117+
/>
118+
<div className="flex items-center justify-center w-10 h-10 border border-[#1A161330] text-[#1A1613] group-hover:border-[#C96442] group-hover:text-[#9E4A2F] transition-colors">
119+
<Icon size={20} weight="duotone" />
120+
</div>
121+
<span className="font-ibm-plex-mono text-[9.5px] uppercase tracking-[0.28em] text-[#C96442]">
122+
{label}
123+
</span>
124+
<span className="font-fraunces italic text-[16px] text-[#1A1613] truncate">
125+
{value}
126+
</span>
127+
<ArrowUpRightIcon
128+
size={14}
129+
weight="bold"
130+
className="text-[#1A161340] group-hover:text-[#9E4A2F] transition-colors"
131+
/>
132+
</a>
133+
);
134+
81135
const LuxeContactLink = ({ href, icon: Icon, label, value }) => (
82136
<a
83137
href={href}

src/components/Toast.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ const Toast = ({
2020
icon,
2121
links,
2222
}) => {
23-
const { fezcodexTheme } = useVisualSettings();
24-
const isTerracotta = fezcodexTheme === 'terracotta';
23+
const visualSettings = useVisualSettings();
24+
const isTerracotta = visualSettings?.fezcodexTheme === 'terracotta';
2525

2626
useEffect(() => {
2727
const timer = setTimeout(() => {

src/context/VisualSettingsContext.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ export const VisualSettingsProvider = ({ children }) => {
123123
'terminal-green',
124124
'old',
125125
'luxe',
126+
'terracotta',
127+
'galley',
126128
].includes(blogModeParam)
127129
) {
128130
setBlogPostViewMode(blogModeParam);

src/pages/BlogPostPage.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import TerminalBlogPostPage from './blog-views/TerminalBlogPostPage';
1010
import TerminalGreenBlogPostPage from './blog-views/TerminalGreenBlogPostPage';
1111
import LuxeBlogPostPage from './blog-views/LuxeBlogPostPage';
1212
import TerracottaBlogPostPage from './blog-views/TerracottaBlogPostPage';
13+
import GalleyBlogPostPage from './blog-views/GalleyBlogPostPage';
1314

1415
const BlogPostPage = () => {
1516
const { blogPostViewMode, fezcodexTheme } = useVisualSettings();
@@ -29,6 +30,7 @@ const BlogPostPage = () => {
2930
'old',
3031
'luxe',
3132
'terracotta',
33+
'galley',
3234
].includes(themeParam)
3335
) {
3436
return themeParam;
@@ -46,6 +48,7 @@ const BlogPostPage = () => {
4648

4749
if (effectiveViewMode === 'luxe') return <LuxeBlogPostPage />;
4850
if (effectiveViewMode === 'terracotta') return <TerracottaBlogPostPage />;
51+
if (effectiveViewMode === 'galley') return <GalleyBlogPostPage />;
4952
if (effectiveViewMode === 'old') return <OldBlogPostPage />;
5053
if (effectiveViewMode === 'dossier') return <DossierBlogPostPage />;
5154
if (effectiveViewMode === 'dokument') return <DokumentBlogPostPage />;

0 commit comments

Comments
 (0)