Skip to content

Commit c8cb937

Browse files
committed
feat: implement newspaper textures, text imperfections, and toggle with emoji workflow branding
1 parent 85d95b0 commit c8cb937

3 files changed

Lines changed: 286 additions & 78 deletions

File tree

src/components/shell/footer/Footer.astro

Lines changed: 137 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -25,90 +25,151 @@ const today = new Date();
2525
});
2626
}
2727
</script> -->
28-
<div class="social-links">
29-
<a href="/about">About</a>
30-
<a href="#" target="_blank" rel="noopener noreferrer">Twitter</a>
31-
<a
32-
href="https://github.com/simplearyan?tab=repositories"
33-
target="_blank"
34-
rel="noopener noreferrer">GitHub</a
35-
>
36-
<a
37-
href="https://simplearyan.github.io/aryan-blog/"
38-
target="_blank"
39-
rel="noopener noreferrer">OldSite</a
40-
>
41-
<a href="/kinetix" target="_blank" rel="noopener noreferrer">Kinetix</a>
42-
</div>
28+
<div class="social-links">
29+
<a href="/about">About</a>
30+
<a href="#" target="_blank" rel="noopener noreferrer">Twitter</a>
31+
<a
32+
href="https://github.com/simplearyan?tab=repositories"
33+
target="_blank"
34+
rel="noopener noreferrer">GitHub</a
35+
>
36+
<a
37+
href="https://simplearyan.github.io/aryan-blog/"
38+
target="_blank"
39+
rel="noopener noreferrer">OldSite</a
40+
>
41+
<a href="/kinetix" target="_blank" rel="noopener noreferrer">Kinetix</a>
42+
<button
43+
id="texture-toggle"
44+
class="texture-btn"
45+
aria-label="Toggle Texture"
46+
>
47+
Texture: ON
48+
</button>
49+
</div>
50+
</p>
4351
</div>
44-
</footer>
4552

46-
<style>
47-
footer {
48-
margin-top: 2rem;
49-
padding: var(--spacing-xl) 0;
50-
border-top: 1px solid var(--color-border);
51-
color: #666;
52-
}
53-
54-
.container {
55-
display: flex;
56-
justify-content: space-between;
57-
align-items: center;
58-
}
59-
60-
.social-links {
61-
display: flex;
62-
gap: var(--spacing-md);
63-
}
64-
65-
a:hover {
66-
color: var(--color-primary);
67-
}
68-
69-
.logo {
70-
display: inline-flex;
71-
align-items: baseline;
72-
text-decoration: none;
73-
line-height: 1;
74-
color: #666;
75-
margin: 0 0.25rem;
76-
}
77-
78-
.logo-a {
79-
font-family: "Playfair Display", serif;
80-
font-size: 1.5rem;
81-
font-weight: 700;
82-
font-style: italic;
83-
letter-spacing: -0.05em;
84-
}
85-
86-
.logo-x {
87-
font-family: "Kalam", cursive;
88-
font-size: 1rem;
89-
font-weight: 700;
90-
margin-left: 1.5px;
91-
transform: translateY(-7px);
92-
}
93-
94-
@media (max-width: 768px) {
53+
<style>
54+
footer {
55+
margin-top: 2rem;
56+
padding: var(--spacing-xl) 0;
57+
border-top: 1px solid var(--color-border);
58+
color: #666;
59+
}
60+
9561
.container {
96-
flex-direction: column;
97-
gap: var(--spacing-md);
98-
text-align: center;
62+
display: flex;
63+
justify-content: space-between;
64+
align-items: center;
9965
}
10066

10167
.social-links {
102-
justify-content: center;
68+
display: flex;
69+
gap: var(--spacing-md);
70+
align-items: center; /* Ensure alignment with button */
71+
}
72+
73+
/* ... existing styles ... */
74+
a:hover {
75+
color: var(--color-primary);
76+
}
77+
78+
.texture-btn {
79+
background: none;
80+
border: 1px solid var(--color-border);
81+
border-radius: 4px;
82+
padding: 0.25rem 0.75rem;
83+
font-family: var(--font-mono);
84+
font-size: 0.85rem;
85+
color: var(--color-text-muted);
86+
cursor: pointer;
87+
transition: all 0.2s ease;
88+
}
89+
90+
.texture-btn:hover {
91+
border-color: var(--color-primary);
92+
color: var(--color-primary);
93+
}
94+
95+
.logo {
96+
display: inline-flex;
97+
align-items: baseline;
98+
text-decoration: none;
99+
line-height: 1;
100+
color: #666;
101+
margin: 0 0.25rem;
102+
}
103+
104+
.logo-a {
105+
font-family: "Playfair Display", serif;
106+
font-size: 1.5rem;
107+
font-weight: 700;
108+
font-style: italic;
109+
letter-spacing: -0.05em;
103110
}
104111

105-
.footer-separator {
106-
display: none;
112+
.logo-x {
113+
font-family: "Kalam", cursive;
114+
font-size: 1rem;
115+
font-weight: 700;
116+
margin-left: 1.5px;
117+
transform: translateY(-7px);
107118
}
108119

109-
#footer-date {
110-
display: block;
111-
margin-top: 0.5rem;
120+
@media (max-width: 768px) {
121+
.container {
122+
flex-direction: column;
123+
gap: var(--spacing-md);
124+
text-align: center;
125+
}
126+
127+
.social-links {
128+
justify-content: center;
129+
flex-wrap: wrap; /* Handle overflow */
130+
}
131+
132+
.footer-separator {
133+
display: none;
134+
}
135+
136+
#footer-date {
137+
display: block;
138+
margin-top: 0.5rem;
139+
}
140+
}
141+
</style>
142+
143+
<script>
144+
const toggleBtn = document.getElementById("texture-toggle");
145+
const body = document.body;
146+
147+
// Check storage or default to ON (so no-texture is false)
148+
// If stored is 'false', it means texture is OFF (so no-texture class added)
149+
// Logic:
150+
// - 'texture' key in localStorage.
151+
// - value 'enabled' (default) or 'disabled'.
152+
153+
const currentTexture = localStorage.getItem("texture") || "enabled";
154+
155+
function updateState(isEnabled: boolean) {
156+
if (isEnabled) {
157+
body.classList.remove("no-texture");
158+
if (toggleBtn) toggleBtn.textContent = "Texture: ON";
159+
localStorage.setItem("texture", "enabled");
160+
} else {
161+
body.classList.add("no-texture");
162+
if (toggleBtn) toggleBtn.textContent = "Texture: OFF";
163+
localStorage.setItem("texture", "disabled");
164+
}
112165
}
113-
}
114-
</style>
166+
167+
// Init
168+
updateState(currentTexture === "enabled");
169+
170+
toggleBtn?.addEventListener("click", () => {
171+
const isCurrentlyOn = !body.classList.contains("no-texture");
172+
updateState(!isCurrentlyOn);
173+
});
174+
</script>
175+
</footer>

src/layouts/BaseLayout.astro

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,54 @@ const socialImageURL = new URL(image, Astro.url);
141141
<HeroSection />
142142
<Footer />
143143
<!-- {Astro.url.pathname !== "/" && <StickyBottomAd />} -->
144+
<!-- Global SVG Filters for Cinematic Textures -->
145+
<svg
146+
style="position: absolute; width: 0; height: 0; overflow: hidden;"
147+
aria-hidden="true"
148+
>
149+
<defs>
150+
<!-- Filter for Headings: Strong Ink Bleed & Distort -->
151+
<filter
152+
id="ink-bleed"
153+
x="-20%"
154+
y="-20%"
155+
width="140%"
156+
height="140%"
157+
>
158+
<feTurbulence
159+
type="fractalNoise"
160+
baseFrequency="0.03"
161+
numOctaves="3"
162+
result="noise"></feTurbulence>
163+
<feDisplacementMap
164+
in="SourceGraphic"
165+
in2="noise"
166+
scale="2"
167+
xChannelSelector="R"
168+
yChannelSelector="G"></feDisplacementMap>
169+
<feGaussianBlur stdDeviation="0.4"></feGaussianBlur>
170+
<feColorMatrix
171+
type="matrix"
172+
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7"
173+
result="goo"></feColorMatrix>
174+
<feComposite in="SourceGraphic" in2="goo" operator="atop"
175+
></feComposite>
176+
</filter>
177+
178+
<!-- Filter for Body Text: Subtle Roughness -->
179+
<filter id="text-roughness">
180+
<feTurbulence
181+
type="fractalNoise"
182+
baseFrequency="0.5"
183+
numOctaves="1"
184+
result="noise"></feTurbulence>
185+
<feDisplacementMap
186+
in="SourceGraphic"
187+
in2="noise"
188+
scale="0.5"></feDisplacementMap>
189+
</filter>
190+
</defs>
191+
</svg>
144192
<script>
145193
if ("serviceWorker" in navigator) {
146194
window.addEventListener("load", () => {

src/styles/global.css

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
/* Global Styles */
55
:root {
66
/* Color Palette - Light Mode */
7-
--color-bg: #ffffff;
8-
--color-bg-offset: #f5f5f5;
7+
--color-bg: #f4f1ea;
8+
/* Warm Newsprint */
9+
--color-bg-offset: #e6e2d8;
910
--color-text: #1a1a1a;
1011
--color-primary: #1B2A41;
1112
/* Navy Blue */
@@ -606,4 +607,102 @@ p {
606607
overflow-x: auto;
607608
white-space: nowrap;
608609
}
610+
}
611+
612+
/*
613+
========================================
614+
Newspaper Texture & Grain Effects
615+
========================================
616+
*/
617+
618+
/*
619+
========================================
620+
Newspaper Texture & Grain Effects
621+
========================================
622+
*/
623+
624+
/* Global Page Grain Overlay */
625+
body:not(.no-texture)::before {
626+
content: "";
627+
position: fixed;
628+
top: 0;
629+
left: 0;
630+
width: 100vw;
631+
height: 100vh;
632+
pointer-events: none;
633+
z-index: 9999;
634+
/* Stronger, coarser noise */
635+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.6' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='0.6'/%3E%3C/svg%3E");
636+
opacity: 0.4;
637+
mix-blend-mode: multiply;
638+
filter: sepia(0.3);
639+
/* Add old paper tint to noise */
640+
}
641+
642+
/* Dark Mode Adjustment for Grain */
643+
[data-theme="dark"] body:not(.no-texture)::before {
644+
opacity: 0.15;
645+
mix-blend-mode: overlay;
646+
filter: invert(1);
647+
/* Invert noise for better visibility on dark */
648+
}
649+
650+
/* Ink Bleed Texture for Headings */
651+
h1,
652+
h2,
653+
h3,
654+
.logo-a {
655+
/* Base Color Fallback - Always present */
656+
color: var(--color-text);
657+
}
658+
659+
/* Apply filters only when texture is enabled */
660+
body:not(.no-texture) h1,
661+
body:not(.no-texture) h2,
662+
body:not(.no-texture) h3,
663+
body:not(.no-texture) .logo-a {
664+
/* Apply SVG Filter for imperfect edges */
665+
filter: url(#ink-bleed);
666+
667+
/* Optional: Keep the noise texture as a subtle overlay if desired,
668+
but standard text color usually works better with displacement filters.
669+
Let's try combining them for maximum effect. */
670+
background: linear-gradient(to bottom, var(--color-text), var(--color-text));
671+
-webkit-background-clip: text;
672+
background-clip: text;
673+
/* mix-blend-mode: multiply; */
674+
}
675+
676+
/* Texture for Body Text (Subtler Imperfection) */
677+
body:not(.no-texture) p,
678+
body:not(.no-texture) a,
679+
body:not(.no-texture) li,
680+
body:not(.no-texture) span,
681+
body:not(.no-texture) td {
682+
filter: url(#text-roughness);
683+
/* subtle blur to soften digital edges */
684+
/* text-shadow: 0.2px 0 var(--color-text); */
685+
}
686+
687+
/* Dark Mode Overrides */
688+
[data-theme="dark"] body:not(.no-texture) h1,
689+
[data-theme="dark"] body:not(.no-texture) h2,
690+
[data-theme="dark"] body:not(.no-texture) h3,
691+
[data-theme="dark"] body:not(.no-texture) .logo-a {
692+
/* Filter needs to be slightly adjusted or identical */
693+
filter: url(#ink-bleed);
694+
color: var(--color-text);
695+
background: none;
696+
-webkit-background-clip: border-box;
697+
background-clip: border-box;
698+
}
699+
700+
[data-theme="dark"] body:not(.no-texture) p,
701+
[data-theme="dark"] body:not(.no-texture) a,
702+
[data-theme="dark"] body:not(.no-texture) li,
703+
[data-theme="dark"] body:not(.no-texture) span,
704+
[data-theme="dark"] body:not(.no-texture) td {
705+
filter: url(#text-roughness);
706+
opacity: 0.9;
707+
/* Slightly reduce brightness of white text on dark for analog feel */
609708
}

0 commit comments

Comments
 (0)