Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add automatic time-based dark mode switching #208

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_BUILD_TARGET=extension
VITE_API_URL=https://api.hackertab.dev/
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@
.env*
*.zip
.todo

# dependencies
/node_modules
/.pnp
.pnp.js
/dist

# testing
/coverage

# production
/build
/dist

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ As a developer, it can be difficult to stay on top of everything happening in th
- 🔖 Bookmark and read it later.
- 🌙 Dark mode for when it gets late.
- ✨ AI-powered recommendations exclusively tailored to your preferences.

- 🧠 Chat GPT integration
Even more features are going to come in the future!

## Data sources
Expand All @@ -56,7 +56,8 @@ Please do not hesitate to ask a question, report a bug or add a suggestion. or s

## Development

Please use the develop branch. Create an .env file with the necessary
Please use the develop branch.
don't forget to rename `.env.example` to `.env`

```bash
$ git clone --branch develop [email protected]:medyo/hackertab.dev.git
Expand Down
2 changes: 1 addition & 1 deletion public/base.manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Hackertab.dev - developer news",
"description": "All developer news in one tab",
"version": "1.20.1",
"version": "1.22.0",
"chrome_url_overrides": {
"newtab": "index.html"
},
Expand Down
81 changes: 72 additions & 9 deletions src/assets/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ body {
font-family: 'nunito';
font-size: 100%;
}

.appError {
justify-content: center;
align-items: center;
Expand Down Expand Up @@ -329,6 +330,7 @@ a {
height: 16px;
width: 16px;
}

.blockHeaderBadge {
width: auto;
font-size: 12px;
Expand All @@ -343,6 +345,7 @@ a {
text-transform: lowercase;
color: white;
}

.blockHeaderIcon img {
display: block;
}
Expand Down Expand Up @@ -421,6 +424,7 @@ a {
.blockRow:not(:last-child) {
border-bottom: 1px solid var(--card-content-divider);
}

.rowCover {
border-radius: 4px;
display: block;
Expand All @@ -441,6 +445,7 @@ a {
display: flex;
flex-direction: row;
}

.rowLink {
color: var(--primary-text-color);
margin: 0;
Expand All @@ -454,10 +459,12 @@ a {
.rowTitle:hover {
color: var(--primary-hover-text-color);
}

.titleWithCover {
display: block;
width: 100%;
}

.dark .blockHeaderWhite {
color: white;
}
Expand Down Expand Up @@ -907,6 +914,7 @@ Producthunt item
padding: 2px;
color: var(--tag-background-color);
}

/*.searchBarIcon > svg {
background-color: white;
color: black;
Expand All @@ -926,9 +934,11 @@ Producthunt item
width: 100%;
background-color: var(--card-header-background-color);
}

.searchBarInput:focus {
outline: none;
}

.tooltipLoading {
display: flex;
justify-content: center;
Expand Down Expand Up @@ -1014,6 +1024,63 @@ Producthunt item
opacity: 1;
}

.settingsGroup {
margin-bottom: 2rem;
padding: 1rem;
background-color: var(--bg-color-secondary);
border-radius: 8px;
}

.settingsGroupTitle {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 1rem;
color: var(--text-color-primary);
}

.settingsGroupContent {
display: flex;
flex-direction: column;
gap: 1.5rem;
}

.settingItem {
display: flex;
flex-direction: column;
gap: 0.5rem;
}

.settingDescription {
font-size: 0.9rem;
color: var(--text-color-secondary);
}

.settingSelect {
padding: 0.5rem;
border-radius: 4px;
border: 1px solid var(--border-color);
background-color: var(--bg-color-primary);
color: var(--text-color-primary);
font-size: 0.9rem;
max-width: 300px;
}

.timeInputs {
display: flex;
align-items: center;
gap: 0.5rem;
}

.timeInput {
width: 60px;
padding: 0.5rem;
border-radius: 4px;
border: 1px solid var(--border-color);
background-color: var(--bg-color-primary);
color: var(--text-color-primary);
font-size: 0.9rem;
}

/*****************
*** BREAKPOINTS
*******************/
Expand Down Expand Up @@ -1274,9 +1341,7 @@ Producthunt item
}

.block {
width: calc(
(1800px - 20px * min(5, var(--max-visible-cards))) / min(5, var(--max-visible-cards))
);
width: calc((1800px - 20px * min(5, var(--max-visible-cards))) / min(5, var(--max-visible-cards)));
}
}

Expand Down Expand Up @@ -1314,7 +1379,7 @@ Producthunt item
scroll-snap-type: y mandatory;
}

.layoutLayers > * {
.layoutLayers>* {
scroll-snap-align: end;
}

Expand All @@ -1337,10 +1402,7 @@ Producthunt item
}

.preload * {
-webkit-transition: none !important;
-moz-transition: none !important;
-ms-transition: none !important;
-o-transition: none !important;
transition: none !important;
}

.defaultToast {
Expand All @@ -1349,6 +1411,7 @@ Producthunt item
color: var(--primary-text-color);
border-radius: 10px;
}

.capitalize {
text-transform: capitalize;
}
}
49 changes: 43 additions & 6 deletions src/components/Layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,41 @@ import { useUserPreferences } from 'src/stores/preferences'

export const Header = () => {
const [themeIcon, setThemeIcon] = useState(<BsMoonFill />)
const { theme, setTheme, setDNDDuration, isDNDModeActive } = useUserPreferences()
const { theme, setTheme, themePreferences, setThemePreferences, setDNDDuration, isDNDModeActive } = useUserPreferences()
const { userBookmarks } = useBookmarks()
const navigate = useNavigate()
const location = useLocation()

// Check and update theme based on time
useEffect(() => {
const checkAutoTheme = () => {
if (themePreferences.mode === 'auto') {
const now = new Date()
const currentHour = now.getHours()
const { autoStartHour, autoEndHour } = themePreferences

// If start hour is less than end hour, dark mode is during the same day
// If start hour is greater than end hour, dark mode spans across midnight
const isDarkModeTime = autoStartHour <= autoEndHour
? currentHour >= autoStartHour || currentHour < autoEndHour
: currentHour >= autoStartHour && currentHour < autoEndHour

const newTheme = isDarkModeTime ? 'dark' : 'light'
if (theme !== newTheme) {
setTheme(newTheme)
trackThemeSelect(newTheme)
identifyUserTheme(newTheme)
}
}
}

checkAutoTheme()
const interval = setInterval(checkAutoTheme, 60000) // Check every minute
return () => clearInterval(interval)
}, [themePreferences, theme, setTheme])

useEffect(() => {
document.documentElement.classList.add(theme)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

useEffect(() => {
Expand All @@ -36,10 +63,20 @@ export const Header = () => {
}, [theme])

const onThemeChange = () => {
const newTheme = theme === 'dark' ? 'light' : 'dark'
setTheme(newTheme)
trackThemeSelect(newTheme)
identifyUserTheme(newTheme)
if (themePreferences.mode === 'auto') {
// Switch to manual mode with toggled theme
setThemePreferences({ mode: 'manual' })
const newTheme = theme === 'dark' ? 'light' : 'dark'
setTheme(newTheme)
trackThemeSelect(newTheme)
identifyUserTheme(newTheme)
} else {
// Already in manual mode, just toggle theme
const newTheme = theme === 'dark' ? 'light' : 'dark'
setTheme(newTheme)
trackThemeSelect(newTheme)
identifyUserTheme(newTheme)
}
}

const onSettingsClick = () => {
Expand Down
Loading