Adding new style

This commit is contained in:
Moritz Graf 2026-01-02 20:08:53 +01:00
parent 3b836d945e
commit 3fa3eb90ee
2 changed files with 87 additions and 63 deletions

View File

@ -25,7 +25,7 @@ test('smoke test - app loads and editor opens', async ({ page }) => {
await navButton.click() await navButton.click()
} }
await expect(page.getByRole('heading', { name: 'Workout Plans' })).toBeVisible() await expect(page.getByRole('heading', { name: 'My Plans' })).toBeVisible()
// 4. Navigate to Editor // 4. Navigate to Editor
await page.getByRole('button', { name: 'New Plan' }).click() await page.getByRole('button', { name: 'New Plan' }).click()

View File

@ -305,54 +305,45 @@ const getSportName = (workout) => {
<template> <template>
<div class="h-full flex flex-col p-6 max-w-6xl mx-auto w-full"> <div class="h-full flex flex-col p-6 max-w-6xl mx-auto w-full">
<!-- LINK TO DASHBOARD --> <!-- BROWSER TOOLBAR -->
<div v-if="viewMode === 'browser'" class="mb-6 flex justify-between items-center"> <div v-if="viewMode === 'browser'" class="editor-toolbar mb-6 rounded-xl">
<div> <div class="toolbar-left">
<h1 <h2 class="text-lg font-bold text-white tracking-tight">My Plans</h2>
class="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-400 mb-2" <div class="toolbar-divider"></div>
> <!-- Search Input Stub -->
Workout Plans <div class="relative group">
</h1> <input
<p class="text-gray-400">Manage your training collection</p> type="text"
placeholder="Search workouts..."
class="bg-transparent border-none text-sm text-white focus:outline-none w-48 transition-all"
/>
</div>
</div> </div>
<div class="flex gap-4"> <div class="toolbar-right">
<!-- Source Toggle --> <!-- Source Toggle (Segmented) -->
<div class="flex gap-2 bg-gray-900/50 p-1 rounded-lg border border-gray-800"> <div class="segmented-control">
<button <button :class="{ active: sourceMode === 'remote' }" @click="setSourceMode('remote')">
:class="[
'px-4 py-2 rounded-md text-sm font-medium transition-all flex items-center gap-2',
sourceMode === 'remote'
? 'bg-blue-600 text-white shadow-lg shadow-blue-900/20'
: 'text-gray-400 hover:text-white hover:bg-white/5'
]"
@click="setSourceMode('remote')"
>
<Cloud class="w-4 h-4" /> <Cloud class="w-4 h-4" />
Gapminder <span>Gapminder</span>
</button> </button>
<button <button :class="{ active: sourceMode === 'local' }" @click="setSourceMode('local')">
class="px-4 py-1.5 rounded-md transition-all" <FileJson class="w-4 h-4" />
:class=" <span>Local</span>
sourceMode === 'local'
? 'bg-purple-600 text-white shadow-lg'
: 'text-gray-400 hover:text-white'
"
@click="setSourceMode('local')"
>
Local Files
</button> </button>
</div> </div>
<button class="primary-btn" @click="createNewWorkout"> <div class="toolbar-divider"></div>
<Plus class="w-5 h-5" /> New Plan
<button class="toolbar-btn primary-btn" @click="createNewWorkout">
<Plus class="w-4 h-4" />
<span>New Plan</span>
</button> </button>
</div> </div>
</div> </div>
<!-- WORKOUT BROWSER --> <!-- WORKOUT BROWSER GRID -->
<div v-if="viewMode === 'browser'" class="flex-1 overflow-y-auto custom-scrollbar"> <div v-if="viewMode === 'browser'" class="flex-1 overflow-y-auto custom-scrollbar px-1">
<!-- ... existing browser content ... -->
<div v-if="loading" class="flex flex-col items-center justify-center h-64 text-gray-500"> <div v-if="loading" class="flex flex-col items-center justify-center h-64 text-gray-500">
<Loader2 class="w-8 h-8 animate-spin mb-2" /> <Loader2 class="w-8 h-8 animate-spin mb-2" />
<span>Loading workouts...</span> <span>Loading workouts...</span>
@ -367,44 +358,59 @@ const getSportName = (workout) => {
v-for="workout in workouts" v-for="workout in workouts"
:key="workout.workoutId || workout.filename" :key="workout.workoutId || workout.filename"
class="workout-card group" class="workout-card group"
@click="editWorkout(workout)"
> >
<div class="flex justify-between items-start mb-3"> <!-- Card Badge (Top Right Action Area) -->
<div
class="absolute top-3 right-3 flex gap-2 opacity-0 group-hover:opacity-100 transition-all transform translate-x-2 group-hover:translate-x-0 z-10"
>
<button
class="p-2 bg-gray-800 hover:bg-gray-700 text-white rounded-lg shadow-lg border border-gray-700 transition-colors"
title="Duplicate"
@click.stop="duplicateWorkout(workout)"
>
<Copy class="w-4 h-4" />
</button>
<button
class="p-2 bg-blue-600 hover:bg-blue-500 text-white rounded-lg shadow-lg shadow-blue-900/20 border border-blue-500/50 transition-colors"
title="Edit"
@click.stop="editWorkout(workout)"
>
<Edit2 class="w-4 h-4" />
</button>
</div>
<!-- Card Icon -->
<div class="mb-4">
<div <div
class="p-2 rounded-lg bg-gray-800 text-blue-400 group-hover:bg-blue-900/30 transition-colors" class="w-12 h-12 rounded-xl flex items-center justify-center bg-gradient-to-br from-gray-800 to-gray-900 border border-gray-700 text-blue-400 group-hover:border-blue-500/30 group-hover:text-blue-300 transition-all shadow-inner"
> >
<Dumbbell v-if="isStrength(workout)" class="w-6 h-6" /> <Dumbbell v-if="isStrength(workout)" class="w-6 h-6" />
<Activity v-else class="w-6 h-6" /> <Activity v-else class="w-6 h-6" />
</div> </div>
<div class="flex gap-2">
<button
class="icon-btn p-1.5 hover:bg-white/10 rounded-md transition-colors text-gray-400 hover:text-white"
title="Duplicate"
@click.stop="duplicateWorkout(workout)"
>
<Copy class="w-5 h-5" />
</button>
<button
class="icon-btn p-1.5 hover:bg-white/10 rounded-md transition-colors text-gray-400 hover:text-white"
title="Edit"
@click.stop="editWorkout(workout)"
>
<Edit2 class="w-5 h-5" />
</button>
</div>
</div> </div>
<h3 class="font-bold text-lg mb-1 truncate">{{ workout.workoutName }}</h3>
<p class="text-xs text-gray-400 mb-4 line-clamp-2">
{{ workout.description || 'No description provided' }}
</p>
<!-- Content -->
<div class="flex-1">
<h3
class="font-bold text-base text-white mb-1 group-hover:text-blue-400 transition-colors truncate"
>
{{ workout.workoutName }}
</h3>
<p class="text-xs text-gray-500 line-clamp-2 leading-relaxed">
{{ workout.description || 'No description provided' }}
</p>
</div>
<!-- Footer -->
<div <div
class="mt-auto flex justify-between items-center text-xs text-gray-500 border-t border-gray-800 pt-3" class="mt-4 pt-3 border-t border-gray-800 flex justify-between items-center text-[10px] uppercase font-bold tracking-wider text-gray-600"
> >
<span>{{ getSportName(workout) }}</span> <span>{{ getSportName(workout) }}</span>
<span v-if="workout.isLocal" class="text-purple-400 flex items-center gap-1"> <span v-if="workout.isLocal" class="text-purple-400/80 flex items-center gap-1">
<FileJson class="w-3 h-3" /> Local <FileJson class="w-3 h-3" /> Local
</span> </span>
<span v-else class="text-blue-400 flex items-center gap-1"> <span v-else class="text-blue-400/80 flex items-center gap-1">
<Cloud class="w-3 h-3" /> Garmin <Cloud class="w-3 h-3" /> Garmin
</span> </span>
</div> </div>
@ -687,6 +693,24 @@ const getSportName = (workout) => {
box-shadow: 0 4px 12px rgba(31, 111, 235, 0.3); box-shadow: 0 4px 12px rgba(31, 111, 235, 0.3);
} }
.workout-card {
background: #0d1117; /* Darker Github-like bg */
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 1.25rem;
display: flex;
flex-direction: column;
position: relative;
transition: all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);
cursor: pointer;
}
.workout-card:hover {
transform: translateY(-2px);
border-color: #3b82f6; /* Blue 500 */
box-shadow: 0 10px 30px -10px rgba(59, 130, 246, 0.15);
}
.sync-res { .sync-res {
font-size: 0.9rem; font-size: 0.9rem;
margin-right: 1rem; margin-right: 1rem;