chore: archive inactive projects to apps-archived/

Move inactive projects out of active workspace:
- bauntown (community website)
- maerchenzauber (AI story generation)
- memoro (voice memo app)
- news (news aggregation)
- nutriphi (nutrition tracking)
- reader (reading app)
- uload (URL shortener)
- wisekeep (AI wisdom extraction)

Update CLAUDE.md documentation:
- Add presi to active projects
- Document archived projects section
- Update workspace configuration

Archived apps can be re-activated by moving back to apps/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-11-29 07:03:59 +01:00
parent b97149ac12
commit 61d181fbc2
3148 changed files with 437 additions and 46640 deletions

View file

@ -0,0 +1,66 @@
import Constants from 'expo-constants';
const API_BASE = Constants.expoConfig?.extra?.apiUrl || 'http://localhost:3006';
export interface TranscriptionJob {
id: string;
url: string;
language: string;
provider: string;
model?: string;
status: 'pending' | 'downloading' | 'transcribing' | 'completed' | 'failed' | 'cancelled';
progress: number;
createdAt: string;
completedAt?: string;
videoInfo?: {
id: string;
title: string;
channel: string;
thumbnail: string;
duration: number;
};
transcriptPath?: string;
transcriptText?: string;
error?: string;
}
export interface CreateJobRequest {
url: string;
language?: string;
provider?: 'openai' | 'local';
model?: 'tiny' | 'base' | 'small' | 'medium' | 'large';
}
async function request<T>(endpoint: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${API_BASE}${endpoint}`, {
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
});
if (!res.ok) {
const error = await res.json().catch(() => ({ message: res.statusText }));
throw new Error(error.message || 'Request failed');
}
return res.json();
}
export const api = {
createJob: (data: CreateJobRequest) =>
request<TranscriptionJob>('/transcription', {
method: 'POST',
body: JSON.stringify(data),
}),
getJob: (id: string) => request<TranscriptionJob>(`/transcription/${id}`),
getAllJobs: () => request<TranscriptionJob[]>('/transcription'),
cancelJob: (id: string) =>
request<TranscriptionJob>(`/transcription/${id}`, { method: 'DELETE' }),
health: () => request<{ status: string }>('/health'),
};

View file

@ -0,0 +1,57 @@
import { create } from 'zustand';
import type { TranscriptionJob } from '@/services/api';
interface JobStore {
jobs: TranscriptionJob[];
activeJobs: TranscriptionJob[];
addJob: (job: TranscriptionJob) => void;
updateJob: (id: string, updates: Partial<TranscriptionJob>) => void;
removeJob: (id: string) => void;
setJobs: (jobs: TranscriptionJob[]) => void;
}
export const useJobStore = create<JobStore>((set, get) => ({
jobs: [],
activeJobs: [],
addJob: (job) =>
set((state) => {
const jobs = [job, ...state.jobs];
return {
jobs,
activeJobs: jobs.filter(
(j) => j.status === 'pending' || j.status === 'downloading' || j.status === 'transcribing'
),
};
}),
updateJob: (id, updates) =>
set((state) => {
const jobs = state.jobs.map((j) => (j.id === id ? { ...j, ...updates } : j));
return {
jobs,
activeJobs: jobs.filter(
(j) => j.status === 'pending' || j.status === 'downloading' || j.status === 'transcribing'
),
};
}),
removeJob: (id) =>
set((state) => {
const jobs = state.jobs.filter((j) => j.id !== id);
return {
jobs,
activeJobs: jobs.filter(
(j) => j.status === 'pending' || j.status === 'downloading' || j.status === 'transcribing'
),
};
}),
setJobs: (jobs) =>
set({
jobs,
activeJobs: jobs.filter(
(j) => j.status === 'pending' || j.status === 'downloading' || j.status === 'transcribing'
),
}),
}));