1
0

Implement header, notes and google in dashboard

This commit is contained in:
2025-07-18 10:08:03 +02:00
parent d3f733638e
commit 68480757dc
16 changed files with 1945 additions and 14 deletions

View File

@@ -5,7 +5,7 @@
<title>OpenWall</title>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
content="default-src *; script-src * 'unsafe-inline' 'unsafe-eval'; style-src * 'unsafe-inline'; img-src * data: blob:; frame-src *; connect-src *; font-src *; media-src *; object-src *; child-src *;"
/>
</head>

View File

@@ -1,9 +1,38 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import Header from './common/Header'
import Calendar from './pages/Calendar'
import Shopping from './pages/Shopping'
import Notes from './pages/Notes'
import Search from './pages/Search'
// Configuration
const BACKGROUND_IMAGE_URL = 'https://cdn.pixabay.com/photo/2018/11/19/03/26/iceland-3824494_1280.jpg'
const APP_BACKGROUND_STYLE = {
backgroundImage: `url(${BACKGROUND_IMAGE_URL})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundAttachment: 'fixed',
minHeight: '100vh'
}
const App = () => {
return (
<>
<h1>Not implemented yet</h1>
</>
<Router>
<div className="app" style={APP_BACKGROUND_STYLE}>
<Header />
<main className="app__main">
<Routes>
<Route path="/" element={<Calendar />} />
<Route path="/shopping" element={<Shopping />} />
<Route path="/notes" element={<Notes />} />
<Route path="/search" element={<Search />} />
</Routes>
</main>
</div>
</Router>
)
}
export default App;
export default App

View File

@@ -0,0 +1,119 @@
import { useState, useEffect } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'
import { FiCalendar, FiShoppingBag, FiBookOpen, FiSearch } from 'react-icons/fi'
import './styles.sass'
// Static color configuration
const HEADER_COLORS = {
primary: 'rgba(76, 175, 160, 0.25)',
secondary: 'rgba(34, 139, 156, 0.35)',
tertiary: 'rgba(21, 94, 117, 0.4)',
accent: 'rgba(147, 197, 253, 0.3)'
}
// Icon-specific colors for better differentiation
const ICON_COLORS = {
calendar: '#FF6B6B', // Red
shopping: '#4ECDC4', // Teal
notes: '#45B7D1', // Blue
search: '#FFA726' // Orange
}
const Header = () => {
const [currentTime, setCurrentTime] = useState(new Date())
const navigate = useNavigate()
const location = useLocation()
useEffect(() => {
const timer = setInterval(() => {
setCurrentTime(new Date())
}, 1000)
return () => clearInterval(timer)
}, [])
const formatTime = (date) => {
return date.toLocaleTimeString('de-DE', {
hour: '2-digit',
minute: '2-digit'
})
}
const getCurrentMonth = (date) => {
return date.toLocaleDateString('de-DE', { month: 'long' })
}
const navigationItems = [
{ id: 'calendar', icon: FiCalendar, label: 'Kalender', path: '/' },
{ id: 'shopping', icon: FiShoppingBag, label: 'Einkaufen', path: '/shopping' },
{ id: 'notes', icon: FiBookOpen, label: 'Notizen', path: '/notes' },
{ id: 'search', icon: FiSearch, label: 'Suchen', path: '/search' }
]
const getActiveIcon = () => {
const currentPath = location.pathname
const activeItem = navigationItems.find(item => item.path === currentPath)
return activeItem ? activeItem.id : 'calendar'
}
const handleNavigation = (path) => {
navigate(path)
}
const headerStyle = {
background: `linear-gradient(135deg, ${HEADER_COLORS.primary}, ${HEADER_COLORS.secondary}, ${HEADER_COLORS.tertiary})`,
borderColor: HEADER_COLORS.accent
}
const buttonStyle = {
background: `linear-gradient(135deg, ${HEADER_COLORS.accent}, ${HEADER_COLORS.primary})`,
borderColor: HEADER_COLORS.accent,
color: '#ffffff',
boxShadow: `0 8px 32px ${HEADER_COLORS.tertiary}, inset 0 1px 0 ${HEADER_COLORS.accent}`
}
const activeButtonStyle = {
background: `linear-gradient(135deg, ${HEADER_COLORS.primary}, ${HEADER_COLORS.secondary})`,
borderColor: HEADER_COLORS.primary,
color: '#ffffff',
boxShadow: `0 12px 40px ${HEADER_COLORS.primary}, inset 0 2px 0 ${HEADER_COLORS.accent}`
}
return (
<header className="header" style={headerStyle}>
<nav className="header__nav">
<div className="header__left">
<span className="header__month">{getCurrentMonth(currentTime)}</span>
<span className="header__time">{formatTime(currentTime)}</span>
</div>
<div className="header__right">
{navigationItems.map(({ id, icon: Icon, label, path }) => {
const isActive = getActiveIcon() === id
const iconColor = ICON_COLORS[id]
const buttonStyleWithIcon = {
...(isActive ? activeButtonStyle : buttonStyle),
'--icon-color': iconColor
}
return (
<button
key={id}
className={`header__nav-item ${isActive ? 'header__nav-item--active' : ''}`}
onClick={() => handleNavigation(path)}
aria-label={label}
title={label}
style={buttonStyleWithIcon}
>
<Icon style={{ color: iconColor, filter: 'drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))' }} />
</button>
)
})}
</div>
</nav>
</header>
)
}
export default Header

View File

@@ -0,0 +1 @@
export { default } from './Header'

View File

@@ -0,0 +1,161 @@
// Header Component - Dynamic Color Extraction from Background
.header
position: fixed
top: 0.5rem
left: 0.5rem
right: 0.5rem
z-index: 1000
padding: 1rem 2rem
backdrop-filter: blur(80px) saturate(180%)
border-radius: 24px
border: 1px solid
box-shadow: 0 20px 80px rgba(0, 0, 0, 0.15), 0 8px 32px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.4)
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1)
&:hover
backdrop-filter: blur(100px) saturate(200%)
box-shadow: 0 24px 96px rgba(0, 0, 0, 0.25), 0 12px 48px rgba(0, 0, 0, 0.15), inset 0 2px 0 rgba(255, 255, 255, 0.5)
transform: translateY(-1px)
&__nav
display: flex
justify-content: space-between
align-items: center
max-width: 100%
margin: 0 auto
&__left
display: flex
flex-direction: column
align-items: flex-start
gap: 0.125rem
&__month
font-size: 1.5rem
font-weight: 700
color: rgba(255, 255, 255, 0.95)
letter-spacing: -0.02em
text-shadow: 0 2px 8px rgba(21, 94, 117, 0.6), 0 1px 2px rgba(0, 0, 0, 0.3)
line-height: 1.1
&__time
font-size: 2.25rem
font-weight: 800
color: #ffffff
font-variant-numeric: tabular-nums
text-shadow: 0 3px 12px rgba(21, 94, 117, 0.8), 0 1px 4px rgba(0, 0, 0, 0.4)
line-height: 0.9
letter-spacing: -0.05em
&__right
display: flex
align-items: center
gap: 1rem
&__nav-item
display: flex
align-items: center
justify-content: center
width: 56px
height: 56px
border: none
border-radius: 18px
cursor: pointer
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1)
backdrop-filter: blur(40px)
border: 1px solid
font-size: 1.375rem
position: relative
overflow: hidden
// Allow custom icon colors
svg
transition: all 0.3s ease
&::before
content: ''
position: absolute
top: 0
left: 0
right: 0
bottom: 0
opacity: 0
transition: opacity 0.3s ease
border-radius: 18px
&:hover
transform: translateY(-3px) scale(1.08)
svg
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4)) !important
&::before
opacity: 1
&:active
transform: translateY(-1px) scale(1.03)
&--active
border: 1px solid
svg
filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.5)) !important
&::before
opacity: 1
&:hover
transform: translateY(-3px) scale(1.08)
// Responsive Design
@media (max-width: 768px)
.header
top: 0.375rem
left: 0.375rem
right: 0.375rem
padding: 0.875rem 1.75rem
border-radius: 20px
&__left
gap: 0.0625rem
&__month
font-size: 1.25rem
&__time
font-size: 1.875rem
&__right
gap: 0.875rem
&__nav-item
width: 52px
height: 52px
border-radius: 16px
font-size: 1.25rem
@media (max-width: 480px)
.header
top: 0.25rem
left: 0.25rem
right: 0.25rem
padding: 0.75rem 1.5rem
border-radius: 18px
&__left
gap: 0.0625rem
&__month
font-size: 1.125rem
&__time
font-size: 1.625rem
&__right
gap: 0.75rem
&__nav-item
width: 48px
height: 48px
border-radius: 14px
font-size: 1.125rem

View File

@@ -0,0 +1,71 @@
// Global Styles - Light Mode with Waterfall Background
// Reset and base styles
*
margin: 0
padding: 0
box-sizing: border-box
html, body
height: 100vh
width: 100vw
overflow: hidden
body
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif
background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.3)), url('https://cdn.pixabay.com/photo/2024/07/16/23/33/waterfall-8900207_1280.png')
background-size: cover
background-position: center
background-attachment: fixed
color: #1e293b
font-weight: 400
letter-spacing: -0.01em
line-height: 1.5
-webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale
#root
height: 100vh
width: 100vw
display: flex
flex-direction: column
// App Layout Styles
.app
height: 100vh
width: 100vw
display: flex
flex-direction: column
&__main
flex: 1
padding-top: 5rem
display: flex
align-items: center
justify-content: center
&__content
text-align: center
backdrop-filter: blur(40px) saturate(180%)
background: rgba(255, 255, 255, 0.25)
padding: 4rem
border-radius: 32px
border: 1px solid rgba(255, 255, 255, 0.3)
box-shadow: 0 16px 64px rgba(0, 0, 0, 0.1), 0 8px 32px rgba(0, 0, 0, 0.05), inset 0 1px 0 rgba(255, 255, 255, 0.4)
max-width: 600px
margin: 0 auto
h1
font-size: 3rem
font-weight: 800
margin-bottom: 1.5rem
background: linear-gradient(135deg, #1e293b, #475569, #0f766e)
-webkit-background-clip: text
-webkit-text-fill-color: transparent
background-clip: text
line-height: 1.2
p
font-size: 1.25rem
color: rgba(30, 41, 59, 0.8)
font-weight: 500
line-height: 1.6

View File

@@ -1,5 +1,6 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.sass'
import App from './App'
createRoot(document.getElementById('root')).render(

View File

@@ -0,0 +1,9 @@
const Calendar = () => {
return (
<div>
<h1>Kalender</h1>
</div>
)
}
export default Calendar

View File

@@ -0,0 +1,203 @@
import { useRef, useEffect, useState } from 'react'
import { FiEdit3, FiTrash, FiChevronDown } from 'react-icons/fi'
import { TbEraser } from 'react-icons/tb'
import './Notes.sass'
const Notes = () => {
const canvasRef = useRef(null)
const [isDrawing, setIsDrawing] = useState(false)
const [tool, setTool] = useState('pen') // 'pen' or 'eraser'
const [penColor, setPenColor] = useState('#2d3748')
const [showColorPicker, setShowColorPicker] = useState(false)
const colors = [
'#2d3748', // Dark gray
'#000000', // Black
'#e53e3e', // Red
'#3182ce', // Blue
'#38a169', // Green
'#d69e2e', // Yellow
'#805ad5', // Purple
'#dd6b20', // Orange
'#e91e63', // Pink
'#00acc1' // Cyan
]
useEffect(() => {
const canvas = canvasRef.current
const ctx = canvas.getContext('2d')
// Set canvas size
const resizeCanvas = () => {
const container = canvas.parentElement
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
canvas.width = container.clientWidth
canvas.height = container.clientHeight
// Set drawing properties
ctx.lineCap = 'round'
ctx.lineJoin = 'round'
ctx.imageSmoothingEnabled = true
// Restore canvas content after resize
ctx.putImageData(imageData, 0, 0)
// Load saved canvas data
loadCanvasFromStorage()
}
resizeCanvas()
window.addEventListener('resize', resizeCanvas)
return () => window.removeEventListener('resize', resizeCanvas)
}, [])
const saveCanvasToStorage = () => {
const canvas = canvasRef.current
const dataURL = canvas.toDataURL()
localStorage.setItem('notes-canvas', dataURL)
}
const loadCanvasFromStorage = () => {
const canvas = canvasRef.current
const ctx = canvas.getContext('2d')
const savedData = localStorage.getItem('notes-canvas')
if (savedData) {
const img = new Image()
img.onload = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0)
}
img.src = savedData
}
}
const startDrawing = (e) => {
setIsDrawing(true)
const canvas = canvasRef.current
const ctx = canvas.getContext('2d')
const rect = canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
ctx.beginPath()
ctx.moveTo(x, y)
}
const draw = (e) => {
if (!isDrawing) return
const canvas = canvasRef.current
const ctx = canvas.getContext('2d')
const rect = canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
if (tool === 'pen') {
ctx.globalCompositeOperation = 'source-over'
ctx.strokeStyle = penColor
ctx.lineWidth = 3
ctx.lineTo(x, y)
ctx.stroke()
} else if (tool === 'eraser') {
ctx.globalCompositeOperation = 'destination-out'
ctx.lineWidth = 40 // Increased eraser size
ctx.lineTo(x, y)
ctx.stroke()
}
}
const stopDrawing = () => {
setIsDrawing(false)
// Save canvas state after drawing
saveCanvasToStorage()
}
const clearCanvas = () => {
const canvas = canvasRef.current
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
// Clear saved state
localStorage.removeItem('notes-canvas')
}
return (
<div className="notes-page">
<div className="notes-container">
{/* Toolbar */}
<div className="notes-toolbar">
<div className="pen-tool-group">
<button
className={`tool-button ${tool === 'pen' ? 'active' : ''}`}
onClick={() => setTool('pen')}
title="Stift"
style={{ backgroundColor: tool === 'pen' ? penColor + '20' : undefined }}
>
<FiEdit3 style={{ color: tool === 'pen' ? penColor : undefined }} />
</button>
<button
className="color-picker-button"
onClick={() => setShowColorPicker(!showColorPicker)}
title="Farbe wählen"
style={{ backgroundColor: penColor }}
>
<FiChevronDown />
</button>
{showColorPicker && (
<div className="color-picker-popover">
<div className="color-grid">
{colors.map((color) => (
<button
key={color}
className={`color-option ${penColor === color ? 'active' : ''}`}
style={{ backgroundColor: color }}
onClick={() => {
setPenColor(color)
setShowColorPicker(false)
}}
title={`Farbe: ${color}`}
/>
))}
</div>
</div>
)}
</div>
<button
className={`tool-button ${tool === 'eraser' ? 'active' : ''}`}
onClick={() => setTool('eraser')}
title="Radiergummi"
>
<TbEraser />
</button>
<button
className="tool-button clear-button"
onClick={clearCanvas}
title="Alles löschen"
>
<FiTrash />
</button>
</div>
{/* Canvas Container */}
<div className="canvas-container">
<canvas
ref={canvasRef}
className="drawing-canvas"
onMouseDown={startDrawing}
onMouseMove={draw}
onMouseUp={stopDrawing}
onMouseLeave={stopDrawing}
/>
</div>
</div>
</div>
)
}
export default Notes

View File

@@ -0,0 +1,249 @@
// Notes Page - Drawing Canvas with Glassmorphism (Matching Search Page Structure)
.notes-page
padding: 2rem 0.75rem 0.75rem 0.75rem
height: calc(100vh - 6rem)
width: 100%
.notes-container
position: relative
width: 100%
height: 100%
backdrop-filter: blur(60px) saturate(200%)
background: linear-gradient(135deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.2))
border-radius: 28px
border: 1px solid rgba(255, 255, 255, 0.5)
box-shadow: 0 16px 64px rgba(0, 0, 0, 0.1), 0 8px 32px rgba(0, 0, 0, 0.05), inset 0 2px 0 rgba(255, 255, 255, 0.6), inset 0 -1px 0 rgba(0, 0, 0, 0.1)
padding: 1.5rem
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)
overflow: hidden
&:hover
backdrop-filter: blur(80px) saturate(220%)
background: linear-gradient(135deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.3))
box-shadow: 0 20px 80px rgba(0, 0, 0, 0.15), 0 10px 40px rgba(0, 0, 0, 0.08), inset 0 2px 0 rgba(255, 255, 255, 0.7)
transform: translateY(-2px)
.notes-toolbar
position: absolute
bottom: 1rem
left: 50%
transform: translateX(-50%)
z-index: 10
display: flex
align-items: center
gap: 0.75rem
padding: 0.75rem 1rem
backdrop-filter: blur(40px) saturate(180%)
background: rgba(255, 255, 255, 0.2)
border-radius: 16px
border: 1px solid rgba(255, 255, 255, 0.3)
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.4)
.pen-tool-group
position: relative
display: flex
align-items: center
gap: 0.25rem
.color-picker-button
display: flex
align-items: center
justify-content: center
width: 24px
height: 44px
border: none
border-radius: 0 14px 14px 0
border: 1px solid rgba(255, 255, 255, 0.4)
border-left: none
cursor: pointer
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)
font-size: 0.875rem
color: white
&:hover
transform: translateY(-2px)
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15)
.color-picker-popover
position: absolute
bottom: calc(100% + 0.5rem)
left: 0
backdrop-filter: blur(40px) saturate(180%)
background: rgba(255, 255, 255, 0.25)
border-radius: 16px
border: 1px solid rgba(255, 255, 255, 0.3)
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.4)
padding: 0.75rem
z-index: 20
.color-grid
display: grid
grid-template-columns: repeat(5, 1fr)
gap: 0.5rem
.color-option
width: 32px
height: 32px
border: 2px solid rgba(255, 255, 255, 0.3)
border-radius: 12px
cursor: pointer
transition: all 0.2s ease
position: relative
&:hover
transform: scale(1.1)
border-color: rgba(255, 255, 255, 0.6)
&.active
transform: scale(1.15)
border-color: rgba(255, 255, 255, 0.8)
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2)
&::after
content: ''
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
color: white
font-size: 0.875rem
font-weight: bold
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8)
.toolbar-section
display: flex
align-items: center
gap: 0.75rem
.tool-button
display: flex
align-items: center
justify-content: center
width: 44px
height: 44px
border: none
border-radius: 14px
background: rgba(255, 255, 255, 0.3)
backdrop-filter: blur(20px)
border: 1px solid rgba(255, 255, 255, 0.4)
color: rgba(50, 50, 50, 0.8)
cursor: pointer
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)
font-size: 1.125rem
&:hover
background: rgba(255, 255, 255, 0.5)
color: rgba(50, 50, 50, 1)
transform: translateY(-2px)
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15)
&.active
background: rgba(255, 255, 255, 0.6)
color: rgba(50, 50, 50, 1)
border-color: rgba(255, 255, 255, 0.6)
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2)
&.clear-button
background: rgba(239, 68, 68, 0.3)
border-color: rgba(239, 68, 68, 0.4)
color: rgba(50, 50, 50, 0.8)
&:hover
background: rgba(239, 68, 68, 0.5)
color: rgba(50, 50, 50, 1)
transform: translateY(-2px)
box-shadow: 0 8px 24px rgba(239, 68, 68, 0.2)
// Special styling for pen tool in group
.pen-tool-group &:first-child
border-radius: 14px 0 0 14px
border-right: none
.canvas-container
width: 100%
height: 100%
border-radius: 20px
background: rgba(255, 255, 255, 0.9)
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5)
overflow: hidden
.drawing-canvas
width: 100%
height: 100%
cursor: crosshair
display: block
background: #ffffff
border-radius: 20px
&.eraser-mode
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="10" r="8" fill="none" stroke="black" stroke-width="2"/></svg>') 10 10, auto
// Responsive Design
@media (max-width: 768px)
.notes-page
padding: 1.5rem 0.5rem 0.5rem 0.5rem
.notes-container
border-radius: 24px
padding: 1.25rem
.canvas-container
border-radius: 16px
.drawing-canvas
border-radius: 16px
.notes-toolbar
bottom: 0.75rem
padding: 0.625rem 0.875rem
gap: 0.625rem
.tool-button
width: 40px
height: 40px
font-size: 1rem
.color-picker-button
width: 20px
height: 40px
.color-option
width: 28px
height: 28px
@media (max-width: 480px)
.notes-page
padding: 1rem 0.375rem 0.375rem 0.375rem
.notes-container
border-radius: 20px
padding: 1rem
.canvas-container
border-radius: 12px
.drawing-canvas
border-radius: 12px
.notes-toolbar
bottom: 0.5rem
padding: 0.5rem 0.75rem
gap: 0.5rem
border-radius: 14px
.tool-button
width: 36px
height: 36px
border-radius: 12px
font-size: 0.875rem
.color-picker-button
width: 18px
height: 36px
.color-option
width: 24px
height: 24px
.color-grid
grid-template-columns: repeat(4, 1fr)

View File

@@ -0,0 +1,20 @@
import './Search.sass'
const Search = () => {
return (
<div className="search-page">
<div className="search-container">
<div className="google-embed-container">
<iframe
src="https://www.google.com/search?igu=1"
className="google-iframe"
title="Google Search"
allow="microphone"
/>
</div>
</div>
</div>
)
}
export default Search

View File

@@ -0,0 +1,58 @@
// Search Page - Full Screen Glassmorphism Google Embed
.search-page
padding: 2rem 0.75rem 0.75rem 0.75rem
height: calc(100vh - 6rem)
width: 100%
.search-container
width: 100%
height: 100%
.google-embed-container
width: 100%
height: 100%
backdrop-filter: blur(60px) saturate(200%)
background: linear-gradient(135deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.2))
border-radius: 28px
border: 1px solid rgba(255, 255, 255, 0.5)
box-shadow: 0 16px 64px rgba(0, 0, 0, 0.1), 0 8px 32px rgba(0, 0, 0, 0.05), inset 0 2px 0 rgba(255, 255, 255, 0.6), inset 0 -1px 0 rgba(0, 0, 0, 0.1)
padding: 1.5rem
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)
overflow: hidden
&:hover
backdrop-filter: blur(80px) saturate(220%)
background: linear-gradient(135deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.3))
box-shadow: 0 20px 80px rgba(0, 0, 0, 0.15), 0 10px 40px rgba(0, 0, 0, 0.08), inset 0 2px 0 rgba(255, 255, 255, 0.7)
transform: translateY(-2px)
.google-iframe
width: 100%
height: 100%
border: none
border-radius: 20px
background: rgba(255, 255, 255, 0.9)
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5)
// Responsive Design
@media (max-width: 768px)
.search-page
padding: 1.5rem 0.5rem 0.5rem 0.5rem
.google-embed-container
border-radius: 24px
padding: 1.25rem
.google-iframe
border-radius: 16px
@media (max-width: 480px)
.search-page
padding: 1rem 0.375rem 0.375rem 0.375rem
.google-embed-container
border-radius: 20px
padding: 1rem
.google-iframe
border-radius: 12px

View File

@@ -0,0 +1,9 @@
const Shopping = () => {
return (
<div>
<h1>Einkaufen</h1>
</div>
)
}
export default Shopping

View File

@@ -0,0 +1,697 @@
// Pages Styles - Light Mode with Glass Effects
// Common page container
.page-container
padding: 2rem
min-height: calc(100vh - 6rem)
overflow-y: auto
// Calendar Styles
.calendar-container
max-width: 1200px
margin: 0 auto
.calendar-header
display: flex
justify-content: space-between
align-items: center
margin-bottom: 2rem
flex-wrap: wrap
gap: 1rem
h1
font-size: 2rem
font-weight: 700
color: #1e293b
margin: 0
.calendar-nav
display: flex
align-items: center
gap: 1rem
background: rgba(255, 255, 255, 0.3)
padding: 0.75rem 1.5rem
border-radius: 16px
backdrop-filter: blur(20px)
border: 1px solid rgba(255, 255, 255, 0.4)
h2
font-size: 1.25rem
font-weight: 600
color: #1e293b
margin: 0
min-width: 200px
text-align: center
.nav-btn, .add-event-btn
background: linear-gradient(135deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.2))
border: 1px solid rgba(255, 255, 255, 0.5)
border-radius: 12px
padding: 0.75rem 1rem
color: #475569
cursor: pointer
transition: all 0.3s ease
backdrop-filter: blur(20px)
font-weight: 500
&:hover
background: linear-gradient(135deg, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.4))
transform: translateY(-2px)
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1)
.add-event-btn
display: flex
align-items: center
gap: 0.5rem
font-size: 0.875rem
.calendar-grid
background: rgba(255, 255, 255, 0.25)
border-radius: 24px
padding: 2rem
margin-bottom: 2rem
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
box-shadow: 0 16px 64px rgba(0, 0, 0, 0.1)
.calendar-days-header
display: grid
grid-template-columns: repeat(7, 1fr)
gap: 1rem
margin-bottom: 1rem
.day-header
text-align: center
font-weight: 600
color: #475569
padding: 0.75rem
.calendar-days
display: grid
grid-template-columns: repeat(7, 1fr)
gap: 1rem
.calendar-day
aspect-ratio: 1
display: flex
align-items: center
justify-content: center
border-radius: 12px
cursor: pointer
font-weight: 500
transition: all 0.3s ease
&.empty
cursor: default
&.active
background: rgba(255, 255, 255, 0.2)
color: #1e293b
&:hover
background: rgba(255, 255, 255, 0.4)
transform: scale(1.05)
&.today
background: linear-gradient(135deg, rgba(59, 130, 246, 0.3), rgba(37, 99, 235, 0.3))
color: white
font-weight: 700
&.selected
background: linear-gradient(135deg, rgba(168, 85, 247, 0.3), rgba(147, 51, 234, 0.3))
color: white
// Shopping Styles
.shopping-container
max-width: 800px
margin: 0 auto
.shopping-header
display: flex
justify-content: space-between
align-items: center
margin-bottom: 2rem
h1
display: flex
align-items: center
gap: 0.75rem
font-size: 2rem
font-weight: 700
color: #1e293b
margin: 0
.shopping-stats
display: flex
gap: 1rem
span
background: rgba(255, 255, 255, 0.3)
padding: 0.5rem 1rem
border-radius: 12px
font-size: 0.875rem
font-weight: 500
color: #475569
.add-item-form
background: rgba(255, 255, 255, 0.25)
border-radius: 20px
padding: 1.5rem
margin-bottom: 2rem
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
.input-group
display: flex
gap: 1rem
input
flex: 1
padding: 0.75rem 1rem
border: 1px solid rgba(255, 255, 255, 0.4)
border-radius: 12px
background: rgba(255, 255, 255, 0.3)
color: #1e293b
font-size: 1rem
backdrop-filter: blur(20px)
&::placeholder
color: rgba(30, 41, 59, 0.6)
&:focus
outline: none
border-color: rgba(59, 130, 246, 0.5)
background: rgba(255, 255, 255, 0.4)
.add-btn
background: linear-gradient(135deg, rgba(16, 185, 129, 0.3), rgba(5, 150, 105, 0.3))
border: 1px solid rgba(255, 255, 255, 0.4)
border-radius: 12px
padding: 0.75rem 1rem
color: white
cursor: pointer
transition: all 0.3s ease
&:hover
background: linear-gradient(135deg, rgba(16, 185, 129, 0.4), rgba(5, 150, 105, 0.4))
transform: translateY(-2px)
.shopping-section
margin-bottom: 2rem
h3
font-size: 1.25rem
font-weight: 600
color: #1e293b
margin-bottom: 1rem
.items-list
background: rgba(255, 255, 255, 0.25)
border-radius: 20px
padding: 1.5rem
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
.shopping-item
display: flex
align-items: center
gap: 1rem
padding: 1rem 0
border-bottom: 1px solid rgba(255, 255, 255, 0.2)
&:last-child
border-bottom: none
&.completed
opacity: 0.6
.item-name
text-decoration: line-through
.check-btn
width: 32px
height: 32px
border-radius: 50%
border: 2px solid rgba(16, 185, 129, 0.5)
background: transparent
color: transparent
cursor: pointer
transition: all 0.3s ease
&.checked
background: linear-gradient(135deg, rgba(16, 185, 129, 0.8), rgba(5, 150, 105, 0.8))
color: white
&:hover
border-color: rgba(16, 185, 129, 0.8)
background: rgba(16, 185, 129, 0.1)
.item-details
flex: 1
display: flex
flex-direction: column
gap: 0.25rem
.item-name
font-weight: 500
color: #1e293b
.item-quantity, .item-category
font-size: 0.875rem
color: #64748b
.delete-btn
background: transparent
border: none
color: #ef4444
cursor: pointer
padding: 0.5rem
border-radius: 8px
transition: all 0.3s ease
&:hover
background: rgba(239, 68, 68, 0.1)
color: #dc2626
// Notes Styles
.notes-container
max-width: 1200px
margin: 0 auto
.notes-header
display: flex
justify-content: space-between
align-items: center
margin-bottom: 2rem
h1
font-size: 2rem
font-weight: 700
color: #1e293b
margin: 0
.add-note-btn
display: flex
align-items: center
gap: 0.5rem
background: linear-gradient(135deg, rgba(139, 92, 246, 0.3), rgba(124, 58, 237, 0.3))
border: 1px solid rgba(255, 255, 255, 0.4)
border-radius: 12px
padding: 0.75rem 1.5rem
color: white
cursor: pointer
font-weight: 500
transition: all 0.3s ease
&:hover
background: linear-gradient(135deg, rgba(139, 92, 246, 0.4), rgba(124, 58, 237, 0.4))
transform: translateY(-2px)
.note-editor
background: rgba(255, 255, 255, 0.25)
border-radius: 20px
padding: 2rem
margin-bottom: 2rem
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
.editor-header
display: flex
justify-content: space-between
align-items: center
margin-bottom: 1rem
gap: 1rem
.title-input
flex: 1
padding: 0.75rem 1rem
border: 1px solid rgba(255, 255, 255, 0.4)
border-radius: 12px
background: rgba(255, 255, 255, 0.3)
color: #1e293b
font-size: 1.125rem
font-weight: 600
&:focus
outline: none
border-color: rgba(59, 130, 246, 0.5)
.color-picker
display: flex
gap: 0.5rem
.color-option
width: 32px
height: 32px
border-radius: 50%
border: 2px solid transparent
cursor: pointer
transition: all 0.3s ease
&.selected
border-color: rgba(255, 255, 255, 0.8)
transform: scale(1.1)
.content-input
width: 100%
padding: 1rem
border: 1px solid rgba(255, 255, 255, 0.4)
border-radius: 12px
background: rgba(255, 255, 255, 0.3)
color: #1e293b
font-size: 1rem
line-height: 1.6
resize: vertical
margin-bottom: 1rem
&:focus
outline: none
border-color: rgba(59, 130, 246, 0.5)
.editor-actions
display: flex
gap: 1rem
.save-btn, .cancel-btn
display: flex
align-items: center
gap: 0.5rem
padding: 0.75rem 1.5rem
border-radius: 12px
cursor: pointer
font-weight: 500
transition: all 0.3s ease
.save-btn
background: linear-gradient(135deg, rgba(16, 185, 129, 0.3), rgba(5, 150, 105, 0.3))
border: 1px solid rgba(255, 255, 255, 0.4)
color: white
&:hover
background: linear-gradient(135deg, rgba(16, 185, 129, 0.4), rgba(5, 150, 105, 0.4))
.cancel-btn
background: rgba(255, 255, 255, 0.3)
border: 1px solid rgba(255, 255, 255, 0.4)
color: #475569
&:hover
background: rgba(255, 255, 255, 0.4)
.notes-grid
display: grid
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr))
gap: 1.5rem
.note-card
background: rgba(255, 255, 255, 0.25)
border-radius: 20px
padding: 1.5rem
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
border-left: 4px solid #3b82f6
transition: all 0.3s ease
&:hover
transform: translateY(-4px)
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15)
.note-header
display: flex
justify-content: space-between
align-items: flex-start
margin-bottom: 1rem
h3
font-size: 1.125rem
font-weight: 600
color: #1e293b
margin: 0
.note-actions
display: flex
gap: 0.5rem
button
background: transparent
border: none
color: #64748b
cursor: pointer
padding: 0.25rem
border-radius: 6px
transition: all 0.3s ease
&:hover
background: rgba(100, 116, 139, 0.1)
color: #475569
.note-content
margin-bottom: 1rem
p
color: #475569
line-height: 1.6
margin-bottom: 0.5rem
&:last-child
margin-bottom: 0
.note-footer
border-top: 1px solid rgba(255, 255, 255, 0.2)
padding-top: 1rem
.note-date
font-size: 0.875rem
color: #64748b
// Search Styles
.search-container
max-width: 800px
margin: 0 auto
.search-header
margin-bottom: 2rem
h1
font-size: 2rem
font-weight: 700
color: #1e293b
margin-bottom: 1.5rem
.search-input-container
position: relative
background: rgba(255, 255, 255, 0.25)
border-radius: 20px
padding: 1.5rem
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
.search-icon
position: absolute
left: 2.5rem
top: 50%
transform: translateY(-50%)
color: #64748b
font-size: 1.25rem
.search-input
width: 100%
padding: 1rem 1rem 1rem 3rem
border: none
background: transparent
color: #1e293b
font-size: 1.125rem
outline: none
&::placeholder
color: rgba(30, 41, 59, 0.6)
.search-suggestions
display: grid
grid-template-columns: 1fr 1fr
gap: 2rem
.recent-searches, .quick-actions
background: rgba(255, 255, 255, 0.25)
border-radius: 20px
padding: 1.5rem
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
h3
font-size: 1.125rem
font-weight: 600
color: #1e293b
margin-bottom: 1rem
.recent-list
display: flex
flex-direction: column
gap: 0.75rem
.recent-item
display: flex
align-items: center
gap: 0.75rem
padding: 0.75rem 1rem
background: rgba(255, 255, 255, 0.3)
border: 1px solid rgba(255, 255, 255, 0.4)
border-radius: 12px
color: #475569
cursor: pointer
transition: all 0.3s ease
&:hover
background: rgba(255, 255, 255, 0.4)
transform: translateX(4px)
.actions-grid
display: grid
grid-template-columns: 1fr 1fr
gap: 1rem
.quick-action
display: flex
flex-direction: column
align-items: center
gap: 0.5rem
padding: 1rem
background: rgba(255, 255, 255, 0.3)
border: 1px solid rgba(255, 255, 255, 0.4)
border-radius: 12px
color: #475569
cursor: pointer
transition: all 0.3s ease
text-align: center
&:hover
background: rgba(255, 255, 255, 0.4)
transform: translateY(-2px)
svg
font-size: 1.5rem
span
font-size: 0.875rem
font-weight: 500
.search-results
.results-header
margin-bottom: 1.5rem
h3
font-size: 1.125rem
font-weight: 600
color: #1e293b
.results-list
display: flex
flex-direction: column
gap: 1rem
.result-item
display: flex
align-items: flex-start
gap: 1rem
padding: 1.5rem
background: rgba(255, 255, 255, 0.25)
border-radius: 16px
backdrop-filter: blur(40px)
border: 1px solid rgba(255, 255, 255, 0.3)
cursor: pointer
transition: all 0.3s ease
&:hover
transform: translateY(-2px)
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1)
.result-icon
width: 48px
height: 48px
border-radius: 12px
display: flex
align-items: center
justify-content: center
color: white
font-size: 1.25rem
.result-content
flex: 1
.result-header
display: flex
justify-content: space-between
align-items: center
margin-bottom: 0.5rem
h4
font-size: 1.125rem
font-weight: 600
color: #1e293b
margin: 0
.result-type
font-size: 0.875rem
font-weight: 500
.result-description
color: #475569
line-height: 1.5
margin-bottom: 0.5rem
.result-date
font-size: 0.875rem
color: #64748b
.no-results
text-align: center
padding: 3rem
color: #64748b
svg
margin-bottom: 1rem
opacity: 0.5
h3
font-size: 1.25rem
font-weight: 600
margin-bottom: 0.5rem
p
font-size: 1rem
// Responsive Design
@media (max-width: 768px)
.page-container
padding: 1.5rem
.calendar-header, .shopping-header, .notes-header
flex-direction: column
align-items: flex-start
gap: 1rem
.search-suggestions
grid-template-columns: 1fr
.actions-grid
grid-template-columns: 1fr
.notes-grid
grid-template-columns: 1fr
.editor-header
flex-direction: column
align-items: stretch
@media (max-width: 480px)
.page-container
padding: 1rem
.calendar-days
gap: 0.5rem
.input-group
flex-direction: column
.result-item
padding: 1rem