let junie rework the theme one more time
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>REMind</title>
|
||||
<meta name="theme-color" content="#9d4eff" />
|
||||
<meta name="description" content="REMind - Track and analyze your dreams with our dreamy app" />
|
||||
<title>REMind | Dream Tracker</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
68
src/App.css
68
src/App.css
@@ -1,21 +1,24 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App {
|
||||
min-height: 100vh;
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
filter: drop-shadow(0 0 2em var(--accent));
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
@@ -34,9 +37,54 @@
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
padding: 1.5em;
|
||||
background-color: var(--card);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px var(--shadow);
|
||||
margin-bottom: 1rem;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
.card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 16px var(--shadow);
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.card {
|
||||
padding: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dreamy effects */
|
||||
.dreamy-text {
|
||||
background: var(--accent-gradient);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dreamy-border {
|
||||
border: 2px solid transparent;
|
||||
background:
|
||||
linear-gradient(var(--bg), var(--bg)) padding-box,
|
||||
var(--accent-gradient) border-box;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.dreamy-button {
|
||||
background: var(--accent-gradient);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.6em 1.2em;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
box-shadow: 0 4px 12px var(--shadow);
|
||||
}
|
||||
|
||||
.dreamy-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px var(--shadow);
|
||||
}
|
||||
|
180
src/App.tsx
180
src/App.tsx
@@ -1,43 +1,175 @@
|
||||
import './App.css';
|
||||
import {useState} from 'react';
|
||||
import Navbar from './components/Navbar';
|
||||
import TopBar from './components/TopBar';
|
||||
import SplashScreen from './components/SplashScreen';
|
||||
import {BrowserRouter, Route, Routes} from 'react-router-dom';
|
||||
import Feed from "./pages/Feed.tsx";
|
||||
import DreamPage from "./pages/DreamPage.tsx";
|
||||
import ProfilePage from "./pages/ProfilePage.tsx";
|
||||
|
||||
function Home() {
|
||||
return <div className="p-4">Home Page</div>;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h1 className="dreamy-text text-3xl md:text-4xl mb-6">Welcome to REMind</h1>
|
||||
<p className="mb-8 text-lg">Your dreamy journey to better sleep and dream tracking</p>
|
||||
|
||||
<div className="dream-container">
|
||||
<h2 className="dream-title">Track Your Dreams</h2>
|
||||
<p className="mb-4">Record and analyze your dreams with our intuitive interface</p>
|
||||
<button className="dreamy-button">Get Started</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
|
||||
<div className="card floating">
|
||||
<h3 className="text-xl font-bold mb-2" style={{ color: 'var(--accent)' }}>Dream Journal</h3>
|
||||
<p>Keep track of all your dreams in one place</p>
|
||||
</div>
|
||||
<div className="card" style={{ animationDelay: '2s' }}>
|
||||
<h3 className="text-xl font-bold mb-2" style={{ color: 'var(--accent)' }}>Sleep Analysis</h3>
|
||||
<p>Understand your sleep patterns better</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Record() {
|
||||
return <div className="p-4">Record Page</div>;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h1 className="dreamy-text text-3xl md:text-4xl mb-6">Record Your Dream</h1>
|
||||
|
||||
<div className="dream-container">
|
||||
<div className="flex flex-col items-center mb-6">
|
||||
<div className="w-20 h-20 rounded-full flex items-center justify-center mb-4 floating"
|
||||
style={{ background: 'var(--accent-gradient)' }}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-10 w-10 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" />
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-lg mb-2">Tap to start recording your dream</p>
|
||||
<p className="text-sm text-center" style={{ color: 'var(--text-muted)' }}>
|
||||
Your voice will be transcribed automatically
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="dreamy-border p-4 mb-6">
|
||||
<textarea
|
||||
className="w-full p-3 rounded-lg bg-transparent focus:outline-none"
|
||||
placeholder="Or type your dream here..."
|
||||
rows={5}
|
||||
style={{ color: 'var(--text)', borderColor: 'var(--accent-soft)' }}
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<button className="dreamy-button w-full">Save Dream</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Archive() {
|
||||
return <div className="p-4">Archive Page</div>;
|
||||
}
|
||||
|
||||
function Profile() {
|
||||
return <div className="p-4">Profile Page</div>;
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<div className="pb-16 pt-8 min-h-screen">
|
||||
<TopBar/>
|
||||
<div className="mx-auto w-full max-w-lg">
|
||||
<Navbar/>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home/>}/>
|
||||
<Route path="/feed" element={<Feed/>}/>
|
||||
<Route path="/record" element={<Record/>}/>
|
||||
<Route path="/archive" element={<Archive/>}/>
|
||||
<Route path="/profile" element={<Profile/>}/>
|
||||
<Route path="/dream/:id" element={<DreamPage/>}/>
|
||||
</Routes>
|
||||
<div className="p-4">
|
||||
<h1 className="dreamy-text text-3xl md:text-4xl mb-6">Dream Archive</h1>
|
||||
|
||||
<div className="mb-6 flex flex-col sm:flex-row gap-4">
|
||||
<div className="flex-1">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search dreams..."
|
||||
className="w-full p-3 rounded-lg focus:outline-none"
|
||||
style={{
|
||||
backgroundColor: 'var(--container)',
|
||||
color: 'var(--text)',
|
||||
borderColor: 'var(--accent-soft)',
|
||||
boxShadow: '0 2px 8px var(--shadow)'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<select
|
||||
className="w-full p-3 rounded-lg focus:outline-none"
|
||||
style={{
|
||||
backgroundColor: 'var(--container)',
|
||||
color: 'var(--text)',
|
||||
borderColor: 'var(--accent-soft)',
|
||||
boxShadow: '0 2px 8px var(--shadow)'
|
||||
}}
|
||||
>
|
||||
<option>All Dreams</option>
|
||||
<option>Last Week</option>
|
||||
<option>Last Month</option>
|
||||
<option>Last Year</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
|
||||
<div className="space-y-4">
|
||||
{[1, 2, 3].map((item) => (
|
||||
<div key={item} className="card">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<h3 className="text-xl font-bold" style={{ color: 'var(--accent)' }}>
|
||||
Dream #{item}
|
||||
</h3>
|
||||
<span style={{ color: 'var(--text-muted)' }}>
|
||||
{new Date().toLocaleDateString()}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mb-4">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Vivamus lacinia, nunc eu tincidunt faucibus...
|
||||
</p>
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
className="px-4 py-2 rounded-lg transition-transform hover:scale-105"
|
||||
style={{
|
||||
background: 'var(--accent-gradient)',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
View Details
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default function App() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const handleSplashFinished = () => {
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <SplashScreen onFinished={handleSplashFinished}/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<BrowserRouter>
|
||||
<div className="pb-16 pt-8 min-h-screen">
|
||||
<TopBar/>
|
||||
<div className="mx-auto w-full max-w-lg px-4 sm:px-6 md:max-w-2xl lg:max-w-4xl">
|
||||
<Navbar/>
|
||||
<div className="mt-16 mb-20">
|
||||
<Routes>
|
||||
<Route path="/" element={<Home/>}/>
|
||||
<Route path="/feed" element={<Feed/>}/>
|
||||
<Route path="/record" element={<Record/>}/>
|
||||
<Route path="/archive" element={<Archive/>}/>
|
||||
<Route path="/profile" element={<ProfilePage/>}/>
|
||||
<Route path="/dream/:id" element={<DreamPage/>}/>
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="moonGradient" x1="0%" y1="0%" x2="100%" y2="50%">
|
||||
<stop offset="0%" stop-color="#5B68CE" />
|
||||
<stop offset="100%" stop-color="#6A449E" />
|
||||
<stop offset="0%" stop-color="darkorchid" />
|
||||
<stop offset="100%" stop-color="darkslateblue" />
|
||||
</linearGradient>
|
||||
<mask id="moonMask">
|
||||
<circle cx="100" cy="100" r="50" fill="white" />
|
||||
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 627 B |
@@ -4,8 +4,8 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@400;700&display=swap');
|
||||
</style>
|
||||
<linearGradient id="textGradient" x1="25%" y1="0%" x2="75%" y2="100%">
|
||||
<stop offset="0%" stop-color="#5A8BFF" />
|
||||
<stop offset="100%" stop-color="#9B5CFF" />
|
||||
<stop offset="0%" stop-color="darkslateblue" />
|
||||
<stop offset="100%" stop-color="indigo" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
|
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 720 B |
@@ -2,30 +2,31 @@ import {NavLink} from 'react-router-dom';
|
||||
import {FaArchive, FaHome, FaList, FaMicrophone, FaUser} from "react-icons/fa";
|
||||
|
||||
export default function Navbar() {
|
||||
|
||||
return (<>
|
||||
<nav
|
||||
className="fixed bottom-0 left-0 right-0 flex justify-around bg-violet-900 py-4 z-10">
|
||||
<NavLink to="/">
|
||||
<FaHome className="w-8 h-8 text-fuchsia-400"/>
|
||||
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)' }}>
|
||||
<NavLink to="/" className="transition-transform hover:scale-110">
|
||||
<FaHome className="w-6 h-6 md:w-8 md:h-8" style={{ color: 'var(--accent-soft)' }}/>
|
||||
</NavLink>
|
||||
<NavLink to="/feed">
|
||||
<FaList className="w-8 h-8 text-fuchsia-400"/>
|
||||
<NavLink to="/feed" className="transition-transform hover:scale-110">
|
||||
<FaList className="w-6 h-6 md:w-8 md:h-8" style={{ color: 'var(--accent-soft)' }}/>
|
||||
</NavLink>
|
||||
<div className="w-20"></div>
|
||||
<NavLink to="/archive">
|
||||
<FaArchive className="w-8 h-8 text-fuchsia-400"/>
|
||||
<div className="w-16 md:w-20"></div>
|
||||
<NavLink to="/archive" className="transition-transform hover:scale-110">
|
||||
<FaArchive className="w-6 h-6 md:w-8 md:h-8" style={{ color: 'var(--accent-soft)' }}/>
|
||||
</NavLink>
|
||||
<NavLink to="/profile">
|
||||
<FaUser className="w-8 h-8 text-fuchsia-400"/>
|
||||
<NavLink to="/profile" className="transition-transform hover:scale-110">
|
||||
<FaUser className="w-6 h-6 md:w-8 md:h-8" style={{ color: 'var(--accent-soft)' }}/>
|
||||
</NavLink>
|
||||
</nav>
|
||||
|
||||
<NavLink
|
||||
to="/record"
|
||||
className="microphone-button fixed bottom-6 left-1/2 transform -translate-x-1/2 p-5 rounded-full z-20"
|
||||
className="microphone-button fixed bottom-6 left-1/2 transform -translate-x-1/2 p-4 md:p-5 rounded-full z-20 transition-transform hover:scale-110"
|
||||
style={{ boxShadow: '0 4px 15px var(--shadow)' }}
|
||||
>
|
||||
<FaMicrophone className="w-10 h-10 text-white"/>
|
||||
<FaMicrophone className="w-8 h-8 md:w-10 md:h-10 text-white"/>
|
||||
</NavLink>
|
||||
</>
|
||||
);
|
||||
|
31
src/components/SplashScreen.tsx
Normal file
31
src/components/SplashScreen.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from 'react';
|
||||
import logo from '../assets/logo.svg';
|
||||
import text from '../assets/text.svg';
|
||||
|
||||
interface SplashScreenProps {
|
||||
onFinished: () => void;
|
||||
}
|
||||
|
||||
export default function SplashScreen({ onFinished }: SplashScreenProps) {
|
||||
useEffect(() => {
|
||||
// Simulate loading time with a timeout
|
||||
const timer = setTimeout(() => {
|
||||
onFinished();
|
||||
}, 2000); // Show splash screen for 2 seconds
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [onFinished]);
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 flex flex-col items-center justify-center bg-violet-900 z-50">
|
||||
<div className="animate-pulse flex flex-col items-center">
|
||||
<img src={logo} alt="REMind Logo" className="h-32 w-32 mb-4" />
|
||||
<img src={text} alt="REMind Text" className="h-16" />
|
||||
</div>
|
||||
<div className="mt-8 text-fuchsia-400">
|
||||
<div className="animate-spin h-8 w-8 border-4 border-current border-t-transparent rounded-full mx-auto"></div>
|
||||
<p className="mt-4 text-center">Loading your dreams...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -5,13 +5,41 @@ import text from '../assets/text.svg';
|
||||
export default function TopBar() {
|
||||
const [visible, setVisible] = useState(true);
|
||||
const [lastScrollY, setLastScrollY] = useState(0);
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
|
||||
// Function to update theme meta tag
|
||||
const updateThemeColor = (isDark: boolean) => {
|
||||
const themeColor = isDark ? '#bb86fc' : '#9d4eff';
|
||||
const metaThemeColor = document.querySelector('meta[name="theme-color"]');
|
||||
if (metaThemeColor) {
|
||||
metaThemeColor.setAttribute('content', themeColor);
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize theme based on user preference or system preference
|
||||
useEffect(() => {
|
||||
const isDarkMode = localStorage.getItem('darkMode') === 'true' ||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
setDarkMode(isDarkMode);
|
||||
document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
|
||||
updateThemeColor(isDarkMode);
|
||||
}, []);
|
||||
|
||||
// Function to toggle theme
|
||||
const toggleTheme = () => {
|
||||
const newDarkMode = !darkMode;
|
||||
setDarkMode(newDarkMode);
|
||||
document.documentElement.setAttribute('data-theme', newDarkMode ? 'dark' : 'light');
|
||||
localStorage.setItem('darkMode', newDarkMode.toString());
|
||||
updateThemeColor(newDarkMode);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const currentScrollY = window.scrollY;
|
||||
|
||||
// Hide the topbar when scrolling down, show when scrolling up
|
||||
if (currentScrollY > lastScrollY) {
|
||||
if (currentScrollY > lastScrollY && currentScrollY > 50) {
|
||||
setVisible(false);
|
||||
} else {
|
||||
setVisible(true);
|
||||
@@ -29,13 +57,39 @@ export default function TopBar() {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed top-0 left-0 right-0 bg-violet-900 py-3 px-4 flex items-center transition-transform duration-300 z-20 ${
|
||||
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={{
|
||||
background: 'var(--accent-gradient)',
|
||||
boxShadow: '0 2px 10px var(--shadow)'
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<img src={logo} alt="REMind Logo" className="h-16 w-16" />
|
||||
<img src={text} alt="REMind Text" className="h-12 ml-2" />
|
||||
<div className="flex items-center justify-between w-full max-w-6xl mx-auto">
|
||||
<div className="flex items-center">
|
||||
<img src={logo} alt="REMind Logo" className="h-12 w-12 md:h-16 md:w-16" />
|
||||
<img src={text} alt="REMind Text" className="h-8 md:h-12 ml-2" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="p-2 rounded-full focus:outline-none transition-transform hover:scale-110"
|
||||
aria-label="Toggle theme"
|
||||
style={{
|
||||
backgroundColor: 'var(--card)',
|
||||
boxShadow: '0 2px 8px var(--shadow)'
|
||||
}}
|
||||
>
|
||||
{darkMode ? (
|
||||
<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)' }}>
|
||||
<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" />
|
||||
</svg>
|
||||
) : (
|
||||
<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)' }}>
|
||||
<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" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import User from "../types/User.ts";
|
||||
|
||||
export const MockUsers: User[] = [
|
||||
new User(1, "Matthias", "matthias.jpg"),
|
||||
new User(2, "Kim", "kim.png"),
|
||||
new User(3, "Anja", "anja.png"),
|
||||
new User(1, "Matthias", "matthias.jpg", "s4mapuch@uni-trier.de", 42, 7),
|
||||
new User(2, "Kim", "kim.png", "kim@example.com", 28, 3),
|
||||
new User(3, "Anja", "anja.png", "anja@example.com", 15, 5),
|
||||
new User(4, "Neo Quantum", "neo.png", "neo@remind.dev", 64, 12),
|
||||
]
|
||||
|
||||
export const MockUserMap: Map<number, User> = new Map(MockUsers.map(user => [user.id, user]));
|
||||
|
||||
export default MockUsers;
|
||||
export default MockUsers;
|
||||
|
@@ -1,13 +1,16 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--bg: #f9f6ff;
|
||||
--bg: #f8f5ff;
|
||||
--container: #ede6fa;
|
||||
--card: #d6c6ff;
|
||||
--card: #e0d4ff;
|
||||
--text: #1e102e;
|
||||
--text-muted: #4a375e;
|
||||
--accent: #7f39fb;
|
||||
--accent-gradient: linear-gradient(135deg, #7f39fb, #d500f9);
|
||||
--accent: #9d4eff;
|
||||
--accent-gradient: linear-gradient(135deg, #9d4eff, #d500f9);
|
||||
--accent-soft: #c9a4ff;
|
||||
--accent-dark: #6a0dad;
|
||||
--shadow: rgba(157, 78, 255, 0.2);
|
||||
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
@@ -24,13 +27,16 @@
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--bg: #1e102e;
|
||||
--container: #3a1a5d;
|
||||
--card: #5c2d91;
|
||||
--bg: #1a0933;
|
||||
--container: #2d1155;
|
||||
--card: #3d1a6e;
|
||||
--text: #f5e6ff;
|
||||
--text-muted: #c9a4e3;
|
||||
--accent: #bb86fc;
|
||||
--accent-gradient: linear-gradient(135deg, #7f39fb, #d500f9);
|
||||
--accent-gradient: linear-gradient(135deg, #bb86fc, #d500f9);
|
||||
--accent-soft: #9d4eff;
|
||||
--accent-dark: #6a0dad;
|
||||
--shadow: rgba(187, 134, 252, 0.3);
|
||||
}
|
||||
|
||||
.border-background {
|
||||
@@ -69,12 +75,13 @@ a:hover {
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@@ -173,3 +180,75 @@ button:focus-visible {
|
||||
.theme-toggle input:checked + .slider {
|
||||
background-color: var(--accent);
|
||||
}
|
||||
|
||||
/* Dreamy violet enhancements */
|
||||
.dream-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
background: var(--accent-gradient);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.dream-container {
|
||||
background-color: var(--container);
|
||||
border-radius: 16px;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
box-shadow: 0 4px 15px var(--shadow);
|
||||
transition: transform 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.dream-container:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px var(--shadow);
|
||||
}
|
||||
|
||||
/* Scrollbar styling */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--accent-soft);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes dream-float {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.floating {
|
||||
animation: dream-float 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Responsive typography */
|
||||
@media (max-width: 768px) {
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
p {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
}
|
||||
|
67
src/pages/ProfilePage.tsx
Normal file
67
src/pages/ProfilePage.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React from 'react';
|
||||
import { MockUsers } from '../data/MockUsers';
|
||||
|
||||
const ProfilePage: React.FC = () => {
|
||||
// Find Neo Quantum in MockUsers
|
||||
const profileUser = MockUsers.find(user => user.name === "Neo Quantum");
|
||||
|
||||
// Default values if user not found
|
||||
const defaultName = "TestUser";
|
||||
const defaultEmail = "user@example.com";
|
||||
const defaultDreamCount = 0;
|
||||
const defaultStreakDays = 0;
|
||||
|
||||
return (
|
||||
<div className="page p-4">
|
||||
<div className="dreamPanel flex flex-col items-center p-6">
|
||||
{/* Profile Picture */}
|
||||
<div className="w-32 h-32 rounded-full overflow-hidden mb-4 border-4 border-accent">
|
||||
<img
|
||||
src={profileUser ? `/assets/profiles/${profileUser.profilePicture}` : `https://ui-avatars.com/api/?name=${defaultName}&background=random&color=fff&size=128`}
|
||||
alt={profileUser ? profileUser.name : defaultName}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* User Information */}
|
||||
<div className="text-center">
|
||||
<h2 className="text-xl font-bold mb-2">{profileUser ? profileUser.name : defaultName}</h2>
|
||||
<p className="text-text-muted mb-4">{profileUser ? profileUser.email : defaultEmail}</p>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 mt-6 text-center">
|
||||
<div className="dreamPanel">
|
||||
<p className="font-bold text-2xl">{profileUser ? profileUser.dreamCount : defaultDreamCount}</p>
|
||||
<p className="text-sm text-text-muted">Dreams</p>
|
||||
</div>
|
||||
<div className="dreamPanel">
|
||||
<p className="font-bold text-2xl">{profileUser ? profileUser.streakDays : defaultStreakDays}</p>
|
||||
<p className="text-sm text-text-muted">Days Streak</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8">
|
||||
<h3 className="text-lg font-semibold mb-2">Account Settings</h3>
|
||||
<div className="dreamPanel text-left">
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span>Notifications</span>
|
||||
<label className="theme-toggle">
|
||||
<input type="checkbox" defaultChecked />
|
||||
<span className="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span>Privacy</span>
|
||||
<label className="theme-toggle">
|
||||
<input type="checkbox" />
|
||||
<span className="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfilePage;
|
@@ -2,14 +2,23 @@ export default class User {
|
||||
id: number;
|
||||
name: string;
|
||||
profilePicture: string;
|
||||
email: string;
|
||||
dreamCount: number;
|
||||
streakDays: number;
|
||||
|
||||
constructor(
|
||||
id: number,
|
||||
name: string,
|
||||
profilePicture: string
|
||||
profilePicture: string,
|
||||
email: string = "",
|
||||
dreamCount: number = 0,
|
||||
streakDays: number = 0
|
||||
){
|
||||
this.id = id
|
||||
this.name = name
|
||||
this.profilePicture = profilePicture
|
||||
this.email = email
|
||||
this.dreamCount = dreamCount
|
||||
this.streakDays = streakDays
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user