This commit is contained in:
2026-06-08 17:02:38 +01:00
parent 1930190c8d
commit ab19a3bfc9
7 changed files with 407 additions and 301 deletions

2
.env
View File

@@ -8,5 +8,3 @@ VITE_FIREBASE_APP_ID="1:219982610263:web:0ebe67d9cf0e7d2753c812"
VITE_APP_ID=my-closet-app VITE_APP_ID=my-closet-app
VITE_INITIAL_AUTH_TOKEN= VITE_INITIAL_AUTH_TOKEN=
VITE_FIREBASE_VAPID_KEY=BM55REBdX3g7x4JT7C6sN0uBDLATqsCnvgvx3mJnVmgU2dFvZL1przcV-V-Kl50Ao6-i8OA-5PZFWTuhETL9-v4 VITE_FIREBASE_VAPID_KEY=BM55REBdX3g7x4JT7C6sN0uBDLATqsCnvgvx3mJnVmgU2dFvZL1przcV-V-Kl50Ao6-i8OA-5PZFWTuhETL9-v4

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
dist/assets/index-DUBk-k5k.css vendored Normal file

File diff suppressed because one or more lines are too long

4
dist/index.html vendored
View File

@@ -5,8 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MyCloset</title> <title>MyCloset</title>
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<script type="module" crossorigin src="/assets/index-SfxBfoF_.js"></script> <script type="module" crossorigin src="/assets/index-C3FJNYuR.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DFJLltIj.css"> <link rel="stylesheet" crossorigin href="/assets/index-DUBk-k5k.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -70,6 +70,9 @@ export default function App() {
const [weatherData, setWeatherData] = useState(null); const [weatherData, setWeatherData] = useState(null);
const [isPrivate, setIsPrivate] = useState(false); const [isPrivate, setIsPrivate] = useState(false);
const [shortcutsEnabled, setShortcutsEnabled] = useState(false); const [shortcutsEnabled, setShortcutsEnabled] = useState(false);
const [shortcutUpKey, setShortcutUpKey] = useState('q');
const [shortcutDownKey, setShortcutDownKey] = useState('e');
const [recordingKey, setRecordingKey] = useState(null);
const [userStatus, setUserStatus] = useState('online'); const [userStatus, setUserStatus] = useState('online');
// Estado da Comunidade // Estado da Comunidade
@@ -117,6 +120,16 @@ export default function App() {
const t = (key) => translations[language]?.[key] || translations['PT'][key] || key; const t = (key) => translations[language]?.[key] || translations['PT'][key] || key;
const formatKeyName = (key) => {
if (!key) return '';
if (key === ' ') return t('spaceKey') || 'Espaço';
if (key === 'ArrowUp') return '↑';
if (key === 'ArrowDown') return '↓';
if (key === 'ArrowLeft') return '←';
if (key === 'ArrowRight') return '→';
return key.toUpperCase();
};
// Mapeamento de nomes de cor (PT) para valores CSS // Mapeamento de nomes de cor (PT) para valores CSS
const COLOR_MAP = { const COLOR_MAP = {
'Vermelho': '#ef4444', 'Vermelho': '#ef4444',
@@ -299,16 +312,42 @@ export default function App() {
const handleKeyDown = (e) => { const handleKeyDown = (e) => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
if (e.key.toLowerCase() === 'q') { if (e.key.toLowerCase() === shortcutUpKey.toLowerCase()) {
handleNavShortcut('up'); handleNavShortcut('up');
} else if (e.key.toLowerCase() === 'e') { } else if (e.key.toLowerCase() === shortcutDownKey.toLowerCase()) {
handleNavShortcut('down'); handleNavShortcut('down');
} }
}; };
window.addEventListener('keydown', handleKeyDown); window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown);
}, [shortcutsEnabled, view]); }, [shortcutsEnabled, view, shortcutUpKey, shortcutDownKey]);
useEffect(() => {
if (!recordingKey) return;
const handleCapture = (e) => {
e.preventDefault();
e.stopPropagation();
if (['control', 'shift', 'alt', 'meta'].includes(e.key.toLowerCase())) {
return;
}
const key = e.key;
if (recordingKey === 'up') {
setShortcutUpKey(key);
saveUserSetting('shortcutUpKey', key);
} else if (recordingKey === 'down') {
setShortcutDownKey(key);
saveUserSetting('shortcutDownKey', key);
}
setRecordingKey(null);
};
window.addEventListener('keydown', handleCapture, true);
return () => window.removeEventListener('keydown', handleCapture, true);
}, [recordingKey]);
useEffect(() => { useEffect(() => {
if (editingItem && editingItem.color) { if (editingItem && editingItem.color) {
@@ -454,6 +493,8 @@ export default function App() {
} }
if (data.settings.isPrivate !== undefined) setIsPrivate(data.settings.isPrivate); if (data.settings.isPrivate !== undefined) setIsPrivate(data.settings.isPrivate);
if (data.settings.shortcutsEnabled !== undefined) setShortcutsEnabled(data.settings.shortcutsEnabled); if (data.settings.shortcutsEnabled !== undefined) setShortcutsEnabled(data.settings.shortcutsEnabled);
if (data.settings.shortcutUpKey !== undefined) setShortcutUpKey(data.settings.shortcutUpKey);
if (data.settings.shortcutDownKey !== undefined) setShortcutDownKey(data.settings.shortcutDownKey);
if (data.settings.status !== undefined) setUserStatus(data.settings.status); if (data.settings.status !== undefined) setUserStatus(data.settings.status);
} }
} }
@@ -1476,7 +1517,7 @@ export default function App() {
{shortcutsEnabled && ( {shortcutsEnabled && (
<button onClick={() => handleNavShortcut('up')} className="w-full flex items-center justify-center gap-2 p-2 bg-gray-100 dark:bg-gray-800 rounded-xl mb-3 text-xs font-bold hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"> <button onClick={() => handleNavShortcut('up')} className="w-full flex items-center justify-center gap-2 p-2 bg-gray-100 dark:bg-gray-800 rounded-xl mb-3 text-xs font-bold hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
<span className="px-2 py-1 bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">Q</span> {t('up')} <span className="px-2 py-1 bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">{formatKeyName(shortcutUpKey)}</span> {t('up')}
</button> </button>
)} )}
<nav className="flex-1 space-y-3"> <nav className="flex-1 space-y-3">
@@ -1505,7 +1546,7 @@ export default function App() {
</nav> </nav>
{shortcutsEnabled && ( {shortcutsEnabled && (
<button onClick={() => handleNavShortcut('down')} className="w-full flex items-center justify-center gap-2 p-2 bg-gray-100 dark:bg-gray-800 rounded-xl mt-3 text-xs font-bold hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"> <button onClick={() => handleNavShortcut('down')} className="w-full flex items-center justify-center gap-2 p-2 bg-gray-100 dark:bg-gray-800 rounded-xl mt-3 text-xs font-bold hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
<span className="px-2 py-1 bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">E</span> {t('down')} <span className="px-2 py-1 bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">{formatKeyName(shortcutDownKey)}</span> {t('down')}
</button> </button>
)} )}
@@ -2736,6 +2777,43 @@ export default function App() {
</button> </button>
</div> </div>
{shortcutsEnabled && (
<div className="pl-4 border-l-2 border-primary-500 dark:border-primary-400 flex flex-col gap-3 my-2 transition-all">
<div className="flex items-center justify-between">
<div>
<p className="text-xs font-bold text-inherit">{t('shortcutUp') || 'Navegar para Cima'}</p>
<p className="text-[10px] opacity-50 text-inherit">{t('shortcutUpDesc') || 'Tecla para navegar para cima no menu'}</p>
</div>
<button
onClick={() => setRecordingKey(recordingKey === 'up' ? null : 'up')}
className={`px-3 py-1.5 rounded-xl text-xs font-black uppercase tracking-widest border transition-all ${
recordingKey === 'up'
? 'bg-primary-100 dark:bg-primary-950 border-primary-500 text-primary-600 ring-2 ring-primary-500 animate-pulse'
: 'bg-gray-100 dark:bg-gray-800 border-transparent text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700'
}`}
>
{recordingKey === 'up' ? t('pressAnyKey') || 'Pressione uma tecla...' : formatKeyName(shortcutUpKey)}
</button>
</div>
<div className="flex items-center justify-between">
<div>
<p className="text-xs font-bold text-inherit">{t('shortcutDown') || 'Navegar para Baixo'}</p>
<p className="text-[10px] opacity-50 text-inherit">{t('shortcutDownDesc') || 'Tecla para navegar para baixo no menu'}</p>
</div>
<button
onClick={() => setRecordingKey(recordingKey === 'down' ? null : 'down')}
className={`px-3 py-1.5 rounded-xl text-xs font-black uppercase tracking-widest border transition-all ${
recordingKey === 'down'
? 'bg-primary-100 dark:bg-primary-950 border-primary-500 text-primary-600 ring-2 ring-primary-500 animate-pulse'
: 'bg-gray-100 dark:bg-gray-800 border-transparent text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700'
}`}
>
{recordingKey === 'down' ? t('pressAnyKey') || 'Pressione uma tecla...' : formatKeyName(shortcutDownKey)}
</button>
</div>
</div>
)}
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4"> <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
<div> <div>
<p className="font-bold text-inherit flex items-center gap-2">{t('dailyOutfitNotification')}</p> <p className="font-bold text-inherit flex items-center gap-2">{t('dailyOutfitNotification')}</p>

View File

@@ -225,6 +225,12 @@ export const translations = {
userOutfits: "Outfits do Utilizador", userOutfits: "Outfits do Utilizador",
userCloset: "Armário", userCloset: "Armário",
usernameTaken: "Este nome de utilizador já está em uso.", usernameTaken: "Este nome de utilizador já está em uso.",
shortcutUp: "Navegar para Cima",
shortcutDown: "Navegar para Baixo",
shortcutUpDesc: "Tecla para navegar para cima no menu",
shortcutDownDesc: "Tecla para navegar para baixo no menu",
pressAnyKey: "Pressione uma tecla...",
spaceKey: "Espaço",
}, },
EN: { EN: {
loginModeIntro: "The Future of Your Style", loginModeIntro: "The Future of Your Style",
@@ -452,6 +458,12 @@ export const translations = {
userOutfits: "User's Outfits", userOutfits: "User's Outfits",
userCloset: "Closet", userCloset: "Closet",
usernameTaken: "This username is already taken.", usernameTaken: "This username is already taken.",
shortcutUp: "Navigate Up",
shortcutDown: "Navigate Down",
shortcutUpDesc: "Key to navigate up in the menu",
shortcutDownDesc: "Key to navigate down in the menu",
pressAnyKey: "Press a key...",
spaceKey: "Space",
}, },
ES: { ES: {
loginModeIntro: "El Futuro de Tu Estilo", loginModeIntro: "El Futuro de Tu Estilo",
@@ -679,6 +691,12 @@ export const translations = {
userOutfits: "Outfits del Usuario", userOutfits: "Outfits del Usuario",
userCloset: "Armario", userCloset: "Armario",
usernameTaken: "Este nombre de usuario ya está en uso.", usernameTaken: "Este nombre de usuario ya está en uso.",
shortcutUp: "Navegar hacia Arriba",
shortcutDown: "Navegar hacia Abajo",
shortcutUpDesc: "Tecla para navegar hacia arriba en el menú",
shortcutDownDesc: "Tecla para navegar hacia abajo en el menú",
pressAnyKey: "Presione una tecla...",
spaceKey: "Espacio",
}, },
FR: { FR: {
loginModeIntro: "Le Futur de Ton Style", loginModeIntro: "Le Futur de Ton Style",
@@ -906,6 +924,12 @@ export const translations = {
userOutfits: "Outfits de l'Utilisateur", userOutfits: "Outfits de l'Utilisateur",
userCloset: "Placard", userCloset: "Placard",
usernameTaken: "Ce nom d'utilisateur est déjà utilisé.", usernameTaken: "Ce nom d'utilisateur est déjà utilisé.",
shortcutUp: "Naviguer vers le Haut",
shortcutDown: "Naviguer vers le Bas",
shortcutUpDesc: "Touche pour naviguer vers le haut dans le menu",
shortcutDownDesc: "Touche pour naviguer vers le bas dans le menu",
pressAnyKey: "Appuyez sur une touche...",
spaceKey: "Espace",
}, },
DE: { DE: {
loginModeIntro: "Die Zukunft deines Stils", loginModeIntro: "Die Zukunft deines Stils",
@@ -1133,5 +1157,11 @@ export const translations = {
userOutfits: "Outfits des Benutzers", userOutfits: "Outfits des Benutzers",
userCloset: "Kleiderschrank", userCloset: "Kleiderschrank",
usernameTaken: "Dieser Benutzername ist bereits vergeben.", usernameTaken: "Dieser Benutzername ist bereits vergeben.",
shortcutUp: "Nach oben navigieren",
shortcutDown: "Nach unten navigieren",
shortcutUpDesc: "Taste zum Navigieren nach oben im Menü",
shortcutDownDesc: "Taste zum Navigieren nach unten im Menü",
pressAnyKey: "Taste drücken...",
spaceKey: "Leertaste",
} }
}; };