Skip to content

Commit 84c8eaf

Browse files
swordbreakerTobias Bollinger
andauthored
Feature/UI redesing (#163)
* feat: redesign media upload UI with modern animations and improved UX - Complete UI overhaul of MediaPreviewView, MediaProcessingView, and MediaSelectionView - Add motion-v animations and enhanced visual design with gradients and shadows - Implement step-by-step media processing workflow with progress indicators - Add AGENTS.md coding guidelines document - Fix FFmpeg instance cleanup and improve error handling - Update types for media step configuration and processing * refactor: modularize media processing and task management Extract MediaProgressView component and useTaskListener composable for better separation of concerns. Replace command bus pattern with direct task polling, simplify error handling, and move layout structure to default layout. * feat: redesign transcription detail page with animations and improved layout - Add motion-v animations for page transitions, buttons, and sections - Teleport transcription info to layout header (left side) as popover - Teleport export toolbar to layout header (right side) - Add loading state with animated spinner - Enhance summary section with amber gradient styling - Improve mode toggle with sliding indicator animation - Add i18n translations for nameLabel and noMedia - Make layout more mobile-friendly with responsive design * Worked on the ui * Updated the edit view * cleanup of transcriptionService * added dummy mode * fixed the MediaPlaybackBar * Squash merge ai/testing into feature/ui-redesing * update the ci files * Update the transcription list * added cleanupTranscriptions * Addd speaker stats * added a progress indication for one segement * added summary types * added support for word export In the export toolbar and a new button in the summary view. * fixed pr findings * Update bun.lock * updated the translation file * Removed unused component * bumpt version to 0.6.0 * fixed pr findings * Delete KeyboardShortcutsHint.vue * fixed bun errors * fixed console warnings * added onboarding * Add language selection to summary feature - Create languages utility with 60+ supported languages (de, en, fr, it at top) - Add optional language field to SummarizeRequest schema - Add language selector with flag icons to summary popover - Persist language selection using VueUse useStorage - Add i18n translations for language selection labels * fixed some ui bugs and added summary language * bumpt to v1.0.0 * fixed pr finding s --------- Co-authored-by: Tobias Bollinger <tobias.bollinger@bs.ch>
1 parent 97eb928 commit 84c8eaf

File tree

108 files changed

+7350
-4047
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+7350
-4047
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
API_URL='http://localhost:8000'
2+
DUMMY=false
23
GITHUB_TOKEN='YOUR_GITHUB_TOKEN'
4+
5+
LOGGER_LAYER_URI=github:DCC-BS/nuxt-layers/pino-logger

.github/workflows/ci.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
- main
1010

1111
jobs:
12-
build:
12+
ci:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: DCC-BS/ci-workflows/actions/node-bun-biome-playwright@v8
@@ -20,6 +20,5 @@ jobs:
2020
run_playwright: "false"
2121
install_method: "bun"
2222
build_command: "bun run build"
23-
test_command: "bunx playwright test"
24-
artifact_name: "playwright-report"
25-
artifact_retention_days: 30
23+
- name: test
24+
run: bun run test

.github/workflows/docker-publish.yml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
name: Build and Publish Docker Image
22
on:
33
workflow_dispatch:
4-
inputs:
5-
version_bump:
6-
description: Version bump type
7-
required: true
8-
default: patch
9-
type: choice
10-
options: [major, minor, patch]
114

125
permissions:
136
contents: write
@@ -18,7 +11,6 @@ jobs:
1811
uses: DCC-BS/ci-workflows/.github/workflows/publish-docker.yml@v8
1912
secrets: inherit
2013
with:
21-
release_type: ${{ inputs.version_bump }} # major|minor|patch
2214
version_project_type: "node" # or "python"
2315
registry: ghcr.io
2416
image_name: ghcr.io/${{ github.repository }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ logs
2323
.env.*
2424
!.env.example
2525
!docker/.env.backend.example
26+
27+
.worktreees/*

.nuxtrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
setups.@nuxt/test-utils="4.0.0"

AGENTS.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Transcribo Frontend - Agent Coding Guidelines
2+
3+
## Build & Development Commands
4+
5+
```bash
6+
# Install dependencies (Bun required, not npm)
7+
bun install
8+
9+
# Development server
10+
bun run dev
11+
12+
# Build for production
13+
bun run build
14+
15+
# Start production server
16+
bun run start
17+
18+
# Generate static site
19+
bun run generate
20+
21+
# Linting & Formatting
22+
bun run lint # Biome format --write
23+
bun run check # Biome check --fix
24+
25+
# Docker
26+
bun run docker:dev # Start dev container
27+
bun run docker:dev:down # Stop dev container
28+
bun run docker:prod # Start production container
29+
bun run docker:prod:down # Stop production container
30+
```
31+
32+
## Package Manager
33+
**Use `bun` for all package operations, NOT npm.**
34+
35+
## Code Style Guidelines
36+
37+
### TypeScript & Vue
38+
- **Always use Composition API** (`<script setup lang="ts">`)
39+
- **Never use `any` type** - use `unknown` with validation or specific types
40+
- **Never use non-null assertion `!`** - structure code so TypeScript understands nullable values
41+
- **Always use semicolons** - terminate all statements
42+
- **Prefer undefined over null** - use `ref(undefined)` not `ref(null)`
43+
- **Non-null refs** - initialize refs with values, not null
44+
- **Explicit types** - function parameters and return types must be typed
45+
- **Function declarations** - use `function foo()` not `const foo = () => {}`
46+
- **Async/await** - prefer over promise chains
47+
48+
### Naming Conventions
49+
- **Pages**: kebab-case (`user-profile.vue`)
50+
- **Components**: PascalCase (`UserProfileCard.vue`)
51+
- **Composables**: camelCase with `use` prefix (`useCounter.ts`)
52+
- **Server API**: kebab-case (`user-account.get.ts`)
53+
- **Utils/Services**: camelCase (`formatDate.ts`)
54+
55+
### Import Aliases
56+
```typescript
57+
~/ // app/ directory
58+
~~/ // root directory
59+
~~/server // server directory
60+
```
61+
62+
### UI & Styling
63+
- **Use Nuxt UI components** instead of custom implementations
64+
- **Use Tailwind CSS** for styling (native, no custom CSS when possible)
65+
- **Use Lucide icons** (auto-imported via Nuxt UI)
66+
- **Use motion** for animations (auto-imported via `motion-v`)
67+
68+
### Formatting (Biome)
69+
- 4 space indentation
70+
- Double quotes for strings
71+
- Semicolons required
72+
- `organizeImports` enabled
73+
74+
## Key Conventions from Cursor/Copilot Rules
75+
- Use `===` and `!==` for equality
76+
- No `console` in production code
77+
- No `@ts-ignore` - always fix type errors
78+
- No TypeScript enums
79+
- No reassigning function parameters
80+
- No unused imports/variables (ignored in .vue files)
81+
- Use `for-of` instead of `forEach`
82+
- Use `Array.isArray()` instead of `instanceof Array`
83+
- Throw Error objects with messages
84+
- Handle async errors properly with try/catch
85+
86+
## Project Structure
87+
```
88+
app/
89+
components/ # Vue components (PascalCase)
90+
composables/ # use* functions (camelCase) + other composables
91+
pages/ # Routes (kebab-case)
92+
utils/ # Framework-agnostic utilities
93+
services/ # API/business logic (e.g., indexDbService.ts)
94+
types/ # TypeScript definitions
95+
plugins/ # Nuxt plugins (e.g., api.ts, konvaPlugin.client.ts)
96+
layouts/ # Page layouts (default.vue, edit.vue)
97+
assets/ # Static assets (CSS, images, disclaimer.html)
98+
server/
99+
api/ # API endpoints (kebab-case with HTTP method suffix)
100+
utils/ # Server utilities
101+
changelogs/ # Version changelog markdown files
102+
tsconfig.json # Server-specific TypeScript config
103+
public/
104+
ios/ # PWA icons for iOS
105+
icons.json # PWA icon configuration
106+
```
107+
108+
## Key Dependencies
109+
- **Nuxt UI 4.x** - Component library
110+
- **@ffmpeg/ffmpeg** - Audio/video processing in browser
111+
- **dexie** - IndexedDB wrapper for local storage
112+
- **konva / vue-konva** - Canvas rendering for timeline editor
113+
- **ts-pattern** - Pattern matching
114+
- **zod** - Runtime type validation
115+
- **motion-v** - Vue animations
116+
117+
## Nuxt Features
118+
- Auto-imports enabled for composables, utils, components
119+
- TypeScript strict mode enabled
120+
- Pinia for state management
121+
- Nuxt UI for components
122+
- i18n for internationalization (en, de)
123+
- PWA support via @vite-pwa/nuxt
124+
- Extends GitHub layers: backend_communication, health_check, feedback-control, logger
125+
126+
## Testing
127+
- No test framework currently configured
128+
- Tests should be added when implementing new features
129+
130+
## Before Committing
131+
1. Run `bun run check` - fix all linting issues
132+
2. Run `bun run build` - ensure production build works

app/app.config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export default defineAppConfig({
2+
// ui: {
3+
// colors: {
4+
// primary: "purple",
5+
// secondary: "teal",
6+
// success: "green",
7+
// info: "blue",
8+
// warning: "yellow",
9+
// error: "red",
10+
// },
11+
// },
12+
});

app/app.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const disclaimerText = disclaimerTextRaw as string;
1010
const { isOpen, title, message, onSubmit, onClose } = useInitDialog();
1111
const { undo, redo, canUndo, canRedo } = useCommandHistory();
1212
13+
const appConfig = useAppConfig();
14+
1315
onMounted(() => {
1416
window.addEventListener("keydown", handleKeyDown);
1517
});
@@ -32,7 +34,6 @@ function handleKeyDown(event: KeyboardEvent) {
3234
<template>
3335
<NuxtPwaManifest />
3436
<Changelogs />
35-
<FeedbackControl />
3637
<Disclaimer
3738
app-name="Transcribo"
3839
:postfixHTML="disclaimerText"

app/components/AudioRecordingView.client.vue

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const { isReady, abandonedRecording } =
1717
logger: debugLog,
1818
});
1919
20-
const audioRecorder = ref<typeof AudioRecorder>();
2120
const shouldRecord = ref(false);
2221
const isRecording = ref(false);
2322
const audioBlob = ref<Blob | undefined>(undefined);
@@ -27,6 +26,7 @@ function onRecordingStopped(file: Blob, _: string) {
2726
isRecording.value = false;
2827
audioBlob.value = file;
2928
userRecording.value = true;
29+
emitAudio();
3030
}
3131
3232
function emitAudio(): void {
@@ -62,10 +62,6 @@ const audioSessionActions = computed(() => [
6262
t("pages.index.recordAudio") }}</UButton>
6363
</div>
6464
<div v-if="isReady && shouldRecord">
65-
<AudioRecorder ref="audioRecorder" :logger="debugLog" auto-start :show-result="true"
66-
@recording-stopped="onRecordingStopped" />
67-
<div v-if="audioBlob" class="flex flex-col justify-center items-center mt-4">
68-
<UButton @click="emitAudio">{{ t("audioRecorder.useRecording") }}</UButton>
69-
</div>
65+
<AudioRecorder :logger="debugLog" auto-start :show-result="true" @recording-stopped="onRecordingStopped" />
7066
</div>
71-
</template>
67+
</template>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<script setup lang="ts">
2+
import { motion } from "motion-v";
3+
import { UButton } from "#components";
4+
5+
type EditorMode = "view" | "summary" | "edit" | "statistics";
6+
7+
const UButtonMotion = motion.create(UButton);
8+
9+
const props = withDefaults(
10+
defineProps<{ idPrefix?: string }>(),
11+
{ idPrefix: "" }
12+
);
13+
14+
const mode = defineModel<EditorMode>({ default: "view" });
15+
16+
const { t } = useI18n();
17+
18+
const modes: { value: EditorMode; icon: string; label: string }[] = [
19+
{ value: "view", icon: "i-lucide-eye", label: "viewer" },
20+
{ value: "summary", icon: "i-lucide-sparkles", label: "summary" },
21+
{ value: "edit", icon: "i-lucide-square-pen", label: "editor" },
22+
{ value: "statistics", icon: "i-lucide-bar-chart-2", label: "statistics" },
23+
];
24+
</script>
25+
26+
<template>
27+
<div :id="`${props.idPrefix}editor-mode-selector`" class="editor-mode-selector">
28+
<UFieldGroup>
29+
<UButtonMotion
30+
v-for="(m, index) in modes"
31+
:key="m.value"
32+
:variant="mode === m.value ? 'solid' : 'soft'"
33+
color="primary"
34+
:whileHover="{ scale: 1.02 }"
35+
:whileTap="{ scale: 0.98 }"
36+
:transition="{
37+
type: 'spring' as const,
38+
stiffness: 400,
39+
damping: 17,
40+
}"
41+
@click="mode = m.value"
42+
:id="`${props.idPrefix}mode-${m.value}`"
43+
>
44+
<UIcon :name="m.icon" class="w-4 h-4" />
45+
<span>{{ t(`mode.${m.label}`) }}</span>
46+
</UButtonMotion>
47+
</UFieldGroup>
48+
</div>
49+
</template>

0 commit comments

Comments
 (0)