Compare commits
2 Commits
5ad3894683
...
18f2984bbc
Author | SHA1 | Date | |
---|---|---|---|
18f2984bbc | |||
97ebb62239 |
31
src/App.css
31
src/App.css
@@ -38,16 +38,18 @@
|
|||||||
|
|
||||||
.card {
|
.card {
|
||||||
padding: 1.5em;
|
padding: 1.5em;
|
||||||
background-color: var(--card);
|
background: linear-gradient(135deg, rgba(166, 77, 255, 0.25), rgba(213, 0, 249, 0.25));
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 4px 12px var(--shadow);
|
box-shadow: 0 10px 30px var(--shadow), inset 0 0 15px rgba(166, 77, 255, 0.2);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover {
|
.card:hover {
|
||||||
transform: translateY(-3px);
|
transform: translateY(-5px);
|
||||||
box-shadow: 0 6px 16px var(--shadow);
|
box-shadow: 0 15px 35px var(--shadow), inset 0 0 20px rgba(166, 77, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive adjustments */
|
/* Responsive adjustments */
|
||||||
@@ -63,14 +65,18 @@
|
|||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
text-rendering: geometricPrecision;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dreamy-border {
|
.dreamy-border {
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
background:
|
background: linear-gradient(135deg, rgba(166, 77, 255, 0.25), rgba(213, 0, 249, 0.25)) padding-box,
|
||||||
linear-gradient(var(--bg), var(--bg)) padding-box,
|
|
||||||
var(--accent-gradient) border-box;
|
var(--accent-gradient) border-box;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 10px 30px var(--shadow), inset 0 0 15px rgba(166, 77, 255, 0.2);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dreamy-button {
|
.dreamy-button {
|
||||||
@@ -80,11 +86,14 @@
|
|||||||
padding: 0.6em 1.2em;
|
padding: 0.6em 1.2em;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
box-shadow: 0 4px 12px var(--shadow);
|
box-shadow: 0 10px 30px var(--shadow), inset 0 0 15px rgba(255, 255, 255, 0.2);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dreamy-button:hover {
|
.dreamy-button:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-5px);
|
||||||
box-shadow: 0 6px 16px var(--shadow);
|
box-shadow: 0 15px 35px var(--shadow), inset 0 0 20px rgba(255, 255, 255, 0.3);
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
31
src/App.tsx
31
src/App.tsx
@@ -3,11 +3,12 @@ import {useState} from 'react';
|
|||||||
import Navbar from './components/Navbar';
|
import Navbar from './components/Navbar';
|
||||||
import TopBar from './components/TopBar';
|
import TopBar from './components/TopBar';
|
||||||
import SplashScreen from './components/SplashScreen';
|
import SplashScreen from './components/SplashScreen';
|
||||||
import {BrowserRouter, Route, Routes} from 'react-router-dom';
|
import {BrowserRouter, Route, Routes, useLocation} from 'react-router-dom';
|
||||||
import Feed from "./pages/Feed.tsx";
|
import Feed from "./pages/Feed.tsx";
|
||||||
import DreamPage from "./pages/DreamPage.tsx";
|
import DreamPage from "./pages/DreamPage.tsx";
|
||||||
import ProfilePage from "./pages/ProfilePage.tsx";
|
import ProfilePage from "./pages/ProfilePage.tsx";
|
||||||
import Home from "./pages/Home.tsx";
|
import Home from "./pages/Home.tsx";
|
||||||
|
import Overview from "./pages/Overview.tsx";
|
||||||
|
|
||||||
function Record() {
|
function Record() {
|
||||||
return (
|
return (
|
||||||
@@ -116,16 +117,9 @@ function Archive() {
|
|||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [isLoggedIn, setIsLoggedIn] = useState(localStorage.getItem('loggedIn') === 'true' || false);
|
|
||||||
|
|
||||||
const handleLogin = () => {
|
|
||||||
setIsLoggedIn(true);
|
|
||||||
localStorage.setItem('loggedIn', 'true');
|
|
||||||
}
|
|
||||||
const handleSplashFinished = () => {
|
const handleSplashFinished = () => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setIsLoggedIn(false);
|
|
||||||
localStorage.setItem('loggedIn', 'false');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -135,13 +129,26 @@ export default function App() {
|
|||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
<AppContent/>
|
||||||
|
</BrowserRouter>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate component to use useLocation hook
|
||||||
|
function AppContent() {
|
||||||
|
const location = useLocation();
|
||||||
|
const isOverviewPage = location.pathname === '/';
|
||||||
|
|
||||||
|
return (
|
||||||
<div className="pb-16 pt-8 min-h-screen">
|
<div className="pb-16 pt-8 min-h-screen">
|
||||||
<TopBar/>
|
<TopBar/>
|
||||||
<div className="mx-auto w-full max-w-lg px-4 sm:px-6 md:max-w-2xl lg:max-w-4xl">
|
<div className="mx-auto w-full max-w-lg px-4 sm:px-6 md:max-w-2xl lg:max-w-4xl">
|
||||||
<Navbar isLoggedIn={isLoggedIn}/>
|
{!isOverviewPage && <Navbar/>}
|
||||||
<div className="mt-16 mb-20">
|
<div className={isOverviewPage ? "" : "mt-16 mb-20"}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home isLoggedIn={isLoggedIn} handleLogin={handleLogin}/>}/>
|
<Route path="/" element={<Overview/>}/>
|
||||||
|
<Route path="/home" element={<Home/>}/>
|
||||||
<Route path="/feed" element={<Feed/>}/>
|
<Route path="/feed" element={<Feed/>}/>
|
||||||
<Route path="/record" element={<Record/>}/>
|
<Route path="/record" element={<Record/>}/>
|
||||||
<Route path="/archive" element={<Archive/>}/>
|
<Route path="/archive" element={<Archive/>}/>
|
||||||
@@ -151,7 +158,5 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</BrowserRouter>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -6,13 +6,13 @@
|
|||||||
</linearGradient>
|
</linearGradient>
|
||||||
<mask id="moonMask">
|
<mask id="moonMask">
|
||||||
<circle cx="60" cy="60" r="50" fill="white" />
|
<circle cx="60" cy="60" r="50" fill="white" />
|
||||||
<circle cx="70" cy="50" r="45" fill="black"/>
|
<circle cx="75" cy="40" r="45" fill="black"/>
|
||||||
</mask>
|
</mask>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@400;700&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@400;700&display=swap');
|
||||||
</style>
|
</style>
|
||||||
</defs>
|
</defs>
|
||||||
<circle cx="60" cy="50%" r="50" fill="url(#moonGradient)" mask="url(#moonMask)" />
|
<circle cx="60" cy="60" r="60" fill="url(#moonGradient)" mask="url(#moonMask)"/>
|
||||||
<text x="250" y="60%" dominant-baseline="middle" text-anchor="middle"
|
<text x="250" y="60%" dominant-baseline="middle" text-anchor="middle"
|
||||||
font-family="'Raleway', sans-serif" font-size="70" fill="white" letter-spacing="2"
|
font-family="'Raleway', sans-serif" font-size="70" fill="white" letter-spacing="2"
|
||||||
style="text-shadow: 0 0 5px rgba(0,0,0,0.3);">
|
style="text-shadow: 0 0 5px rgba(0,0,0,0.3);">
|
||||||
|
Before Width: | Height: | Size: 988 B After Width: | Height: | Size: 986 B |
@@ -2,38 +2,62 @@
|
|||||||
import Dream from '../types/Dream';
|
import Dream from '../types/Dream';
|
||||||
import type User from "../types/User.ts";
|
import type User from "../types/User.ts";
|
||||||
import {NavLink} from "react-router-dom";
|
import {NavLink} from "react-router-dom";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
interface DreamCardProps {
|
interface DreamCardProps {
|
||||||
dream: Dream;
|
dream: Dream;
|
||||||
user: User | undefined;
|
user: User | undefined;
|
||||||
|
animationDelay?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DreamCard({dream, user}: DreamCardProps) {
|
export default function DreamCard({dream, user, animationDelay = 0}: DreamCardProps) {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setIsVisible(true);
|
||||||
|
}, animationDelay * 100);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [animationDelay]);
|
||||||
|
|
||||||
return (<NavLink key={dream.id} to={`/dream/${dream.id}`}>
|
return (<NavLink key={dream.id} to={`/dream/${dream.id}`}>
|
||||||
<li className="dream-card mb-4">
|
<li className={`dream-card card mb-4 transition-all duration-500 ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
|
||||||
<div className="flex rounded items-center mb-2">
|
<div className="flex rounded items-center mb-3">
|
||||||
|
<div className="relative">
|
||||||
<img
|
<img
|
||||||
src={`/assets/profiles/${user?.profilePicture}`}
|
src={`/assets/profiles/${user?.profilePicture}`}
|
||||||
alt={user?.name}
|
alt={user?.name}
|
||||||
className="w-10 h-10 rounded-full"
|
className="w-12 h-12 rounded-full border-2 border-accent-soft"
|
||||||
|
style={{borderColor: 'var(--accent-soft)'}}
|
||||||
/>
|
/>
|
||||||
<span className="ml-4 font-semibold">{user?.name} hat geträumt:</span>
|
<div className="absolute -bottom-1 -right-1 w-4 h-4 bg-accent rounded-full"
|
||||||
|
style={{backgroundColor: 'var(--accent)'}}></div>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="title">
|
<span className="ml-4 font-semibold text-left">{user?.name} <span className="text-text-muted">hat geträumt:</span></span>
|
||||||
|
</div>
|
||||||
|
<h2 className="title text-left dreamy-text text-lg">
|
||||||
{dream.title}
|
{dream.title}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-2 line-clamp-2">
|
<p className="mt-2 line-clamp-2 text-left">
|
||||||
{(dream.input.inputType === 'text' && dream.input.input)
|
{(dream.input.inputType === 'text' && dream.input.input)
|
||||||
|| (dream.input.inputType === 'audio' && dream.input.transcript)
|
|| (dream.input.inputType === 'audio' && dream.input.transcript)
|
||||||
|| (dream.input.inputType === 'image' && dream.input.description)}
|
|| (dream.input.inputType === 'image' && dream.input.description)}
|
||||||
</p>
|
</p>
|
||||||
<p
|
<div className="flex justify-between items-center mt-3">
|
||||||
className="timestamp mt-2">
|
<p className="timestamp text-left">
|
||||||
{dream.date.toLocaleDateString('de-DE', {
|
{dream.date.toLocaleDateString('de-DE', {
|
||||||
day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit',
|
day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit',
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
{/* Display dream type as a tag */}
|
||||||
|
<span className="px-2 py-1 text-xs rounded-full bg-accent-soft text-text"
|
||||||
|
style={{backgroundColor: 'var(--accent-soft)', color: 'var(--text)'}}>
|
||||||
|
{dream.input.inputType}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</NavLink>)
|
</NavLink>)
|
||||||
|
|
||||||
}
|
}
|
@@ -1,19 +1,12 @@
|
|||||||
import {NavLink} from 'react-router-dom';
|
import {NavLink} from 'react-router-dom';
|
||||||
import {FaArchive, FaHome, FaList, FaMicrophone, FaUser} from "react-icons/fa";
|
import {FaArchive, FaHome, FaList, FaMicrophone, FaUser} from "react-icons/fa";
|
||||||
|
|
||||||
interface NavbarProps {
|
export default function Navbar() {
|
||||||
isLoggedIn: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Navbar({isLoggedIn}: NavbarProps) {
|
|
||||||
if (!isLoggedIn && localStorage.getItem('loggedIn') !== 'true') return (
|
|
||||||
<></>
|
|
||||||
)
|
|
||||||
return (<>
|
return (<>
|
||||||
<nav
|
<nav
|
||||||
className="fixed bottom-0 left-0 right-0 flex justify-around py-4 z-10"
|
className="fixed bottom-0 left-0 right-0 flex justify-around py-4 z-10"
|
||||||
style={{backgroundColor: 'var(--accent-dark)', boxShadow: '0 -2px 10px var(--shadow)'}}>
|
style={{backgroundColor: 'var(--accent-dark)', boxShadow: '0 -2px 10px var(--shadow)'}}>
|
||||||
<NavLink to="/" className="transition-transform hover:scale-110">
|
<NavLink to="/home" className="transition-transform hover:scale-110">
|
||||||
<FaHome className="w-6 h-6 md:w-8 md:h-8" style={{color: 'var(--accent-soft)'}}/>
|
<FaHome className="w-6 h-6 md:w-8 md:h-8" style={{color: 'var(--accent-soft)'}}/>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink to="/feed" className="transition-transform hover:scale-110">
|
<NavLink to="/feed" className="transition-transform hover:scale-110">
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
import logotext from "../assets/logotext.svg";
|
import logotext from "../assets/logotext.svg";
|
||||||
|
import {NavLink} from "react-router-dom";
|
||||||
|
|
||||||
export default function TopBar() {
|
export default function TopBar() {
|
||||||
const [visible, setVisible] = useState(true);
|
const [visible, setVisible] = useState(true);
|
||||||
@@ -17,8 +18,7 @@ export default function TopBar() {
|
|||||||
|
|
||||||
// Initialize theme based on user preference or system preference
|
// Initialize theme based on user preference or system preference
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isDarkMode = localStorage.getItem('darkMode') === 'true' ||
|
const isDarkMode = localStorage.getItem('darkMode') === 'true' || window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
||||||
setDarkMode(isDarkMode);
|
setDarkMode(isDarkMode);
|
||||||
document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
|
document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
|
||||||
updateThemeColor(isDarkMode);
|
updateThemeColor(isDarkMode);
|
||||||
@@ -47,27 +47,26 @@ export default function TopBar() {
|
|||||||
setLastScrollY(currentScrollY);
|
setLastScrollY(currentScrollY);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
window.addEventListener('scroll', handleScroll, {passive: true});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('scroll', handleScroll);
|
window.removeEventListener('scroll', handleScroll);
|
||||||
};
|
};
|
||||||
}, [lastScrollY]);
|
}, [lastScrollY]);
|
||||||
|
|
||||||
return (
|
return (<div
|
||||||
<div
|
className={`fixed top-0 left-0 right-0 py-2 md:py-3 px-3 md:px-4 flex items-center transition-transform duration-300 z-20 ${visible ? 'transform-none' : 'transform -translate-y-full'}`}
|
||||||
className={`fixed top-0 left-0 right-0 py-2 md:py-3 px-3 md:px-4 flex items-center transition-transform duration-300 z-20 ${
|
|
||||||
visible ? 'transform-none' : 'transform -translate-y-full'
|
|
||||||
}`}
|
|
||||||
style={{
|
style={{
|
||||||
background: 'var(--accent-gradient)',
|
background: 'var(--accent-gradient)', boxShadow: '0 2px 10px var(--shadow)'
|
||||||
boxShadow: '0 2px 10px var(--shadow)'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between w-full max-w-6xl mx-auto">
|
<div className="flex items-center justify-between w-full max-w-6xl mx-auto">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="p-1 rounded-lg" style={{ backgroundColor: 'rgba(255, 255, 255, 0.15)', backdropFilter: 'blur(4px)' }}>
|
<div className="p-1 rounded-lg"
|
||||||
|
style={{backgroundColor: 'rgba(255, 255, 255, 0.15)', backdropFilter: 'blur(4px)'}}>
|
||||||
|
<NavLink to='/home'>
|
||||||
<img src={logotext} alt="REMind Logo and Text" className="h-16"/>
|
<img src={logotext} alt="REMind Logo and Text" className="h-16"/>
|
||||||
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -76,21 +75,19 @@ export default function TopBar() {
|
|||||||
className="p-2 rounded-full focus:outline-none transition-transform hover:scale-110"
|
className="p-2 rounded-full focus:outline-none transition-transform hover:scale-110"
|
||||||
aria-label="Toggle theme"
|
aria-label="Toggle theme"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: 'var(--card)',
|
backgroundColor: 'var(--card)', boxShadow: '0 2px 8px var(--shadow)'
|
||||||
boxShadow: '0 2px 8px var(--shadow)'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{darkMode ? (
|
{darkMode ? (<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 md:h-6 md:w-6" fill="none"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 md:h-6 md:w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: 'var(--accent)' }}>
|
viewBox="0 0 24 24" stroke="currentColor" style={{color: 'var(--accent)'}}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
||||||
</svg>
|
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>
|
||||||
) : (
|
</svg>) : (<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 md:h-6 md:w-6" fill="none"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 md:h-6 md:w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: 'var(--accent-dark)' }}>
|
viewBox="0 0 24 24" stroke="currentColor" style={{color: 'var(--accent-dark)'}}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
||||||
</svg>
|
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/>
|
||||||
)}
|
</svg>)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
10
src/data/DreamUtils.ts
Normal file
10
src/data/DreamUtils.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import Dream from '../types/Dream';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts dreams by date in descending order (newest first)
|
||||||
|
* @param dreams - Array of dreams to sort
|
||||||
|
* @returns Sorted array of dreams
|
||||||
|
*/
|
||||||
|
export const getSortedDreamsByDate = (dreams: Dream[]): Dream[] => {
|
||||||
|
return [...dreams].sort((a, b) => b.date.getTime() - a.date.getTime());
|
||||||
|
};
|
134
src/index.css
134
src/index.css
@@ -11,6 +11,7 @@
|
|||||||
--accent-soft: #c9a4ff;
|
--accent-soft: #c9a4ff;
|
||||||
--accent-dark: #6a0dad;
|
--accent-dark: #6a0dad;
|
||||||
--shadow: rgba(166, 77, 255, 0.2);
|
--shadow: rgba(166, 77, 255, 0.2);
|
||||||
|
--text-shadow: rgba(0, 0, 0, 0.5);
|
||||||
|
|
||||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
--accent-soft: #a64dff;
|
--accent-soft: #a64dff;
|
||||||
--accent-dark: #6a0dad;
|
--accent-dark: #6a0dad;
|
||||||
--shadow: rgba(196, 144, 255, 0.3);
|
--shadow: rgba(196, 144, 255, 0.3);
|
||||||
|
--text-shadow: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.border-background {
|
.border-background {
|
||||||
@@ -47,6 +49,21 @@
|
|||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
transition: background-color 0.3s, color 0.3s;
|
transition: background-color 0.3s, color 0.3s;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page::before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-image: radial-gradient(var(--accent-soft) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
opacity: 0.05;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageTitle {
|
.pageTitle {
|
||||||
@@ -56,11 +73,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dreamPanel {
|
.dreamPanel {
|
||||||
background-color: var(--card);
|
background: linear-gradient(135deg, rgba(166, 77, 255, 0.35), rgba(213, 0, 249, 0.35));
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
border: 1px solid var(--accent);
|
backdrop-filter: blur(5px);
|
||||||
|
box-shadow: 0 0 15px var(--shadow);
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@@ -110,27 +129,58 @@ button:focus-visible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.feed-container {
|
.feed-container {
|
||||||
background-color: var(--container);
|
padding: 1.5em;
|
||||||
padding: 1em;
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border: none;
|
||||||
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.dream-card {
|
.dream-card {
|
||||||
background-color: var(--card);
|
background: linear-gradient(135deg, rgba(166, 77, 255, 0.35), rgba(213, 0, 249, 0.35));
|
||||||
border-radius: 10px;
|
border-radius: 12px;
|
||||||
padding: 1em;
|
padding: 1.25em;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
border: 1px solid var(--accent);
|
backdrop-filter: blur(10px);
|
||||||
|
box-shadow: 0 10px 30px var(--shadow), inset 0 0 15px rgba(166, 77, 255, 0.3);
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dream-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1;
|
||||||
|
margin: -1px;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: var(--accent-gradient);
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dream-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 15px 35px var(--shadow), inset 0 0 20px rgba(166, 77, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dream-card .title {
|
.dream-card .title {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dream-card .timestamp {
|
.dream-card .timestamp {
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.microphone-button {
|
.microphone-button {
|
||||||
@@ -189,20 +239,26 @@ button:focus-visible {
|
|||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
text-shadow: 0 1px 2px var(--text-shadow);
|
||||||
|
text-rendering: geometricPrecision;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dream-container {
|
.dream-container {
|
||||||
background-color: var(--container);
|
background: linear-gradient(135deg, rgba(166, 77, 255, 0.25), rgba(213, 0, 249, 0.25));
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
box-shadow: 0 4px 15px var(--shadow);
|
box-shadow: 0 10px 30px var(--shadow), inset 0 0 15px rgba(166, 77, 255, 0.2);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
transition: transform 0.3s, box-shadow 0.3s;
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dream-container:hover {
|
.dream-container:hover {
|
||||||
transform: translateY(-5px);
|
transform: translateY(-5px);
|
||||||
box-shadow: 0 8px 25px var(--shadow);
|
box-shadow: 0 15px 35px var(--shadow), inset 0 0 20px rgba(166, 77, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scrollbar styling */
|
/* Scrollbar styling */
|
||||||
@@ -223,13 +279,30 @@ button:focus-visible {
|
|||||||
background: var(--accent);
|
background: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dreamy Card Styling */
|
||||||
|
.dreamy-card {
|
||||||
|
background: linear-gradient(135deg, rgba(166, 77, 255, 0.35), rgba(213, 0, 249, 0.35));
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1.25em;
|
||||||
|
color: var(--text);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
box-shadow: 0 10px 30px var(--shadow), inset 0 0 15px rgba(166, 77, 255, 0.3);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dreamy-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 15px 35px var(--shadow), inset 0 0 20px rgba(166, 77, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
/* Animations */
|
/* Animations */
|
||||||
@keyframes dream-float {
|
@keyframes dream-float {
|
||||||
0% {
|
0% {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
transform: translateY(-10px);
|
transform: translateY(-5px);
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
@@ -240,7 +313,7 @@ button:focus-visible {
|
|||||||
animation: dream-float 6s ease-in-out infinite;
|
animation: dream-float 6s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive typography */
|
/* Responsive adjustments */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
@@ -251,4 +324,39 @@ button:focus-visible {
|
|||||||
p {
|
p {
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.feed-container {
|
||||||
|
padding: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dream-card {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dream-card .title {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.page {
|
||||||
|
padding: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feed-container {
|
||||||
|
padding: 1em 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dream-card {
|
||||||
|
padding: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dream-card .title {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dream-card img {
|
||||||
|
width: 2.5rem !important;
|
||||||
|
height: 2.5rem !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,19 +62,30 @@ export default function DreamPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-4 sm:p-6 md:p-8 space-y-6 sm:space-y-8 max-w-4xl mx-auto">
|
<div className="p-4 sm:p-6 md:p-8 space-y-6 sm:space-y-8 max-w-4xl mx-auto">
|
||||||
<div className="dream-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
<div className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center mb-4">
|
||||||
<span className="font-medium" style={{ color: 'var(--accent)' }}>Traum-Beschreibung</span>
|
<span className="font-medium dreamy-text">Traum-Beschreibung</span>
|
||||||
</div>
|
</div>
|
||||||
|
{(dream.input.inputType === 'image' || dream.input.inputType === 'audio') && (
|
||||||
|
<div className="flex justify-center mb-1">
|
||||||
|
{dream.input.inputType === 'audio' && (
|
||||||
|
<audio></audio>
|
||||||
|
)}
|
||||||
|
{dream.input.inputType === 'image' && (
|
||||||
|
<img alt={dream.input.imgAlt}></img>
|
||||||
|
)}
|
||||||
|
</div>)}
|
||||||
<p className="leading-relaxed text-base sm:text-lg">
|
<p className="leading-relaxed text-base sm:text-lg">
|
||||||
{dream.input}
|
{(dream.input.inputType === 'text' && dream.input.input)
|
||||||
|
|| (dream.input.inputType === 'audio' && dream.input.transcript)
|
||||||
|
|| (dream.input.inputType === 'image' && dream.input.description)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{dream.ai?.interpretation && dream.ai.interpretation !== '' && (<div
|
{dream.ai?.interpretation && dream.ai.interpretation !== '' && (<div
|
||||||
className="dreamPanel rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center mb-4">
|
||||||
<span className="font-medium" style={{ color: 'var(--accent)' }}>KI-Interpretation</span>
|
<span className="font-medium dreamy-text">KI-Interpretation</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="leading-relaxed">
|
<p className="leading-relaxed">
|
||||||
{dream.ai.interpretation}
|
{dream.ai.interpretation}
|
||||||
@@ -82,9 +93,9 @@ export default function DreamPage() {
|
|||||||
</div>)}
|
</div>)}
|
||||||
|
|
||||||
{dream.ai?.image && dream.ai.image !== '' && (<div
|
{dream.ai?.image && dream.ai.image !== '' && (<div
|
||||||
className="dreamPanel rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center mb-4">
|
||||||
<span className="font-medium" style={{ color: 'var(--accent)' }}>KI-Bild</span>
|
<span className="font-medium dreamy-text">KI-Bild</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<img
|
<img
|
||||||
@@ -97,9 +108,9 @@ export default function DreamPage() {
|
|||||||
</div>)}
|
</div>)}
|
||||||
|
|
||||||
{dream.ai?.audio && dream.ai.audio !== '' && (<div
|
{dream.ai?.audio && dream.ai.audio !== '' && (<div
|
||||||
className="dreamPanel rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center mb-4">
|
||||||
<span className="font-medium" style={{ color: 'var(--accent)' }}>KI-Audio</span>
|
<span className="font-medium dreamy-text">KI-Audio</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<audio
|
<audio
|
||||||
@@ -113,9 +124,9 @@ export default function DreamPage() {
|
|||||||
</div>)}
|
</div>)}
|
||||||
|
|
||||||
{dream.ai?.video && dream.ai.video !== '' && (<div
|
{dream.ai?.video && dream.ai.video !== '' && (<div
|
||||||
className="dreamPanel rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center mb-4">
|
||||||
<span className="font-medium" style={{ color: 'var(--accent)' }}>KI-Video</span>
|
<span className="font-medium dreamy-text">KI-Video</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<video
|
<video
|
||||||
@@ -129,12 +140,12 @@ export default function DreamPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>)}
|
</div>)}
|
||||||
|
|
||||||
<div className="dream-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
<div className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6">
|
||||||
<h2 className="text-lg font-semibold mb-3">Details</h2>
|
<h2 className="text-lg font-semibold mb-3 dreamy-text">Details</h2>
|
||||||
<div className="space-y-3" style={{ color: 'var(--text-muted)' }}>
|
<div className="space-y-3" style={{ color: 'var(--text-muted)' }}>
|
||||||
<div className="flex flex-col sm:flex-row sm:justify-between">
|
<div className="flex flex-col sm:flex-row sm:justify-between">
|
||||||
<span className="font-medium mb-1 sm:mb-0">Eingabetyp</span>
|
<span className="font-medium mb-1 sm:mb-0">Eingabetyp</span>
|
||||||
<span className="capitalize">{dream.inputType}</span>
|
<span className="capitalize">{dream.input.inputType}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col sm:flex-row sm:justify-between">
|
<div className="flex flex-col sm:flex-row sm:justify-between">
|
||||||
<span className="font-medium mb-1 sm:mb-0">Datum</span>
|
<span className="font-medium mb-1 sm:mb-0">Datum</span>
|
||||||
|
@@ -4,17 +4,23 @@ import Dream from '../types/Dream';
|
|||||||
import type User from "../types/User.ts";
|
import type User from "../types/User.ts";
|
||||||
import {MockUserMap} from "../data/MockUsers.ts";
|
import {MockUserMap} from "../data/MockUsers.ts";
|
||||||
import DreamCard from "../components/DreamCard";
|
import DreamCard from "../components/DreamCard";
|
||||||
|
import {getSortedDreamsByDate} from "../data/DreamUtils";
|
||||||
|
|
||||||
export default function Feed() {
|
export default function Feed() {
|
||||||
const sortedDreams = [...mockDreams].sort((a, b) => b.date.getTime() - a.date.getTime());
|
const sortedDreams = getSortedDreamsByDate(mockDreams);
|
||||||
return (
|
return (
|
||||||
<div className="page p-4 space-y-4">
|
<div className="page p-4 space-y-6">
|
||||||
<div className="feed-container rounded-lg">
|
<div className="feed-container">
|
||||||
<ul className="space-y-6">
|
<ul className="space-y-6 md:space-y-8">
|
||||||
{sortedDreams.map((dream: Dream) => {
|
{sortedDreams.map((dream: Dream, index) => {
|
||||||
const user: User | undefined = MockUserMap.get(dream.userId);
|
const user: User | undefined = MockUserMap.get(dream.userId);
|
||||||
return (
|
return (
|
||||||
<DreamCard key={dream.id} dream={dream} user={user} />
|
<DreamCard
|
||||||
|
key={dream.id}
|
||||||
|
dream={dream}
|
||||||
|
user={user}
|
||||||
|
animationDelay={index}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
252
src/pages/Overview.tsx
Normal file
252
src/pages/Overview.tsx
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
import {BsMoonStars, BsStars} from 'react-icons/bs';
|
||||||
|
import {
|
||||||
|
FaBed,
|
||||||
|
FaBook,
|
||||||
|
FaBrain,
|
||||||
|
FaChartBar,
|
||||||
|
FaCloud,
|
||||||
|
FaEye,
|
||||||
|
FaHeart,
|
||||||
|
FaMicrophone,
|
||||||
|
FaMoon,
|
||||||
|
FaPen,
|
||||||
|
FaRobot,
|
||||||
|
FaStar,
|
||||||
|
FaVrCardboard,
|
||||||
|
} from 'react-icons/fa';
|
||||||
|
import {HiSparkles} from 'react-icons/hi';
|
||||||
|
import logotext from "../assets/logotext.svg";
|
||||||
|
import {NavLink} from 'react-router-dom';
|
||||||
|
|
||||||
|
export default function Overview() {
|
||||||
|
return (<div className="p-4 pt-24 pb-20 max-w-6xl mx-auto relative overflow-hidden">
|
||||||
|
{/* Floating Background Elements */}
|
||||||
|
<div className="absolute inset-0 pointer-events-none">
|
||||||
|
<div className="absolute top-20 left-0 text-purple-200 opacity-30">
|
||||||
|
<FaCloud size={40}/>
|
||||||
|
</div>
|
||||||
|
<div className="absolute top-60 right-5 text-purple-300 opacity-20">
|
||||||
|
<BsStars size={30}/>
|
||||||
|
</div>
|
||||||
|
<div className="absolute bottom-10 left-32 text-purple-200 opacity-25">
|
||||||
|
<BsMoonStars size={35}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Hero Section */}
|
||||||
|
<div className="text-center mb-12 sm:mb-16 relative z-10">
|
||||||
|
<div className="animate-pulse flex flex-col items-center mb-8 sm:mb-12">
|
||||||
|
<div className="flex items-center justify-around">
|
||||||
|
<img src={logotext} alt="REMind Logo and Text" className="h-32 sm:h-40 md:h-48 mb-4"/>
|
||||||
|
</div>
|
||||||
|
<p className="text-lg sm:text-xl dreamy-text">Träume analysieren, Gesellschaft verstehen</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="dream-container floating max-w-3xl mx-auto backdrop-blur-sm bg-white/10 dark:bg-white/5 rounded-3xl p-4 sm:p-6 md:p-8"
|
||||||
|
style={{animationDelay: '0.2s'}}>
|
||||||
|
<div className="flex flex-col sm:flex-row justify-center items-center mb-3 sm:mb-4">
|
||||||
|
<HiSparkles className="text-yellow-400 mb-2 sm:mb-0 sm:mr-2" size={20}/>
|
||||||
|
<h2 className="dream-title text-xl sm:text-2xl">Träume sammeln • KI verstehen • VR erleben</h2>
|
||||||
|
<HiSparkles className="text-yellow-400 mt-2 sm:mt-0 sm:ml-2 hidden sm:block" size={20}/>
|
||||||
|
</div>
|
||||||
|
<p className="mb-4 sm:mb-6 md:mb-8 text-sm sm:text-base md:text-lg" style={{color: 'var(--text)'}}>
|
||||||
|
Verwandle deine nächtlichen Reisen in interaktive Traumlandschaften
|
||||||
|
mit KI-gestützter Analyse und immersiven VR-Erlebnissen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Main Features Grid - Dreamy Cards */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-16">
|
||||||
|
{/* KI-Traumdeutung */}
|
||||||
|
<div
|
||||||
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6 floating backdrop-blur-md bg-gradient-to-br from-purple-100/50 to-pink-100/50 border border-purple-200/30 dark:bg-gradient-to-br dark:from-purple-900/30 dark:to-pink-900/30 dark:border-purple-700/30"
|
||||||
|
style={{animationDelay: '0.5s'}}>
|
||||||
|
<div className="flex justify-center mb-4">
|
||||||
|
<div className="p-3 sm:p-4 bg-purple-500/20 rounded-full">
|
||||||
|
<FaBrain className="text-purple-600 dark:text-purple-400" size={28}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg sm:text-xl font-bold mb-2 sm:mb-3 text-center dreamy-text">
|
||||||
|
KI-Traumdeutung
|
||||||
|
</h3>
|
||||||
|
<p className="text-center text-sm sm:text-base" style={{color: 'var(--text)'}}>
|
||||||
|
Deine Träume werden von KI entschlüsselt -
|
||||||
|
Symbole erkannt, Emotionen analysiert, Bedeutungen offenbart
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Multimediale Traumerfassung */}
|
||||||
|
<div
|
||||||
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6 floating backdrop-blur-md bg-gradient-to-br from-blue-100/50 to-indigo-100/50 border border-blue-200/30 dark:bg-gradient-to-br dark:from-blue-900/30 dark:to-indigo-900/30 dark:border-blue-700/30"
|
||||||
|
style={{animationDelay: '1s'}}>
|
||||||
|
<div className="flex justify-center mb-4">
|
||||||
|
<div className="p-3 sm:p-4 bg-blue-500/20 rounded-full">
|
||||||
|
<FaMicrophone className="text-blue-600 dark:text-blue-400" size={28}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg sm:text-xl font-bold mb-2 sm:mb-3 text-center dreamy-text">
|
||||||
|
Träume einfangen
|
||||||
|
</h3>
|
||||||
|
<p className="text-center text-sm sm:text-base" style={{color: 'var(--text)'}}>
|
||||||
|
Sprich deine Träume in der Nacht, zeichne traumhafte Skizzen
|
||||||
|
oder schreibe poetische Beschreibungen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* VR-Traumwelten */}
|
||||||
|
<div
|
||||||
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6 floating backdrop-blur-md bg-gradient-to-br from-violet-100/50 to-purple-100/50 border border-violet-200/30 dark:bg-gradient-to-br dark:from-violet-900/30 dark:to-purple-900/30 dark:border-violet-700/30"
|
||||||
|
style={{animationDelay: '1.5s'}}>
|
||||||
|
<div className="flex justify-center mb-4">
|
||||||
|
<div className="p-3 sm:p-4 bg-violet-500/20 rounded-full">
|
||||||
|
<FaVrCardboard className="text-violet-600 dark:text-violet-400" size={28}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg sm:text-xl font-bold mb-2 sm:mb-3 text-center dreamy-text">
|
||||||
|
VR-Traumreisen
|
||||||
|
</h3>
|
||||||
|
<p className="text-center text-sm sm:text-base" style={{color: 'var(--text)'}}>
|
||||||
|
Betritt deine Träume als begehbare Welten -
|
||||||
|
schwebe durch Erinnerungen, berühre Traumsymbole
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Traumarchiv */}
|
||||||
|
<div
|
||||||
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6 floating backdrop-blur-md bg-gradient-to-br from-emerald-100/50 to-teal-100/50 border border-emerald-200/30 dark:bg-gradient-to-br dark:from-emerald-900/30 dark:to-teal-900/30 dark:border-emerald-700/30"
|
||||||
|
style={{animationDelay: '2s'}}>
|
||||||
|
<div className="flex justify-center mb-4">
|
||||||
|
<div className="p-3 sm:p-4 bg-emerald-500/20 rounded-full">
|
||||||
|
<FaBook className="text-emerald-600 dark:text-emerald-400" size={28}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg sm:text-xl font-bold mb-2 sm:mb-3 text-center dreamy-text">
|
||||||
|
Traumschatzkammer
|
||||||
|
</h3>
|
||||||
|
<p className="text-center text-sm sm:text-base" style={{color: 'var(--text)'}}>
|
||||||
|
Deine Traumsammlung wächst - durchsuchbar nach Gefühlen,
|
||||||
|
Symbolen und magischen Momenten
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Traumstatistiken */}
|
||||||
|
<div
|
||||||
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6 floating backdrop-blur-md bg-gradient-to-br from-amber-100/50 to-orange-100/50 border border-amber-200/30 dark:bg-gradient-to-br dark:from-amber-900/30 dark:to-orange-900/30 dark:border-amber-700/30"
|
||||||
|
style={{animationDelay: '2.5s'}}>
|
||||||
|
<div className="flex justify-center mb-4">
|
||||||
|
<div className="p-3 sm:p-4 bg-amber-500/20 rounded-full">
|
||||||
|
<FaChartBar className="text-amber-600 dark:text-amber-400" size={28}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg sm:text-xl font-bold mb-2 sm:mb-3 text-center dreamy-text">
|
||||||
|
Traummuster
|
||||||
|
</h3>
|
||||||
|
<p className="text-center text-sm sm:text-base" style={{color: 'var(--text)'}}>
|
||||||
|
Entdecke die geheimen Muster deiner Nachtreisen -
|
||||||
|
welche Träume kehren zurück?
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Schlafrhythmus */}
|
||||||
|
<div
|
||||||
|
className="dreamy-card rounded-xl sm:rounded-2xl p-4 sm:p-6 floating backdrop-blur-md bg-gradient-to-br from-rose-100/50 to-pink-100/50 border border-rose-200/30 dark:bg-gradient-to-br dark:from-rose-900/30 dark:to-pink-900/30 dark:border-rose-700/30"
|
||||||
|
style={{animationDelay: '3s'}}>
|
||||||
|
<div className="flex justify-center mb-4">
|
||||||
|
<div className="p-3 sm:p-4 bg-rose-500/20 rounded-full">
|
||||||
|
<FaMoon className="text-rose-600 dark:text-rose-400" size={28}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg sm:text-xl font-bold mb-2 sm:mb-3 text-center dreamy-text">
|
||||||
|
Schlafzyklen
|
||||||
|
</h3>
|
||||||
|
<p className="text-center text-sm sm:text-base" style={{color: 'var(--text)'}}>
|
||||||
|
Verstehe deine Schlafrhythmen und wie sie deine
|
||||||
|
Traumlandschaften formen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Dreamy Workflow Section */}
|
||||||
|
<div
|
||||||
|
className="dream-container floating mb-16 backdrop-blur-lg bg-gradient-to-br from-pink-500/30 to-red-400/30 dark:from-pink-800/30 dark:to-red-900/30 rounded-xl sm:rounded-2xl md:rounded-3xl p-6 sm:p-8 md:p-12"
|
||||||
|
style={{animationDelay: '3.2s'}}>
|
||||||
|
<div className="text-center">
|
||||||
|
<FaHeart className="text-pink-500 dark:text-pink-400 mx-auto mb-4" size={32}/>
|
||||||
|
<h2 className="dream-title text-2xl sm:text-3xl">Deine magische Traumreise</h2>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-6 sm:gap-8 mt-6 sm:mt-8">
|
||||||
|
<div className="text-center">
|
||||||
|
<div
|
||||||
|
className="bg-gradient-to-br from-purple-400 to-purple-600 rounded-full w-16 h-16 sm:w-20 sm:h-20 flex items-center justify-center mx-auto mb-4 sm:mb-6 shadow-lg">
|
||||||
|
<FaBed className="text-white" size={24}/>
|
||||||
|
</div>
|
||||||
|
<h4 className="font-bold mb-2 sm:mb-3 dreamy-text text-base sm:text-lg">1. Träumen</h4>
|
||||||
|
<p className="text-xs sm:text-sm" style={{color: 'var(--text)'}}>
|
||||||
|
In der Nacht zeichnen deine Sensoren sanft deine Traumreisen auf
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<div
|
||||||
|
className="bg-gradient-to-br from-blue-400 to-blue-600 rounded-full w-16 h-16 sm:w-20 sm:h-20 flex items-center justify-center mx-auto mb-4 sm:mb-6 shadow-lg">
|
||||||
|
<FaPen className="text-white" size={24}/>
|
||||||
|
</div>
|
||||||
|
<h4 className="font-bold mb-2 sm:mb-3 dreamy-text text-base sm:text-lg">2. Einfangen</h4>
|
||||||
|
<p className="text-xs sm:text-sm" style={{color: 'var(--text)'}}>
|
||||||
|
Beim Erwachen flüsterst du deine Träume in die App
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<div
|
||||||
|
className="bg-gradient-to-br from-violet-400 to-violet-600 rounded-full w-16 h-16 sm:w-20 sm:h-20 flex items-center justify-center mx-auto mb-4 sm:mb-6 shadow-lg">
|
||||||
|
<FaRobot className="text-white" size={24}/>
|
||||||
|
</div>
|
||||||
|
<h4 className="font-bold mb-2 sm:mb-3 dreamy-text text-base sm:text-lg">3. Verzaubern</h4>
|
||||||
|
<p className="text-xs sm:text-sm" style={{color: 'var(--text)'}}>
|
||||||
|
KI-Magie verwandelt deine Worte in Bilder, Klänge und Bedeutungen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<div
|
||||||
|
className="bg-gradient-to-br from-pink-400 to-pink-600 rounded-full w-16 h-16 sm:w-20 sm:h-20 flex items-center justify-center mx-auto mb-4 sm:mb-6 shadow-lg">
|
||||||
|
<FaEye className="text-white" size={24}/>
|
||||||
|
</div>
|
||||||
|
<h4 className="font-bold mb-2 sm:mb-3 dreamy-text text-base sm:text-lg">4. Erleben</h4>
|
||||||
|
<p className="text-xs sm:text-sm" style={{color: 'var(--text)'}}>
|
||||||
|
Tauche ein in deine VR-Traumwelten und entdecke dich selbst
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Dreamy CTA Section */}
|
||||||
|
<div className="relative mt-12 sm:mt-16">
|
||||||
|
<div
|
||||||
|
className="dreamy-card rounded-xl sm:rounded-2xl p-6 sm:p-8 md:p-12 text-center floating bg-gradient-to-br from-pink-600 via-violet-600 to-purple-600 border-none overflow-hidden"
|
||||||
|
style={{animationDelay: '3.5s'}}>
|
||||||
|
<div className="relative z-10">
|
||||||
|
<div className="flex flex-col sm:flex-row justify-center items-center mb-4 sm:mb-6">
|
||||||
|
<FaStar className="text-yellow-300 mb-2 sm:mb-0 sm:mr-3" size={24}/>
|
||||||
|
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold text-white">Wo Träume Realität
|
||||||
|
werden</h2>
|
||||||
|
<FaStar className="text-yellow-300 mt-2 sm:mt-0 sm:ml-3 hidden sm:block" size={24}/>
|
||||||
|
</div>
|
||||||
|
<p className="text-base sm:text-lg md:text-xl text-purple-100 mb-6 sm:mb-8 md:mb-10 max-w-2xl mx-auto">
|
||||||
|
Lass dich von KI-gestützter Traumdeutung, VR-Erlebnissen und personalisierten
|
||||||
|
Einsichten in eine tiefere Welt deines Unterbewusstseins führen
|
||||||
|
</p>
|
||||||
|
<div className="flex justify-center w-full">
|
||||||
|
<NavLink
|
||||||
|
to='/home'
|
||||||
|
className="dreamy-button inline-flex items-center justify-center text-center mx-auto text-sm sm:text-base px-6 py-3 rounded-full font-medium shadow-lg"
|
||||||
|
style={{minWidth: '200px'}}
|
||||||
|
>
|
||||||
|
<FaMoon className="mr-2 sm:mr-3" size={18}/>
|
||||||
|
Lass die Magie beginnen!
|
||||||
|
<HiSparkles className="ml-2 sm:ml-3" size={18}/>
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>)
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MockUsers } from '../data/MockUsers';
|
import {MockUsers} from '../data/MockUsers';
|
||||||
|
|
||||||
const ProfilePage: React.FC = () => {
|
const ProfilePage: React.FC = () => {
|
||||||
// Find Neo Quantum in MockUsers
|
// Find Neo Quantum in MockUsers
|
||||||
@@ -13,47 +13,89 @@ const ProfilePage: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page p-4 pb-20">
|
<div className="page p-4 pb-20">
|
||||||
<div className="dreamPanel flex flex-col items-center p-4 sm:p-6 md:p-8 max-w-md mx-auto">
|
<div
|
||||||
|
className="dreamy-border rounded-xl p-6 max-w-md mx-auto overflow-hidden"
|
||||||
|
style={{
|
||||||
|
background: 'linear-gradient(135deg, rgba(166, 77, 255, 0.25), rgba(213, 0, 249, 0.25))',
|
||||||
|
backdropFilter: 'blur(10px)',
|
||||||
|
boxShadow: '0 10px 30px var(--shadow), inset 0 0 15px rgba(166, 77, 255, 0.2)'
|
||||||
|
}}>
|
||||||
{/* Profile Picture */}
|
{/* Profile Picture */}
|
||||||
<div className="w-24 h-24 sm:w-32 sm:h-32 rounded-full overflow-hidden mb-4 border-4 border-accent">
|
<div className="w-28 h-28 sm:w-36 sm:h-36 rounded-full overflow-hidden mb-6 mx-auto relative"
|
||||||
|
style={{
|
||||||
|
background: 'var(--accent-gradient)',
|
||||||
|
padding: '4px',
|
||||||
|
boxShadow: '0 0 15px var(--shadow)'
|
||||||
|
}}>
|
||||||
<img
|
<img
|
||||||
src={profileUser ? `/assets/profiles/${profileUser.profilePicture}` : `https://ui-avatars.com/api/?name=${defaultName}&background=random&color=fff&size=128`}
|
src={profileUser ? `/assets/profiles/${profileUser.profilePicture}` : `https://ui-avatars.com/api/?name=${defaultName}&background=random&color=fff&size=128`}
|
||||||
alt={profileUser ? profileUser.name : defaultName}
|
alt={profileUser ? profileUser.name : defaultName}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover rounded-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* User Information */}
|
{/* User Information */}
|
||||||
<div className="text-center w-full">
|
<div className="text-center w-full">
|
||||||
<h2 className="text-xl sm:text-2xl font-bold mb-2">{profileUser ? profileUser.name : defaultName}</h2>
|
<h2 className="text-xl sm:text-2xl mb-2 break-words dreamy-text font-bold">{profileUser ? profileUser.name : defaultName}</h2>
|
||||||
<p className="text-text-muted mb-4">{profileUser ? profileUser.email : defaultEmail}</p>
|
<p className="text-text-muted mb-8 break-words">{profileUser ? profileUser.email : defaultEmail}</p>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-2 sm:gap-4 mt-6 text-center">
|
<div className="grid grid-cols-2 gap-6 mt-6 text-center">
|
||||||
<div className="dreamPanel p-3 sm:p-4">
|
<div
|
||||||
<p className="font-bold text-xl sm:text-2xl">{profileUser ? profileUser.dreamCount : defaultDreamCount}</p>
|
className="dreamy-border rounded-lg p-4"
|
||||||
<p className="text-xs sm:text-sm text-text-muted">Dreams</p>
|
style={{
|
||||||
|
background: 'linear-gradient(135deg, rgba(166, 77, 255, 0.35), rgba(213, 0, 249, 0.35))',
|
||||||
|
boxShadow: '0 0 15px var(--shadow)',
|
||||||
|
backdropFilter: 'blur(5px)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className="dreamy-text text-2xl sm:text-3xl font-bold">{profileUser ? profileUser.dreamCount : defaultDreamCount}</p>
|
||||||
|
<p className="text-sm sm:text-base font-medium" style={{color: 'var(--text)'}}>Dreams</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="dreamPanel p-3 sm:p-4">
|
<div
|
||||||
<p className="font-bold text-xl sm:text-2xl">{profileUser ? profileUser.streakDays : defaultStreakDays}</p>
|
className="dreamy-border rounded-lg p-4"
|
||||||
<p className="text-xs sm:text-sm text-text-muted">Days Streak</p>
|
style={{
|
||||||
|
background: 'linear-gradient(135deg, rgba(166, 77, 255, 0.35), rgba(213, 0, 249, 0.35))',
|
||||||
|
boxShadow: '0 0 15px var(--shadow)',
|
||||||
|
backdropFilter: 'blur(5px)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className="dreamy-text text-2xl sm:text-3xl font-bold">{profileUser ? profileUser.streakDays : defaultStreakDays}</p>
|
||||||
|
<p className="text-sm sm:text-base font-medium" style={{color: 'var(--text)'}}>Days Streak</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6 sm:mt-8">
|
<div className="mt-10">
|
||||||
<h3 className="text-lg font-semibold mb-2">Account Settings</h3>
|
<h3 className="dreamy-text text-lg mb-4 font-bold">Account Settings</h3>
|
||||||
<div className="dreamPanel text-left p-3 sm:p-4">
|
<div
|
||||||
<div className="flex justify-between items-center py-2">
|
className="dreamy-border rounded-lg p-5 text-left"
|
||||||
<span>Notifications</span>
|
style={{
|
||||||
<label className="theme-toggle relative inline-block">
|
background: 'linear-gradient(135deg, rgba(166, 77, 255, 0.35), rgba(213, 0, 249, 0.35))',
|
||||||
<input type="checkbox" defaultChecked />
|
boxShadow: '0 0 15px var(--shadow)',
|
||||||
<span className="slider"></span>
|
backdropFilter: 'blur(5px)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex justify-between items-center py-3 flex-wrap border-b border-purple-100/30">
|
||||||
|
<span className="mr-2 font-medium" style={{color: 'var(--text)'}}>Notifications</span>
|
||||||
|
<label className="relative inline-block w-12 h-6">
|
||||||
|
<input type="checkbox" className="opacity-0 w-0 h-0" defaultChecked/>
|
||||||
|
<span className="absolute cursor-pointer inset-0 rounded-full transition-all duration-300"
|
||||||
|
style={{
|
||||||
|
background: 'var(--accent-gradient)',
|
||||||
|
opacity: '0.9',
|
||||||
|
boxShadow: 'inset 0 0 5px rgba(166, 77, 255, 0.5)'
|
||||||
|
}}></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center py-2">
|
<div className="flex justify-between items-center py-3 flex-wrap">
|
||||||
<span>Privacy</span>
|
<span className="mr-2 font-medium" style={{color: 'var(--text)'}}>Privacy</span>
|
||||||
<label className="theme-toggle relative inline-block">
|
<label className="relative inline-block w-12 h-6">
|
||||||
<input type="checkbox" />
|
<input type="checkbox" className="opacity-0 w-0 h-0"/>
|
||||||
<span className="slider"></span>
|
<span className="absolute cursor-pointer inset-0 rounded-full transition-all duration-300"
|
||||||
|
style={{
|
||||||
|
background: 'var(--accent-gradient)',
|
||||||
|
opacity: '0.9',
|
||||||
|
boxShadow: 'inset 0 0 5px rgba(166, 77, 255, 0.5)'
|
||||||
|
}}></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user