Skip to content

Commit e8ae80d

Browse files
committed
feat: use CSS modules
1 parent 5ac1fca commit e8ae80d

29 files changed

+488
-710
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier/)
77
[![ESLint: TypeScript](https://img.shields.io/badge/ESLint-TypeScript-blue.svg)](https://github.com/typescript-eslint/typescript-eslint)
88
[![React](https://github.com/aleen42/badges/raw/master/src/react.svg)](https://reactjs.org/)
9+
[![CSS modules](https://img.shields.io/badge/CSS-modules-yellow)](https://github.com/css-modules/css-modules)
910
[![Vite](https://github.com/aleen42/badges/raw/master/src/vitejs.svg)](https://vitejs.dev/)
1011

1112
Create a shareable schedule with times in your local timezone. Great for remote

index.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html lang="en">
2+
<html lang="en" data-theme="light">
33
<head>
44
<meta charset="utf-8" />
55
<meta
@@ -23,6 +23,7 @@
2323
type="text/css"
2424
href="https://fonts.googleapis.com/css?family=DM+Mono&display=swap"
2525
/>
26+
<link rel="stylesheet" type="text/css" href="/theme.css" />
2627
</head>
2728
<body>
2829
<div id="root"></div>

package-lock.json

+114-316
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+4-5
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
"feather-icons": "4.28.0",
3535
"react": "17.0.2",
3636
"react-dom": "17.0.2",
37-
"react-router-dom": "6.2.2",
38-
"styled-components": "5.3.3"
37+
"react-router-dom": "6.2.2"
3938
},
4039
"devDependencies": {
4140
"@nordicsemiconductor/asset-tracker-cloud-code-style": "11.0.35",
@@ -46,13 +45,13 @@
4645
"@types/jest": "27.4.1",
4746
"@types/react": "17.0.39",
4847
"@types/react-dom": "17.0.13",
49-
"@types/styled-components": "5.1.24",
5048
"@vitejs/plugin-react": "1.2.0",
5149
"check-node-version": "4.2.1",
5250
"eslint-config-react-app": "7.0.0",
5351
"eslint-plugin-jsx-a11y": "6.5.1",
5452
"eslint-plugin-no-restricted-imports": "0.0.0",
5553
"handlebars": "4.7.7",
54+
"identity-obj-proxy": "3.0.0",
5655
"jest": "27.5.1",
5756
"vite": "2.8.6"
5857
},
@@ -84,8 +83,8 @@
8483
"jest": {
8584
"testRegex": ".+\\.spec\\.tsx?$",
8685
"moduleNameMapper": {
87-
"^app/(.*)$": "<rootDir>/src/$1",
88-
"^style/(.*)$": "<rootDir>/src/style/$1"
86+
"^.+\\.css$": "identity-obj-proxy",
87+
"^app/(.*)$": "<rootDir>/src/$1"
8988
},
9089
"transform": {
9190
"^.+\\.(t|j)sx?$": [

public/theme.css

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
html[data-theme="dark"] {
2+
--color-background: #000;
3+
--color-text: #fff;
4+
--color-delete: #ff5235;
5+
--color-add: #0fa;
6+
--color-addDisabled: #aaa;
7+
--color-countdownWarning: #ff5e007a;
8+
--color-borderColor: #7d7d7d;
9+
--filter-calendar-picker-indicator: invert(1);
10+
}
11+
12+
html[data-theme="light"] {
13+
--color-background: #fffbf6;
14+
--color-text: #000000cc;
15+
--color-add: #22a00d;
16+
--color-addDisabled: #aaa;
17+
--color-delete: #dc2000;
18+
--color-countdownWarning: #ff000052;
19+
--color-borderColor: #a7a7a7;
20+
}
21+
22+
body {
23+
background-color: var(--color-background);
24+
color: var(--color-text);
25+
font-family: "DM Mono", monospace;
26+
}

src/App.module.css

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
.Info {
2+
text-align: center;
3+
font-size: 14px;
4+
margin: 1rem;
5+
display: flex;
6+
justify-content: center;
7+
flex-direction: column;
8+
}
9+
.Info a {
10+
color: var(--color-text);
11+
}
12+
13+
.Headline {
14+
font-size: 16px;
15+
}
16+
@media (min-width: 900px) {
17+
.Headline {
18+
font-size: 22px;
19+
}
20+
}
21+
22+
.Title {
23+
display: flex;
24+
justify-content: space-between;
25+
align-items: center;
26+
padding: 0.25rem;
27+
}
28+
@media (min-width: 900px) {
29+
.Title {
30+
padding: 1rem;
31+
font-size: 16px;
32+
}
33+
}
34+
35+
.Title h1 {
36+
margin: 0;
37+
}
38+
.Title div:global(.actions) {
39+
display: flex;
40+
}

src/App.tsx

+53-54
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1+
import styles from 'app/App.module.css'
2+
import { DaySelector } from 'app/DaySelector'
13
import { Editor } from 'app/Editor'
4+
import { EyeIcon, EyeOffIcon, LockIcon, UnLockIcon } from 'app/FeatherIcons'
5+
import { Footer } from 'app/Footer'
6+
import formStyles from 'app/Form.module.css'
27
import { Schedule } from 'app/Schedule'
3-
import { ThemeSwitcher } from 'app/ThemeSwitcher'
8+
import { Theme, ThemeSwitcher } from 'app/ThemeSwitcher'
9+
import { TimeZoneSelector } from 'app/timezones'
410
import { format } from 'date-fns'
5-
import { useState } from 'react'
6-
import { EyeIcon, EyeOffIcon, LockIcon, UnLockIcon } from 'style/FeatherIcons'
7-
import { Footer } from 'style/Footer'
8-
import {
9-
Button,
10-
DateEditor,
11-
Input,
12-
StyledDaySelector,
13-
StyledTimeZoneSelector,
14-
} from 'style/Form'
15-
import { GlobalStyle } from 'style/Global'
16-
import { Headline, Info, Main, Title, TitleActions } from 'style/Main'
17-
import { dark, light, Theme } from 'style/theme'
18-
import { ThemeProvider } from 'styled-components'
11+
import { useEffect, useState } from 'react'
12+
13+
let defaultTheme = Theme.light
14+
if (typeof window.matchMedia === 'function') {
15+
const match = window.matchMedia('(prefers-color-scheme: dark)')
16+
defaultTheme = match.matches ? Theme.dark : Theme.light
17+
}
1918

2019
export const App = () => {
2120
let cfg = {
@@ -57,7 +56,9 @@ export const App = () => {
5756
}
5857
}
5958
const [theme, updateTheme] = useState<Theme>(
60-
window.localStorage.getItem('theme') === 'light' ? light : dark,
59+
(window.localStorage.getItem('theme') ?? defaultTheme) === 'dark'
60+
? Theme.dark
61+
: Theme.light,
6162
)
6263
const [updatedName, updateName] = useState(cfg.name)
6364
const [updatedDay, updateDay] = useState(cfg.day)
@@ -67,14 +68,19 @@ export const App = () => {
6768
const [hidePastSessions, setHidePastSessions] = useState(
6869
hidePastSessionsDefault,
6970
)
71+
72+
useEffect(() => {
73+
document.documentElement.setAttribute('data-theme', theme)
74+
}, [theme])
75+
7076
return (
71-
<ThemeProvider theme={theme}>
72-
<GlobalStyle />
73-
<Main>
77+
<>
78+
<main>
7479
{editing && (
7580
<>
76-
<Title>
77-
<Button
81+
<div className={styles.Title}>
82+
<button
83+
className={formStyles.Button}
7884
title="Save changes"
7985
onClick={() => {
8086
const cfg = {
@@ -92,26 +98,22 @@ export const App = () => {
9298
}}
9399
>
94100
<UnLockIcon />
95-
</Button>
96-
<DateEditor>
97-
<Input
101+
</button>
102+
<div className={formStyles.DateEditor}>
103+
<input
104+
className={formStyles.Input}
98105
type="text"
99106
value={updatedName}
100107
onChange={({ target: { value } }) => updateName(value)}
101108
/>
102-
<StyledDaySelector day={updatedDay} onUpdate={updateDay} />
103-
<StyledTimeZoneSelector
109+
<DaySelector day={updatedDay} onUpdate={updateDay} />
110+
<TimeZoneSelector
104111
value={updatedTimeZone}
105112
onChange={({ target: { value } }) => updateTimeZone(value)}
106113
/>
107-
</DateEditor>
108-
<ThemeSwitcher
109-
currentTheme={theme}
110-
darkTheme={dark}
111-
lightTheme={light}
112-
onSwitch={updateTheme}
113-
/>
114-
</Title>
114+
</div>
115+
<ThemeSwitcher currentTheme={theme} onSwitch={updateTheme} />
116+
</div>
115117
<Editor
116118
onAdd={(add) => {
117119
updateSessions((sessions) => ({
@@ -134,34 +136,31 @@ export const App = () => {
134136
)}
135137
{!editing && (
136138
<>
137-
<Title>
138-
<Button
139+
<div className={styles.Title}>
140+
<button
141+
className={formStyles.Button}
139142
title="Edit schedule"
140143
onClick={() => {
141144
setEditing(true)
142145
}}
143146
>
144147
<LockIcon />
145-
</Button>
146-
<Headline>
148+
</button>
149+
<h1 className={styles.Headline}>
147150
{updatedName}: {updatedDay}
148-
</Headline>
149-
<TitleActions>
150-
<Button
151+
</h1>
152+
<div className="actions">
153+
<button
154+
className={formStyles.Button}
151155
title="Hide past sessions"
152156
onClick={() => setHidePastSessions((h) => !h)}
153157
>
154158
{hidePastSessions && <EyeOffIcon />}
155159
{!hidePastSessions && <EyeIcon />}
156-
</Button>
157-
<ThemeSwitcher
158-
currentTheme={theme}
159-
darkTheme={dark}
160-
lightTheme={light}
161-
onSwitch={updateTheme}
162-
/>
163-
</TitleActions>
164-
</Title>
160+
</button>
161+
<ThemeSwitcher currentTheme={theme} onSwitch={updateTheme} />
162+
</div>
163+
</div>
165164
<Schedule
166165
sessions={cfg.sessions}
167166
eventTimezoneName={cfg.tz}
@@ -170,7 +169,7 @@ export const App = () => {
170169
/>
171170
</>
172171
)}
173-
<Info>
172+
<div className={styles.Info}>
174173
<p>
175174
Click the <LockIcon /> icon to create your own schedule. When done,
176175
click the <UnLockIcon /> and share the updated URL.
@@ -186,9 +185,9 @@ export const App = () => {
186185
</a>{' '}
187186
to embed it on any page.
188187
</p>
189-
</Info>
190-
</Main>
188+
</div>
189+
</main>
191190
<Footer />
192-
</ThemeProvider>
191+
</>
193192
)
194193
}

src/DaySelector.module.css

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.DaySelector {
2+
background-color: transparent;
3+
border: 1px solid var(--color-text);
4+
padding: 0.25rem 0.5rem;
5+
height: 30px;
6+
color: var(--color-text);
7+
margin: 0;
8+
}
9+
10+
.DaySelector:global(::-webkit-calendar-picker-indicator) {
11+
filter: var(--filter-calendar-picker-indicator);
12+
}

src/DaySelector.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1+
import styles from 'app/DaySelector.module.css'
12
import { format } from 'date-fns'
23
import { useState } from 'react'
3-
44
export const DaySelector = ({
55
day,
66
onUpdate,
7-
className,
87
}: {
98
day: string
10-
className?: string
119
onUpdate: (date: string) => unknown
1210
}) => {
1311
const [value, setValue] = useState<string>(day)
1412
return (
1513
<input
16-
className={className}
14+
className={styles.DaySelector}
1715
type="date"
1816
value={value}
1917
aria-label="date-input"

0 commit comments

Comments
 (0)