Reverted all changes back to version 90cfdf0785
This commit is contained in:
@@ -4,7 +4,6 @@ import "./globals.css";
|
|||||||
import { ThemeProvider } from "@/components/theme-provider";
|
import { ThemeProvider } from "@/components/theme-provider";
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
import { Footer } from "@/components/footer";
|
import { Footer } from "@/components/footer";
|
||||||
import { I18nProvider } from "@/context/i18n-context";
|
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
@@ -37,11 +36,9 @@ export default function RootLayout({
|
|||||||
enableSystem
|
enableSystem
|
||||||
disableTransitionOnChange
|
disableTransitionOnChange
|
||||||
>
|
>
|
||||||
<I18nProvider>
|
|
||||||
{children}
|
{children}
|
||||||
<Footer />
|
<Footer />
|
||||||
<Toaster />
|
<Toaster />
|
||||||
</I18nProvider>
|
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
import { HomePage } from "@/components/home-page";
|
import { ImageConverter } from "@/components/image-converter";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return <HomePage />;
|
return (
|
||||||
|
<div className="relative flex flex-col items-center justify-center min-h-screen p-4 sm:p-8 bg-gray-50 dark:bg-background font-[family-name:var(--font-geist-sans)]">
|
||||||
|
<main className="flex flex-col items-center w-full max-w-6xl z-10">
|
||||||
|
<div className="text-center mb-8">
|
||||||
|
<h1 className="text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-100 sm:text-5xl">
|
||||||
|
Image Web Exporter
|
||||||
|
</h1>
|
||||||
|
<p className="mt-3 text-lg text-gray-600 dark:text-gray-400">
|
||||||
|
Upload a picture, then export it in a different resolution and format.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ImageConverter />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@ import Link from "next/link";
|
|||||||
import { Github, Twitter } from "lucide-react";
|
import { Github, Twitter } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { changelogData } from "@/lib/changelog-data";
|
import { changelogData } from "@/lib/changelog-data";
|
||||||
import { LanguageSwitcher } from "./language-switcher";
|
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
const latestVersion = changelogData[0]?.version;
|
const latestVersion = changelogData[0]?.version;
|
||||||
@@ -15,7 +14,6 @@ export function Footer() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center gap-1">
|
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center gap-1">
|
||||||
<LanguageSwitcher />
|
|
||||||
<Button variant="ghost" size="icon" asChild>
|
<Button variant="ghost" size="icon" asChild>
|
||||||
<Link href="https://github.com/" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
|
<Link href="https://github.com/" target="_blank" rel="noopener noreferrer" aria-label="GitHub">
|
||||||
<Github className="h-4 w-4" />
|
<Github className="h-4 w-4" />
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { ImageConverter } from "@/components/image-converter";
|
|
||||||
import { useTranslation } from "@/context/i18n-context";
|
|
||||||
|
|
||||||
export function HomePage() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="relative flex flex-col items-center justify-center min-h-screen p-4 sm:p-8 bg-gray-50 dark:bg-background font-[family-name:var(--font-geist-sans)]">
|
|
||||||
<main className="flex flex-col items-center w-full max-w-6xl z-10">
|
|
||||||
<div className="text-center mb-8">
|
|
||||||
<h1 className="text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-100 sm:text-5xl">
|
|
||||||
{t('appTitle')}
|
|
||||||
</h1>
|
|
||||||
<p className="mt-3 text-lg text-gray-600 dark:text-gray-400">
|
|
||||||
{t('appDescription')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ImageConverter />
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -36,7 +36,6 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { useTranslation } from "@/context/i18n-context";
|
|
||||||
|
|
||||||
const aspectRatios = [
|
const aspectRatios = [
|
||||||
{ name: "Custom", value: "custom" },
|
{ name: "Custom", value: "custom" },
|
||||||
@@ -65,7 +64,6 @@ const initialSettings = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function ImageConverter() {
|
export function ImageConverter() {
|
||||||
const { t } = useTranslation();
|
|
||||||
const [images, setImages] = useState<File[]>([]);
|
const [images, setImages] = useState<File[]>([]);
|
||||||
const [previewUrls, setPreviewUrls] = useState<string[]>([]);
|
const [previewUrls, setPreviewUrls] = useState<string[]>([]);
|
||||||
const [filenames, setFilenames] = useState<string[]>([]);
|
const [filenames, setFilenames] = useState<string[]>([]);
|
||||||
@@ -429,7 +427,7 @@ export function ImageConverter() {
|
|||||||
<Card>
|
<Card>
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h3 className="text-lg font-medium">{t('uploadTitle')}</h3>
|
<h3 className="text-lg font-medium">Upload Images</h3>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full h-48 rounded-lg border-2 border-dashed flex items-center justify-center relative transition-colors cursor-pointer hover:border-primary/60",
|
"w-full h-48 rounded-lg border-2 border-dashed flex items-center justify-center relative transition-colors cursor-pointer hover:border-primary/60",
|
||||||
@@ -442,8 +440,8 @@ export function ImageConverter() {
|
|||||||
>
|
>
|
||||||
<div className="flex flex-col items-center justify-center text-center text-muted-foreground">
|
<div className="flex flex-col items-center justify-center text-center text-muted-foreground">
|
||||||
<Upload className="w-8 h-8 mb-2" />
|
<Upload className="w-8 h-8 mb-2" />
|
||||||
<p className="font-semibold">{t('uploadPrompt')}</p>
|
<p className="font-semibold">Click or drag and drop to upload</p>
|
||||||
<p className="text-xs text-muted-foreground mt-1">{t('uploadFormats')}</p>
|
<p className="text-xs text-muted-foreground mt-1">PNG, JPG, WEBP supported</p>
|
||||||
</div>
|
</div>
|
||||||
<Input type="file" ref={fileInputRef} onChange={handleImageChange} className="hidden" accept="image/*" multiple />
|
<Input type="file" ref={fileInputRef} onChange={handleImageChange} className="hidden" accept="image/*" multiple />
|
||||||
</div>
|
</div>
|
||||||
@@ -455,11 +453,11 @@ export function ImageConverter() {
|
|||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<CardTitle>{t('uploadedImagesTitle')}</CardTitle>
|
<CardTitle>Uploaded Images</CardTitle>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button variant="ghost" size="sm" onClick={handleClearAll} disabled={isConverting || convertingIndex !== null}><Trash2 className="mr-2 h-4 w-4" />{t('clearAll')}</Button>
|
<Button variant="ghost" size="sm" onClick={handleClearAll} disabled={isConverting || convertingIndex !== null}><Trash2 className="mr-2 h-4 w-4" />Clear All</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Remove all uploaded images.</p>
|
<p>Remove all uploaded images.</p>
|
||||||
@@ -469,7 +467,7 @@ export function ImageConverter() {
|
|||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button onClick={handleConvertAndDownloadAll} disabled={!hasImages || isConverting || convertingIndex !== null}>
|
<Button onClick={handleConvertAndDownloadAll} disabled={!hasImages || isConverting || convertingIndex !== null}>
|
||||||
<Download className="mr-2 h-4 w-4" />
|
<Download className="mr-2 h-4 w-4" />
|
||||||
{isConverting ? "Converting..." : t('downloadAll', { count: images.length })}
|
{isConverting ? "Converting..." : `Download All (${images.length})`}
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useTranslation } from "@/context/i18n-context";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import {
|
|
||||||
DropdownMenu,
|
|
||||||
DropdownMenuContent,
|
|
||||||
DropdownMenuItem,
|
|
||||||
DropdownMenuTrigger,
|
|
||||||
} from "@/components/ui/dropdown-menu";
|
|
||||||
import { Languages } from "lucide-react";
|
|
||||||
|
|
||||||
export function LanguageSwitcher() {
|
|
||||||
const { setLanguage } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownMenuTrigger asChild>
|
|
||||||
<Button variant="ghost" size="icon">
|
|
||||||
<Languages className="h-4 w-4" />
|
|
||||||
<span className="sr-only">Change language</span>
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent align="end">
|
|
||||||
<DropdownMenuItem onClick={() => setLanguage("en")}>
|
|
||||||
English
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem onClick={() => setLanguage("de")}>
|
|
||||||
Deutsch
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import React, { createContext, useState, useContext, ReactNode } from 'react';
|
|
||||||
import en from '@/locales/en.json';
|
|
||||||
import de from '@/locales/de.json';
|
|
||||||
|
|
||||||
interface I18nContextType {
|
|
||||||
language: string;
|
|
||||||
setLanguage: (language: string) => void;
|
|
||||||
t: (key: string, params?: { [key: string]: string | number }) => string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const I18nContext = createContext<I18nContextType | undefined>(undefined);
|
|
||||||
|
|
||||||
const translations: { [key: string]: { [key: string]: string } } = {
|
|
||||||
en,
|
|
||||||
de,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function I18nProvider({ children }: { children: ReactNode }) {
|
|
||||||
const [language, setLanguage] = useState('en');
|
|
||||||
|
|
||||||
const t = (key: string, params?: { [key: string]: string | number }) => {
|
|
||||||
let translation = translations[language]?.[key] || key;
|
|
||||||
if (params) {
|
|
||||||
Object.keys(params).forEach(paramKey => {
|
|
||||||
translation = translation.replace(`{${paramKey}}`, String(params[paramKey]));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return translation;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<I18nContext.Provider value={{ language, setLanguage, t }}>
|
|
||||||
{children}
|
|
||||||
</I18nContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useTranslation() {
|
|
||||||
const context = useContext(I18nContext);
|
|
||||||
if (context === undefined) {
|
|
||||||
throw new Error('useTranslation must be used within an I18nProvider');
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"appTitle": "Bild Web Exporter",
|
|
||||||
"appDescription": "Laden Sie ein Bild hoch und exportieren Sie es in einer anderen Auflösung und einem anderen Format.",
|
|
||||||
"uploadTitle": "Bilder hochladen",
|
|
||||||
"uploadPrompt": "Klicken oder per Drag & Drop hochladen",
|
|
||||||
"uploadFormats": "PNG, JPG, WEBP werden unterstützt",
|
|
||||||
"uploadedImagesTitle": "Hochgeladene Bilder",
|
|
||||||
"clearAll": "Alle löschen",
|
|
||||||
"downloadAll": "Alle herunterladen ({count})"
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"appTitle": "Image Web Exporter",
|
|
||||||
"appDescription": "Upload a picture, then export it in a different resolution and format.",
|
|
||||||
"uploadTitle": "Upload Images",
|
|
||||||
"uploadPrompt": "Click or drag and drop to upload",
|
|
||||||
"uploadFormats": "PNG, JPG, WEBP supported",
|
|
||||||
"uploadedImagesTitle": "Uploaded Images",
|
|
||||||
"clearAll": "Clear All",
|
|
||||||
"downloadAll": "Download All ({count})"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user