looking better
This commit is contained in:
92
App.tsx
92
App.tsx
@@ -8,14 +8,14 @@ import { Category, Website, Wallpaper } from './types';
|
||||
import Dropdown from './components/Dropdown';
|
||||
import WebsiteEditModal from './components/WebsiteEditModal';
|
||||
import CategoryEditModal from './components/CategoryEditModal';
|
||||
import { PlusCircle, Pencil } from 'lucide-react';
|
||||
import { baseWallpapers } from './components/utils/baseWallpapers';
|
||||
|
||||
import { baseWallpapers } from './components/utils/baseWallpapers';
|
||||
|
||||
const defaultConfig = {
|
||||
title: 'Vision Start',
|
||||
subtitle: 'Your personal portal to the web.',
|
||||
backgroundUrl: 'https://i.imgur.com/C6ynAtX.jpeg',
|
||||
backgroundUrls: ['https://i.imgur.com/C6ynAtX.jpeg'],
|
||||
wallpaperFrequency: '1d',
|
||||
wallpaperBlur: 0,
|
||||
wallpaperBrightness: 100,
|
||||
wallpaperOpacity: 100,
|
||||
@@ -58,7 +58,11 @@ const App: React.FC = () => {
|
||||
try {
|
||||
const storedConfig = localStorage.getItem('config');
|
||||
if (storedConfig) {
|
||||
return { ...defaultConfig, ...JSON.parse(storedConfig) };
|
||||
const parsedConfig = JSON.parse(storedConfig);
|
||||
if (!parsedConfig.backgroundUrls) {
|
||||
parsedConfig.backgroundUrls = [parsedConfig.backgroundUrl].filter(Boolean);
|
||||
}
|
||||
return { ...defaultConfig, ...parsedConfig };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error parsing config from localStorage', error);
|
||||
@@ -69,9 +73,54 @@ const App: React.FC = () => {
|
||||
const storedUserWallpapers = localStorage.getItem('userWallpapers');
|
||||
return storedUserWallpapers ? JSON.parse(storedUserWallpapers) : [];
|
||||
});
|
||||
const [currentWallpaper, setCurrentWallpaper] = useState<string>('');
|
||||
|
||||
const allWallpapers = [...baseWallpapers, ...userWallpapers];
|
||||
const selectedWallpaper = allWallpapers.find(w => w.url === config.backgroundUrl || w.base64 === config.backgroundUrl);
|
||||
|
||||
useEffect(() => {
|
||||
const getFrequencyInMs = (frequency: string) => {
|
||||
const value = parseInt(frequency.slice(0, -1));
|
||||
const unit = frequency.slice(-1);
|
||||
if (unit === 'h') return value * 60 * 60 * 1000;
|
||||
if (unit === 'd') return value * 24 * 60 * 60 * 1000;
|
||||
return 24 * 60 * 60 * 1000; // Default to 1 day
|
||||
};
|
||||
|
||||
const wallpaperState = JSON.parse(localStorage.getItem('wallpaperState') || '{}');
|
||||
const lastChanged = wallpaperState.lastChanged ? new Date(wallpaperState.lastChanged).getTime() : 0;
|
||||
const frequency = getFrequencyInMs(config.wallpaperFrequency);
|
||||
|
||||
const updateWallpaper = () => {
|
||||
const availableWallpapers = allWallpapers.filter(w => config.backgroundUrls.includes(w.url || w.base64));
|
||||
if (availableWallpapers.length > 0) {
|
||||
const currentIndex = availableWallpapers.findIndex(w => (w.url || w.base64) === wallpaperState.current);
|
||||
const nextIndex = (currentIndex + 1) % availableWallpapers.length;
|
||||
const newWallpaper = availableWallpapers[nextIndex];
|
||||
const newWallpaperUrl = newWallpaper.url || newWallpaper.base64;
|
||||
setCurrentWallpaper(newWallpaperUrl || '');
|
||||
localStorage.setItem('wallpaperState', JSON.stringify({ current: newWallpaper.name, lastChanged: new Date().toISOString() }));
|
||||
} else {
|
||||
setCurrentWallpaper('');
|
||||
}
|
||||
};
|
||||
|
||||
if (Date.now() - lastChanged > frequency) {
|
||||
updateWallpaper();
|
||||
} else {
|
||||
const currentWallpaperName = wallpaperState.current;
|
||||
const wallpaper = allWallpapers.find(w => w.name === currentWallpaperName);
|
||||
if (wallpaper) {
|
||||
setCurrentWallpaper(wallpaper.url || wallpaper.base64 || '');
|
||||
} else {
|
||||
const firstWallpaperUrl = config.backgroundUrls[0] || '';
|
||||
const firstWallpaper = allWallpapers.find(w => (w.url || w.base64) === firstWallpaperUrl);
|
||||
setCurrentWallpaper(firstWallpaperUrl);
|
||||
if (firstWallpaper) {
|
||||
localStorage.setItem('wallpaperState', JSON.stringify({ current: firstWallpaper.name, lastChanged: new Date().toISOString() }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [config.backgroundUrls, config.wallpaperFrequency, allWallpapers]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('categories', JSON.stringify(categories));
|
||||
@@ -257,7 +306,7 @@ const App: React.FC = () => {
|
||||
<div
|
||||
className="fixed inset-0 w-full h-full bg-cover bg-center bg-fixed -z-10"
|
||||
style={{
|
||||
backgroundImage: `url('${selectedWallpaper?.url || selectedWallpaper?.base64 || ''}')`,
|
||||
backgroundImage: `url('${currentWallpaper}')`,
|
||||
filter: `blur(${config.wallpaperBlur}px) brightness(${config.wallpaperBrightness}%)`,
|
||||
opacity: `${config.wallpaperOpacity}%`,
|
||||
}}
|
||||
@@ -266,20 +315,21 @@ const App: React.FC = () => {
|
||||
<button
|
||||
onClick={() => setIsEditing(!isEditing)}
|
||||
className="bg-black/25 backdrop-blur-md border border-white/10 rounded-xl p-3 text-white flex items-center gap-2 hover:bg-white/25 transition-colors"
|
||||
style={{ fontSize: '12px' }}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" className="bi bi-pencil" viewBox="0 0 16 16">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-pencil" viewBox="0 0 16 16">
|
||||
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
|
||||
</svg>
|
||||
{isEditing ? 'Done' : 'Edit'}
|
||||
{isEditing ? 'Done' : ''}
|
||||
</button>
|
||||
</div>
|
||||
<div className="absolute top-4 right-4">
|
||||
<button
|
||||
onClick={() => setIsConfigModalOpen(true)}
|
||||
className="bg-black/25 backdrop-blur-md border border-white/10 rounded-xl p-3 text-white hover:bg-white/25 transition-colors"
|
||||
className="bg-black/25 backdrop-blur-md border border-white/10 rounded-xl p-3 text-white flex items-center gap-2 hover:bg-white/25 transition-colors"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-gear-wide" viewBox="0 0 16 16">
|
||||
<path d="M8.932.727c-.243-.97-1.62-.97-1.864 0l-.071.286a.96.96 0 0 1-1.622.434l-.205-.211c-.695-.719-1.888-.03-1.613.931l.08.284a.96.96 0 0 1-1.186 1.187l-.284-.081c-.96-.275-1.65.918-.931 1.613l.211.205a.96.96 0 0 1-.434 1.622l-.286.071c-.97.243-.97 1.62 0 1.864l.286.071a.96.96 0 0 1 .434 1.622l-.211.205c-.719.695-.03 1.888.931 1.613l.284-.08a.96.96 0 0 1 1.187 1.187l-.081.283c-.275.96.918 1.65 1.613.931l.205-.211a.96.96 0 0 1 1.622.434l.071.286c.243.97 1.62.97 1.864 0l.071-.286a.96.96 0 0 1 1.622-.434l.205.211c.695.719 1.888.03 1.613-.931l-.08-.284a.96.96 0 0 1 1.187-1.187l.283.081c.96.275 1.65-.918.931-1.613l-.211-.205a.96.96 0 0 1 .434-1.622l.286-.071c.97-.243.97-1.62 0-1.864l-.286-.071a.96.96 0 0 1-.434-1.622l.211-.205c.719-.695.03-1.888-.931-1.613l-.284.08a.96.96 0 0 1-1.187-1.186l.081-.284c.275-.96-.918-1.65-1.613-.931l-.205.211a.96.96 0 0 1-1.622-.434zM8 12.997a4.998 4.998 0 1 1 0-9.995 4.998 4.998 0 0 1 0 9.996z"/>
|
||||
<path d="M8.932.727c-.243-.97-1.62-.97-1.864 0l-.071.286a.96.96 0 0 1-1.622.434l-.205-.211c-.695-.719-1.888-.03-1.613.931l.08.284a.96.96 0 0 1-1.186 1.187l-.284-.081c-.96-.275-1.65.918-.931 1.613l.211.205a.96.96 0 0 1-.434 1.622l-.286.071c-.97.243-.97 1.62 0 1.864l.286.071a.96.96 0 0 1 .434 1.622l-.211.205c-.719.695-.03 1.888.931 1.613l.284-.08a.96.96 0 0 1 1.187 1.187l-.081.283c-.275.96.918 1.65 1.613.931l.205-.211a.96.96 0 0 1 1.622.434l.071.286c.243.97 1.62.97 1.864 0l.071-.286a.96.96 0 0 1 1.622-.434l.205.211c.695.719 1.888.03 1.613-.931l-.08-.284a.96.96 0 0 1 1.187-1.187l.283.081c.96.275 1.65-.918-.931-1.613l-.211-.205a.96.96 0 0 1 .434-1.622l.286-.071c.97-.243.97-1.62 0-1.864l-.286-.071a.96.96 0 0 1-.434-1.622l.211-.205c.719-.695.03-1.888-.931-1.613l-.284.08a.96.96 0 0 1-1.187-1.186l.081-.284c.275-.96-.918-1.65-1.613-.931l-.205.211a.96.96 0 0 1-1.622-.434zM8 12.997a4.998 4.998 0 1 1 0-9.995 4.998 4.998 0 0 1 0 9.996z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -321,9 +371,11 @@ const App: React.FC = () => {
|
||||
setEditingCategory(category);
|
||||
setIsCategoryModalOpen(true);
|
||||
}}
|
||||
className="ml-2 text-white/50 hover:text-white transition-colors"
|
||||
className={`ml-2 text-white/50 hover:text-white transition-all duration-300 ease-in-out transform ${isEditing ? 'scale-100 opacity-100' : 'scale-0 opacity-0'}`}
|
||||
>
|
||||
<Pencil size={20} />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" className="bi bi-pencil" viewBox="0 0 16 16">
|
||||
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zM1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -341,16 +393,19 @@ const App: React.FC = () => {
|
||||
{isEditing && (
|
||||
<button
|
||||
onClick={() => setAddingWebsite(category)}
|
||||
className="text-white/50 hover:text-white transition-colors"
|
||||
className={`text-white/50 hover:text-white transition-all duration-300 ease-in-out transform ${isEditing ? 'scale-100 opacity-100' : 'scale-0 opacity-0'}`}
|
||||
>
|
||||
<PlusCircle size={48} />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="currentColor" className="bi bi-plus-circle" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{isEditing && (
|
||||
<div className="flex justify-center">
|
||||
<div className={`flex justify-center transition-all duration-300 ease-in-out transform ${isEditing ? 'scale-100 opacity-100' : 'scale-0 opacity-0'}`}>
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditingCategory(null);
|
||||
@@ -358,7 +413,10 @@ const App: React.FC = () => {
|
||||
}}
|
||||
className="text-white/50 hover:text-white transition-colors"
|
||||
>
|
||||
<PlusCircle size={48} />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="currentColor" className="bi bi-plus-circle" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -407,4 +465,4 @@ const App: React.FC = () => {
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App;
|
Reference in New Issue
Block a user