Skip to content

Commit d841144

Browse files
Merge pull request #823 from jamstack/light-color-theme
Implement a light color theme and theme toggle
2 parents 640e12b + fe3ff69 commit d841144

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+325
-129
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,4 @@ npm run start
8484
You can clone this repository and bootstrap it as a test site of your own, complete with the CI/CD build pipeline on [Netlify](https://netlify.com?utm_source=github&utm_medium=jamstackorg-pnh&utm_campaign=devex) by clicking the button below. (Requires free GitHub and Netlify accounts)
8585

8686
[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/jamstack/jamstack.org)
87+

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@
4343
"postcss-cli": "^8.3.1",
4444
"postcss-import": "^13.0.0",
4545
"spdx-correct": "^3.1.1",
46-
"tailwindcss": "^2.0.3"
46+
"tailwindcss": "^3.1.8"
4747
}
4848
}

src/css/d3chart.css

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,18 @@
5050
}
5151
.d3chart .tick line {
5252
shape-rendering: crispEdges;
53-
stroke: rgba(255,255,255,.15);
53+
}
54+
55+
.d3chart .tick line {
56+
stroke: rgba(22,26,42,.15);
5457
}
5558
.d3chart-bubble .tick:nth-child(2n) line {
56-
stroke: rgba(255,255,255,.22);
59+
stroke: rgba(22,26,42,.22);
5760
}
5861
.d3chart-bubble .tick:nth-child(2n+1) line {
59-
stroke: rgba(255,255,255,.1);
62+
stroke: rgba(22,26,42,.1);
6063
}
64+
6165
.d3chart-bubble .d3chart-xaxis :first-child line,
6266
.d3chart-bubble .d3chart-yaxis .tick:last-child line {
6367
stroke: #737680;
@@ -112,7 +116,6 @@
112116

113117
/* Axis labels */
114118
.d3chart-axislabel {
115-
fill: #fff;
116119
text-anchor: end;
117120
font-weight: 700;
118121
}
@@ -327,6 +330,23 @@
327330
background: linear-gradient(108.82deg, #FF72CF 0%, #C92ECC 90.74%);
328331
}
329332

333+
/* Overrides */
334+
335+
/* Dark mode */
336+
.dark .tick line {
337+
stroke: rgba(255,255,255,.15);
338+
}
339+
.dark .d3chart-bubble .tick:nth-child(2n) line {
340+
stroke: rgba(255,255,255,.22);
341+
}
342+
.dark .d3chart-bubble .tick:nth-child(2n+1) line {
343+
stroke: rgba(255,255,255,.1);
344+
}
330345

346+
.dark .d3chart-axislabel {
347+
fill: #fff;
348+
}
331349

332-
/* Overrides */
350+
.dark .d3chart-bubblelabel.offset-l {
351+
filter: url(#offset-label-bg);
352+
}

src/css/tailwind.css

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010

1111
@layer base {
12+
h1, h2, h3 {
13+
@apply text-blue-900 dark:text-white;
14+
}
1215
h1 {
1316
@apply font-bold text-4xl leading-tight my-8;
1417
}
@@ -18,7 +21,7 @@
1821
}
1922
}
2023
h2 {
21-
@apply text-white text-3xl font-bold leading-none mb-2;
24+
@apply text-3xl font-bold leading-none mb-2;
2225
}
2326
@screen md {
2427
h2 {
@@ -40,11 +43,11 @@ section {
4043
}
4144

4245

43-
section a,
44-
dd a {
45-
@apply text-white;
46+
:where(section a),
47+
:where(dd a) {
48+
@apply dark:text-white;
4649
@apply border-b;
47-
@apply border-blue-100;
50+
@apply border-blue-900 dark:border-blue-100;
4851
}
4952
section:not(.cards):not(.no-underline) a:hover,
5053
section:not(.cards):not(.no-underline) a:focus,
@@ -80,7 +83,6 @@ a.cta:focus {
8083
box-shadow: 0px 3px 15px rgba(241, 86, 77, 0.6);
8184
}
8285

83-
8486
/*
8587
Footer links
8688
*/
@@ -106,6 +108,41 @@ footer p a:focus {
106108
}
107109

108110

111+
/* Color theme selector */
112+
.color-theme-selector-wrapper {
113+
--padding-inline: 0.5rem;
114+
--icon-size: 1rem;
115+
116+
@apply invisible;
117+
@apply relative w-32 h-8 flex items-center;
118+
@apply rounded-default border border-gray-200 dark:border-transparent;
119+
@apply bg-white;
120+
@apply text-black;
121+
}
122+
123+
.color-theme-selector-wrapper-icon {
124+
width: var(--icon-size);
125+
max-height: 100%;
126+
margin-left: var(--padding-inline);
127+
}
128+
129+
.color-theme-selector-wrapper::after {
130+
position:absolute;
131+
top: 50%;
132+
right: var(--padding-inline);
133+
transform: translateY(-50%);
134+
content: "";
135+
width: var(--icon-size);
136+
height: var(--icon-size);
137+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 9L12 15L18 9' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A");
138+
}
139+
140+
.color-theme-selector-wrapper select {
141+
@apply absolute w-full flex items-center bg-transparent;
142+
appearance: none;
143+
padding-left: calc(var(--icon-size) + var(--padding-inline) + 0.5rem);
144+
}
145+
109146
.videowrapper {
110147
position: relative;
111148
padding-bottom: 56.25%; /* 16:9 */
@@ -337,14 +374,14 @@ details[open] .summary-swap-open {
337374

338375
/* Jamstack TV */
339376
.ais-SearchBox-input {
340-
@apply bg-blue-900;
341-
@apply text-white;
377+
@apply bg-white dark:bg-blue-900;
378+
@apply dark:text-white;
342379
@apply font-bold;
343380
@apply p-3;
344381
@apply pl-14;
345382
@apply mx-auto;
346383
@apply border;
347-
border-color: #5A5F75;
384+
@apply border-gray-200 dark:border-gray-400;
348385
@apply rounded-full;
349386
@apply block;
350387
@apply w-full;
@@ -393,6 +430,7 @@ details[open] .summary-swap-open {
393430
@apply bg-black;
394431
@apply text-sm;
395432
@apply font-bold;
433+
@apply text-blue-100;
396434
position: absolute;
397435
right: .4em;
398436
top: .4em;
@@ -471,6 +509,11 @@ details[open] .summary-swap-open {
471509
height: 4px;
472510
background-color: red;
473511
}
512+
513+
/* Survey */
514+
.chart-data-table-head {
515+
@apply bg-gray-200 dark:bg-gray-700 border-b-2;
516+
}
474517
/* purgecss end ignore */
475518

476519
@tailwind utilities;

src/js/color-theme.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
const htmlElement = document.documentElement;
2+
const colorThemeSelector = document.querySelector(
3+
"[data-color-theme-selector]"
4+
);
5+
const colorThemeSelectorInput = colorThemeSelector.querySelector("select");
6+
const colorThemeSelectorInputIcon = colorThemeSelector.querySelector('.color-theme-selector-wrapper-icon');
7+
const colorThemeSelectorInputIconSrc = colorThemeSelectorInputIcon.querySelector('use');
8+
const storedTheme = localStorage.theme;
9+
10+
function setInputIcon(type) {
11+
if(type === 'dark') {
12+
colorThemeSelectorInputIconSrc.setAttribute('xlink:href', '#icon-color-theme-dark');
13+
} else if(type === 'light') {
14+
colorThemeSelectorInputIconSrc.setAttribute('xlink:href', '#icon-color-theme-light');
15+
} else {
16+
colorThemeSelectorInputIconSrc.setAttribute('xlink:href', '#icon-color-theme-system');
17+
}
18+
}
19+
20+
function setInputState(storedTheme) {
21+
if (!!storedTheme) {
22+
colorThemeSelectorInput.querySelector(
23+
`[value="${storedTheme}"]`
24+
).selected = true;
25+
26+
setInputIcon(storedTheme);
27+
28+
htmlElement.classList.add(storedTheme);
29+
}
30+
}
31+
32+
function displayThemeSelector() {
33+
colorThemeSelector.style.visibility = 'visible';
34+
}
35+
36+
function toggleThemeClass(type) {
37+
if (type === "dark") {
38+
if (htmlElement.classList.contains("light")) {
39+
htmlElement.classList.remove("light");
40+
}
41+
42+
htmlElement.classList.add("dark");
43+
} else if (type == "light") {
44+
if (htmlElement.classList.contains("dark")) {
45+
htmlElement.classList.remove("dark");
46+
}
47+
48+
htmlElement.classList.add("light");
49+
} else {
50+
// "System" mode - blanket remove all theme classes from the root <html> element
51+
if (htmlElement.classList.contains("dark")) {
52+
htmlElement.classList.remove("dark");
53+
}
54+
55+
if (htmlElement.classList.contains("light")) {
56+
htmlElement.classList.remove("light");
57+
}
58+
59+
// If the current system color scheme preference is dark, apply the .dark class
60+
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
61+
htmlElement.classList.add("dark");
62+
}
63+
}
64+
}
65+
66+
function updateTheme(type) {
67+
switch (type) {
68+
case "dark":
69+
toggleThemeClass("dark");
70+
71+
setInputIcon('dark');
72+
73+
localStorage.theme = "dark";
74+
break;
75+
case "light":
76+
toggleThemeClass("light");
77+
78+
setInputIcon('light');
79+
80+
localStorage.theme = "light";
81+
break;
82+
default:
83+
toggleThemeClass("system");
84+
85+
setInputIcon('system');
86+
87+
localStorage.removeItem("theme");
88+
break;
89+
}
90+
}
91+
92+
setInputState(storedTheme);
93+
displayThemeSelector();
94+
95+
colorThemeSelectorInput.addEventListener("change", (e) => {
96+
updateTheme(e.target.value);
97+
});

src/site/_includes/components/cards-meetup.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% macro card(name, url, theme ) %}
22

3-
<a href="{{ url }}" target="_BLANK" rel="noopener" class="{{ theme }} bg-gradient-to-r block mb-4 border-gray-400 border rounded-xl rounded-tr-none text-center">
4-
<div class="bg-gray-100 mt-3 py-8 rounded-xl-embed rounded-t-none card-shadow">
3+
<a href="{{ url }}" target="_BLANK" rel="noopener" class="{{ theme }} bg-gradient-to-r block mb-4 border-gray-100 dark:border-gray-400 border rounded-xl rounded-tr-none text-center">
4+
<div class="bg-white dark:bg-gray-900 mt-3 py-8 rounded-xl-embed rounded-t-none card-shadow">
55
<svg role="img" aria-label="Jamstack Group" aria-hidden="true" focusable="false" width="20" height="20" class="inline"><use xlink:href="#gem-jamstack" ></use></svg>
66
<span class="font-bold ml-1">{{ name }} &rarr;</span>
77
</div>

src/site/_includes/components/cards.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{%- if item.data.language %} data-filter-language="{{ item.data.language | join(",") | lower }}"{% endif %}
99
{%- if item.data.license %} data-filter-license="{{ item.data.license | join(",") | lower }}"{% endif %}>
1010
<a href="{{ item.url }}" class="flex-grow block border-0 bg-white text-gray-700 rounded-t-lg last:rounded-b-lg">
11-
<div class="text-xl md:text-2xl lg:text-3xl font-bold text-ellipsis text-black bg-gradient-to-b border-b border-black rounded-t-lg p-4
11+
<div class="text-xl md:text-2xl lg:text-3xl font-bold text-ellipsis text-black bg-gradient-to-b dark:border-b border-black rounded-t-lg p-4
1212
{%- if loopIndex % 4 === 0 %} bg-gradient-card-sunrise
1313
{%- elseif loopIndex % 4 === 1 %} bg-gradient-card-blue
1414
{%- elseif loopIndex % 4 === 2 %} bg-gradient-card-seafoam
@@ -76,7 +76,7 @@
7676
</div>
7777
</a>
7878
{% if item.data.startertemplaterepo %}
79-
<a href="https://app.netlify.com/start/deploy?repository={{ item.data.startertemplaterepo}}" class="block px-4 py-3 text-gray-700 bg-white rounded-b-lg text-center md:text-lg whitespace-nowrap border-t">
79+
<a href="https://app.netlify.com/start/deploy?repository={{ item.data.startertemplaterepo}}" class="block px-4 py-3 text-gray-700 bg-white rounded-b-lg text-center md:text-lg whitespace-nowrap border-b-0 border-t border-blue-100">
8080
<svg role="img" aria-hidden="true" focusable="false" width="30" height="30" viewBox="0 0 40 40" class="inline-block mr-1" fill="#36b0bb"><use xlink:href="#logo-netlify-gem"/></svg>
8181
Deploy to Netlify
8282
</a>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<div class="flex justify-end p-4">
2+
<label class="color-theme-selector-wrapper" data-color-theme-selector>
3+
<svg class="color-theme-selector-wrapper-icon fill-current" role="img" focusable="false">
4+
<use xlink:href="#icon-color-theme-system"></use>
5+
</svg>
6+
<span class="sr-only">Color theme</span>
7+
<select>
8+
<option selected value="system">System</option>
9+
<option value="dark">Dark</option>
10+
<option value="light">Light</option>
11+
</select>
12+
</label>
13+
</div>

src/site/_includes/components/meetup-link.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<tr class="{% if loop.index0 % 2 == 0 %}bg-gray-900{% endif %}">
1+
<tr class="{% if loop.index0 % 2 == 0 %}bg-gray-200 dark:bg-gray-900{% endif %}">
22
<td class="m-2 md:p-4 md:m-0 block md:table-cell"><span class="font-bold md:hidden">Group: </span>{{ item.group.name }}</td>
33
<td class="m-2 md:p-4 md:m-0 block md:table-cell"><span class="font-bold md:hidden">Name: </span><a href="{{ item.link }}">{{ item.name }}</a></td>
44
<td class="m-2 md:p-4 md:m-0 block md:table-cell"><span class="font-bold md:hidden">Venue: </span>{{ item.venue.name }}</dt>

src/site/_includes/components/section-heading.njk

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{% macro heading(title, icon, description ) %}
2-
<h2 class="text-3xl mt-0 mb-2 text-white text-bold md:text-4xl md:mt-12">
2+
<h2 class="text-3xl mt-0 mb-2 dark:text-white text-bold md:text-4xl md:mt-12">
33
<img src="/img/svg/{{ icon }}" class="inline-block" />
44
{{ title }}
55
</h2>
6-
<p class="text-md font-bold inline-block bg-pink-900 text-white p-y px-2 mb-4 md:text-lg leading-relaxed">
6+
<p class="text-md font-bold inline-block bg-pink-900 dark:text-white p-y px-2 mb-4 md:text-lg leading-relaxed">
77
{{ description | safe }}
88
</p>
99
{% endmacro %}
@@ -20,10 +20,10 @@
2020
</svg>
2121
{% endif %}
2222
<div>
23-
<h3 class="font-bold text-white mb-2">
23+
<h3 class="font-bold dark:text-white mb-2">
2424
{{ title }}
2525
</h3>
26-
<div class="text-blue-100">
26+
<div class="dark:text-blue-100">
2727
{{ description | safe }}
2828
</div>
2929
</div>

0 commit comments

Comments
 (0)