Skip to content
Merged
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
60 changes: 60 additions & 0 deletions noteUZ-frontend/src/components/ThemeToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// components/ThemeToggle.tsx
import { useEffect, useState } from 'react';
import { getTheme, setTheme, applyTheme, watchSystemTheme, getEffectiveTheme, type ThemeMode } from '../lib/theme';
Comment thread
lifeoverthinker marked this conversation as resolved.

export default function ThemeToggle() {
const [theme, setThemeState] = useState<ThemeMode>('system');
const [effectiveTheme, setEffectiveTheme] = useState<'light' | 'dark'>('light');

// Inicjalizacja przy montowaniu komponentu
Comment thread
lifeoverthinker marked this conversation as resolved.
useEffect(() => {
const current = getTheme();
setThemeState(current);
setEffectiveTheme(getEffectiveTheme());

// Jeśli system, nasłuchuj zmian
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is in Polish. Consider translating to English for consistency: "If system, listen for changes".

Suggested change
// Jeśli system, nasłuchuj zmian
// If system, listen for changes

Copilot uses AI. Check for mistakes.
if (current === 'system') {
const unwatch = watchSystemTheme(() => {
setEffectiveTheme(getEffectiveTheme());
});
return unwatch;
}
}, []);
Comment thread
lifeoverthinker marked this conversation as resolved.

// Obsługi zmiany motywu
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is in Polish. Consider translating to English for consistency: "Handle theme change".

Suggested change
// Obsługi zmiany motywu
// Handle theme change

Copilot uses AI. Check for mistakes.
const handleToggle = () => {
const newTheme: ThemeMode = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
setThemeState(newTheme);
setEffectiveTheme(getEffectiveTheme());
Comment thread
lifeoverthinker marked this conversation as resolved.
};
Comment thread
lifeoverthinker marked this conversation as resolved.

return (
<button
onClick={handleToggle}
className="theme-toggle"
title={`Przełącz na motyw ${effectiveTheme === 'light' ? 'ciemny' : 'jasny'}`}
aria-label={`Motyw: ${effectiveTheme}`}
>
{effectiveTheme === 'light' ? (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
{/* Moon icon */}
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
) : (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
{/* Sun icon */}
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
)}
</button>
);
}
59 changes: 59 additions & 0 deletions noteUZ-frontend/src/lib/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// lib/theme.ts
export type ThemeMode = 'light' | 'dark' | 'system';

const STORAGE_KEY = 'theme-preference';

export function getTheme(): ThemeMode {
if (typeof window === 'undefined') return 'system';

const stored = localStorage.getItem(STORAGE_KEY) as ThemeMode | null;
if (stored && ['light', 'dark', 'system'].includes(stored)) {
return stored;
}
return 'system';
}

export function setTheme(theme: ThemeMode): void {
if (typeof window === 'undefined') return;

localStorage.setItem(STORAGE_KEY, theme);
applyTheme(theme);
}

export function applyTheme(theme: ThemeMode): void {
if (typeof document === 'undefined') return;

const html = document.documentElement;
const isDark = theme === 'dark' ||
(theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);

if (isDark) {
html.setAttribute('data-theme', 'dark');
} else {
html.setAttribute('data-theme', 'light');
}
}

export function watchSystemTheme(callback: (isDark: boolean) => void): () => void {
if (typeof window === 'undefined') return () => {};

const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handler = (e: MediaQueryListEvent) => {
callback(e.matches);
};

mediaQuery.addEventListener('change', handler);
return () => mediaQuery.removeEventListener('change', handler);
}

export function getEffectiveTheme(): 'light' | 'dark' {
const theme = getTheme();
if (theme === 'dark') return 'dark';
if (theme === 'light') return 'light';

if (typeof window !== 'undefined') {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}

return 'light';
}
15 changes: 15 additions & 0 deletions noteUZ-frontend/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// pages/_app.tsx
import type { AppProps } from 'next/app';
import { useEffect } from 'react';
import { applyTheme, getTheme } from '../lib/theme';
import '../styles/globals.css';

export default function App({ Component, pageProps }: AppProps) {
// Zastosuj motyw przy załadowaniu aplikacji
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is in Polish. Consider translating to English for consistency: "Apply theme on application load".

Suggested change
// Zastosuj motyw przy załadowaniu aplikacji
// Apply theme on application load

Copilot uses AI. Check for mistakes.
useEffect(() => {
const theme = getTheme();
applyTheme(theme);
}, []);

return <Component {...pageProps} />;
Comment thread
lifeoverthinker marked this conversation as resolved.
}
10 changes: 10 additions & 0 deletions noteUZ-frontend/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Head from 'next/head';
import Link from 'next/link';
import React, { useEffect, useState } from 'react';
import ThemeToggle from '../components/ThemeToggle';
import s from '../styles/Home.module.css';

const API = process.env.NEXT_PUBLIC_API_URL ?? '';
Expand Down Expand Up @@ -79,6 +80,7 @@ export default function Home() {
</div>

<div className={s.rightGroup}>
<ThemeToggle />
{isLoggedIn ? (
<button className={s.ctaLinkInline} onClick={onLogout} disabled={busy}>
{busy ? 'Wylogowywanie…' : 'Wyloguj'}
Expand Down Expand Up @@ -116,6 +118,14 @@ export default function Home() {
<button onClick={async () => {
const r = await fetch(`${API}/api/auth/me`, { credentials: 'include' });
alert('ME status: ' + r.status);
}} style={{
padding: '8px 12px',
borderRadius: '8px',
border: '1px solid var(--border)',
background: 'var(--card-bg)',
color: 'var(--foreground)',
cursor: 'pointer',
transition: 'all 0.3s ease'
}}>
Sprawdź sesję
</button>
Expand Down
71 changes: 70 additions & 1 deletion noteUZ-frontend/src/styles/Home.module.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* styles/Home.module.css */
.page {
min-height: 100vh;
display: flex;
Expand All @@ -7,6 +8,7 @@
color: var(--foreground, #171717);
font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial;
padding: 0;
transition: background-color 0.3s ease, color 0.3s ease;
}

/* Header */
Expand All @@ -18,6 +20,7 @@
background: var(--background);
border-bottom: 1px solid rgba(15,23,42,0.04);
backdrop-filter: blur(6px);
transition: background-color 0.3s ease;
}

.navInner {
Expand Down Expand Up @@ -56,6 +59,12 @@
padding: 8px;
border-radius: 8px;
cursor: pointer;
color: var(--foreground);
transition: all 0.3s ease;
}

.iconButton:hover {
background: var(--card-bg);
}

/* Search */
Expand All @@ -70,8 +79,15 @@
border-radius: 12px;
border: 1px solid rgba(15,23,42,0.06);
background: var(--background);
color: var(--foreground);
box-shadow: 0 6px 16px rgba(2,6,23,0.04);
outline: none;
transition: all 0.3s ease;
}

.searchInput:focus {
border-color: #4f46e5;
box-shadow: 0 6px 20px rgba(79, 70, 229, 0.15);
}

/* Container */
Expand Down Expand Up @@ -117,6 +133,11 @@
border-radius: 12px;
background: linear-gradient(180deg, #fbfdff 0%, #eef6ff 100%);
box-shadow: 0 8px 30px rgba(2,6,23,0.04);
transition: background 0.3s ease;
}

[data-theme='dark'] .hero {
background: linear-gradient(180deg, #1a1a1a 0%, #1a1a1a 100%);
}

.heroLeft {
Expand Down Expand Up @@ -147,6 +168,12 @@
font-weight: 600;
text-decoration: none;
box-shadow: 0 8px 22px rgba(255,122,24,0.16);
transition: all 0.3s ease;
}

.ctaLink:hover {
transform: translateY(-2px);
box-shadow: 0 10px 28px rgba(255,122,24,0.24);
}

.ctaLinkInline {
Expand All @@ -157,16 +184,35 @@
color: white;
font-weight: 600;
text-decoration: none;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}

/* Lang/Secondary link (zachowane pod klasą .secondary jeśli potrzebne później) */
.ctaLinkInline:hover {
transform: translateY(-1px);
}

.ctaLinkInline:disabled {
opacity: 0.6;
cursor: not-allowed;
}

/* Secondary link */
.secondary {
padding: 8px 10px;
border-radius: 10px;
background: transparent;
color: #334155;
Comment thread
lifeoverthinker marked this conversation as resolved.
text-decoration: none;
border: 1px solid rgba(15,23,42,0.06);
transition: all 0.3s ease;
}

.secondary:hover {
background: var(--card-bg);
border-color: #4f46e5;
color: #4f46e5;
Comment thread
lifeoverthinker marked this conversation as resolved.
}

/* Text */
Expand All @@ -192,6 +238,12 @@
box-shadow: 0 10px 30px rgba(2,6,23,0.06);
border: 1px solid #eef6ff;
background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
transition: all 0.3s ease;
}

[data-theme='dark'] .device {
border: 1px solid #333333;
background: linear-gradient(180deg, #1a1a1a 0%, #0a0a0a 100%);
}

.deviceHeader {
Expand All @@ -201,12 +253,18 @@

.deviceBody {
padding: 18px;
background: var(--background);
}

.noteMock {
background: #fbfdff;
Copy link

Copilot AI Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .noteMock class uses a hardcoded background color #fbfdff that won't properly adapt to dark mode. While there's a dark mode override at line 266-267, the light mode should use var(--card-bg) for consistency with the rest of the theme system.

Suggested change
background: #fbfdff;
background: var(--card-bg);

Copilot uses AI. Check for mistakes.
border-radius: 8px;
padding: 12px;
transition: background-color 0.3s ease;
}

[data-theme='dark'] .noteMock {
background: var(--card-bg);
}

.noteLine {
Expand Down Expand Up @@ -244,6 +302,16 @@
border-radius: 10px;
padding: 16px;
box-shadow: 0 8px 22px rgba(2,6,23,0.04);
transition: all 0.3s ease;
}

[data-theme='dark'] .feature {
background: var(--card-bg);
}

.feature:hover {
transform: translateY(-2px);
box-shadow: 0 10px 28px rgba(2,6,23,0.08);
}

.featureIcon {
Expand All @@ -255,6 +323,7 @@
margin: 0;
font-size: 14px;
font-weight: 600;
color: var(--foreground);
}

.featureText {
Expand Down
Loading