Apply Anpassung_1: art-specific object logic, responsive design, remove Kuppel field
- Sonnenführung: fixes Sonne as sole object, no selector shown - BEO-Sitzung / Technischer Dienst: object field hidden, DB stays empty - Kuppel field removed from form (determined by active tab) - Responsive layout: single-column on mobile, side-by-side on sm+ - Touch-friendly input sizes (py-3, text-base) - Compact header and tab labels on small screens Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,17 +43,22 @@ export default function MainClient({ kuerzel, beoId, beoName }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-white py-4 px-4">
|
<div className="min-h-screen bg-white py-2 px-2 sm:py-4 sm:px-4">
|
||||||
<main className="max-w-6xl mx-auto border-2 border-black rounded-lg p-6 bg-[#FFFFDD]">
|
<main className="max-w-6xl mx-auto border-2 border-black rounded-lg p-3 sm:p-6 bg-[#FFFFDD]">
|
||||||
<div className="flex justify-between items-center mb-6">
|
|
||||||
<h1 className="text-3xl font-bold">Logbuch — Sternwarte Welzheim</h1>
|
{/* Header */}
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex justify-between items-start sm:items-center mb-4 gap-2">
|
||||||
<span className="text-sm text-gray-600">
|
<h1 className="text-xl sm:text-3xl font-bold leading-tight">
|
||||||
|
Logbuch<span className="hidden sm:inline"> — Sternwarte Welzheim</span>
|
||||||
|
</h1>
|
||||||
|
<div className="flex items-center gap-2 shrink-0">
|
||||||
|
<span className="text-xs sm:text-sm text-gray-600 hidden sm:inline">
|
||||||
{kuerzel} — {beoName}
|
{kuerzel} — {beoName}
|
||||||
</span>
|
</span>
|
||||||
|
<span className="text-xs text-gray-600 sm:hidden">{kuerzel}</span>
|
||||||
<button
|
<button
|
||||||
onClick={handleLogout}
|
onClick={handleLogout}
|
||||||
className="text-sm px-3 py-1.5 bg-gray-200 hover:bg-gray-300 rounded-lg text-gray-700"
|
className="text-xs sm:text-sm px-2 sm:px-3 py-1.5 bg-gray-200 hover:bg-gray-300 rounded-lg text-gray-700"
|
||||||
>
|
>
|
||||||
Abmelden
|
Abmelden
|
||||||
</button>
|
</button>
|
||||||
@@ -61,24 +66,25 @@ export default function MainClient({ kuerzel, beoId, beoName }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Kuppel-Tabs */}
|
{/* Kuppel-Tabs */}
|
||||||
<div className="flex gap-1 mb-4 border-b-2 border-gray-300">
|
<div className="flex gap-1 mb-4 border-b-2 border-gray-300 overflow-x-auto">
|
||||||
{KUPPELN.map((k) => (
|
{KUPPELN.map((k) => (
|
||||||
<button
|
<button
|
||||||
key={k}
|
key={k}
|
||||||
onClick={() => { setActiveKuppel(k); setEditEntry(null); }}
|
onClick={() => { setActiveKuppel(k); setEditEntry(null); }}
|
||||||
className={`px-5 py-2 text-sm font-medium rounded-t-lg transition-colors ${
|
className={`px-3 sm:px-5 py-2 text-sm font-medium rounded-t-lg transition-colors whitespace-nowrap ${
|
||||||
activeKuppel === k
|
activeKuppel === k
|
||||||
? 'bg-[#85B7D7] text-black border-2 border-b-0 border-gray-300'
|
? 'bg-[#85B7D7] text-black border-2 border-b-0 border-gray-300'
|
||||||
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Kuppel {k}
|
<span className="sm:hidden">{k}</span>
|
||||||
|
<span className="hidden sm:inline">Kuppel {k}</span>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Eingabe/Liste-Tabs */}
|
{/* Eingabe/Liste-Tabs */}
|
||||||
<div className="flex gap-1 mb-6 border-b border-gray-200">
|
<div className="flex gap-1 mb-5 border-b border-gray-200">
|
||||||
{(['eingabe', 'liste'] as const).map((tab) => (
|
{(['eingabe', 'liste'] as const).map((tab) => (
|
||||||
<button
|
<button
|
||||||
key={tab}
|
key={tab}
|
||||||
@@ -119,14 +125,14 @@ export default function MainClient({ kuerzel, beoId, beoName }: Props) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<footer className="mt-8 flex justify-between items-center text-sm text-gray-600 px-4">
|
<footer className="mt-8 flex justify-between items-center text-xs sm:text-sm text-gray-600 px-1 sm:px-4">
|
||||||
<div>
|
<div>
|
||||||
<a href="mailto:rxf@gmx.de" className="text-blue-600 hover:underline">
|
<a href="mailto:rxf@gmx.de" className="text-blue-600 hover:underline">
|
||||||
mailto:rxf@gmx.de
|
rxf@gmx.de
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
Version {version} — {buildDate}
|
v{version} — {buildDate}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -1,34 +1,33 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
import { query } from '@/lib/db';
|
import { query, getPool } from '@/lib/db';
|
||||||
import { getSession } from '@/lib/session';
|
import { getSession } from '@/lib/session';
|
||||||
import type { SelectedObjekt } from '@/types/logbuch';
|
import type { SelectedObjekt } from '@/types/logbuch';
|
||||||
|
|
||||||
|
const LIST_SQL =
|
||||||
|
'SELECT' +
|
||||||
|
' l.ID, l.Kuppel, l.ArtFuehrung,' +
|
||||||
|
" DATE_FORMAT(l.Beginn, '%Y-%m-%dT%H:%i') AS Beginn," +
|
||||||
|
" DATE_FORMAT(l.Ende, '%Y-%m-%dT%H:%i') AS Ende," +
|
||||||
|
' l.Besucher, l.Bemerkungen,' +
|
||||||
|
' l.WetterTemp, l.WetterFeuchte, l.WetterDruck,' +
|
||||||
|
' l.created_by, l.created_at,' +
|
||||||
|
" GROUP_CONCAT(DISTINCT bk.kuerzel ORDER BY bk.kuerzel SEPARATOR ', ') AS BEOs," +
|
||||||
|
" GROUP_CONCAT(DISTINCT lo.ObjektName ORDER BY lo.ObjektName SEPARATOR ', ') AS Objekte" +
|
||||||
|
' FROM logbuch l' +
|
||||||
|
' LEFT JOIN logbuch_beos lb ON lb.LogbuchID = l.ID' +
|
||||||
|
' LEFT JOIN (SELECT id, `kürzel` AS kuerzel FROM beos) bk ON bk.id = lb.BeoID' +
|
||||||
|
' LEFT JOIN logbuch_objekte lo ON lo.LogbuchID = l.ID' +
|
||||||
|
' WHERE l.Kuppel = ?' +
|
||||||
|
' GROUP BY l.ID' +
|
||||||
|
' ORDER BY l.Beginn DESC';
|
||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
const kuppel = searchParams.get('kuppel') || 'West';
|
const kuppel = searchParams.get('kuppel') || 'West';
|
||||||
const limit = Math.min(parseInt(searchParams.get('limit') || '20'), 100);
|
const limit = Math.min(parseInt(searchParams.get('limit') || '20'), 100);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const rows = await query(
|
const rows = await query(LIST_SQL + ` LIMIT ${limit}`, [kuppel]);
|
||||||
`SELECT
|
|
||||||
l.ID, l.Kuppel, l.ArtFuehrung,
|
|
||||||
DATE_FORMAT(l.Beginn, '%Y-%m-%dT%H:%i') AS Beginn,
|
|
||||||
DATE_FORMAT(l.Ende, '%Y-%m-%dT%H:%i') AS Ende,
|
|
||||||
l.Besucher, l.Bemerkungen,
|
|
||||||
l.WetterTemp, l.WetterFeuchte, l.WetterDruck,
|
|
||||||
l.created_by, l.created_at,
|
|
||||||
GROUP_CONCAT(DISTINCT b.Kuerzel ORDER BY b.Kuerzel SEPARATOR ', ') AS BEOs,
|
|
||||||
GROUP_CONCAT(DISTINCT lo.ObjektName ORDER BY lo.ObjektName SEPARATOR ', ') AS Objekte
|
|
||||||
FROM logbuch l
|
|
||||||
LEFT JOIN logbuch_beos lb ON lb.LogbuchID = l.ID
|
|
||||||
LEFT JOIN beos b ON b.ID = lb.BeoID
|
|
||||||
LEFT JOIN logbuch_objekte lo ON lo.LogbuchID = l.ID
|
|
||||||
WHERE l.Kuppel = ?
|
|
||||||
GROUP BY l.ID
|
|
||||||
ORDER BY l.Beginn DESC
|
|
||||||
LIMIT ?`,
|
|
||||||
[kuppel, limit]
|
|
||||||
);
|
|
||||||
return NextResponse.json(rows);
|
return NextResponse.json(rows);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('GET /api/logbuch:', error);
|
console.error('GET /api/logbuch:', error);
|
||||||
@@ -44,9 +43,10 @@ export async function POST(request: NextRequest) {
|
|||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { Kuppel, ArtFuehrung, Beginn, Ende, Besucher, beoIds, objekte, Bemerkungen, Wetter } = body;
|
const { Kuppel, ArtFuehrung, Beginn, Ende, Besucher, beoIds, objekte, Bemerkungen, Wetter } = body;
|
||||||
|
|
||||||
const [result] = await (await import('@/lib/db')).getPool().execute(
|
const pool = getPool();
|
||||||
`INSERT INTO logbuch (Kuppel, ArtFuehrung, Beginn, Ende, Besucher, Bemerkungen, WetterTemp, WetterFeuchte, WetterDruck, created_by)
|
const [result] = await pool.execute(
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
'INSERT INTO logbuch (Kuppel, ArtFuehrung, Beginn, Ende, Besucher, Bemerkungen, WetterTemp, WetterFeuchte, WetterDruck, created_by)' +
|
||||||
|
' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||||
[
|
[
|
||||||
Kuppel, ArtFuehrung, Beginn, Ende,
|
Kuppel, ArtFuehrung, Beginn, Ende,
|
||||||
Besucher ?? 0,
|
Besucher ?? 0,
|
||||||
@@ -71,9 +71,7 @@ export async function POST(request: NextRequest) {
|
|||||||
if (existing[0]) {
|
if (existing[0]) {
|
||||||
objektId = existing[0].ID;
|
objektId = existing[0].ID;
|
||||||
} else {
|
} else {
|
||||||
const [ins] = await (await import('@/lib/db')).getPool().execute(
|
const [ins] = await pool.execute('INSERT INTO objekte (Name) VALUES (?)', [obj.Name]) as [{ insertId: number }, unknown];
|
||||||
'INSERT INTO objekte (Name) VALUES (?)', [obj.Name]
|
|
||||||
) as [{ insertId: number }, unknown];
|
|
||||||
objektId = ins.insertId;
|
objektId = ins.insertId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
claude/Anpassung_1.md
Normal file
10
claude/Anpassung_1.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
### Anpassung für die einzelnen Führungen
|
||||||
|
Bei den unterschiedlichen Führungen solle einige Einträge wegfallen:
|
||||||
|
* bei Sonnenführung immer die Sonne als Objekt vorgeben, keine Auswahl von anderen Objekten zulassen
|
||||||
|
* bei BEO-Sitzung und bei Technischer Dienst kein Objekte-Feld vorsehen (in der DB bleibt das Feld leer)
|
||||||
|
|
||||||
|
### Responsives Design
|
||||||
|
Passe das Design des Eingabefensters so an, dass es auf eimem Smartphone-Bildschirm gut zu bedienen ist
|
||||||
|
|
||||||
|
### Kuppel
|
||||||
|
Kein Feld für die Kuppel in der Eingabe
|
||||||
@@ -24,6 +24,9 @@ function nowLocalDatetime(): string {
|
|||||||
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NO_OBJEKTE_ARTEN: ArtFuehrung[] = ['BEO-Sitzung', 'Technischer Dienst'];
|
||||||
|
const SONNE_ART: ArtFuehrung = 'Sonnenführung';
|
||||||
|
|
||||||
export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved }: Props) {
|
export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved }: Props) {
|
||||||
const [artFuehrung, setArtFuehrung] = useState<ArtFuehrung>('Reguläre Führung');
|
const [artFuehrung, setArtFuehrung] = useState<ArtFuehrung>('Reguläre Führung');
|
||||||
const [beginn, setBeginn] = useState(nowLocalDatetime());
|
const [beginn, setBeginn] = useState(nowLocalDatetime());
|
||||||
@@ -37,6 +40,9 @@ export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved
|
|||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [success, setSuccess] = useState(false);
|
const [success, setSuccess] = useState(false);
|
||||||
|
|
||||||
|
const showObjekte = !NO_OBJEKTE_ARTEN.includes(artFuehrung);
|
||||||
|
const isSonne = artFuehrung === SONNE_ART;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch('/api/wetter')
|
fetch('/api/wetter')
|
||||||
.then((r) => { if (!r.ok) throw new Error(); return r.json(); })
|
.then((r) => { if (!r.ok) throw new Error(); return r.json(); })
|
||||||
@@ -94,6 +100,15 @@ export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved
|
|||||||
}
|
}
|
||||||
}, [editEntry]);
|
}, [editEntry]);
|
||||||
|
|
||||||
|
// Objekte-Vorauswahl je nach Art der Führung
|
||||||
|
useEffect(() => {
|
||||||
|
if (artFuehrung === SONNE_ART) {
|
||||||
|
setObjekte([{ ID: null, Name: 'Sonne' }]);
|
||||||
|
} else if (NO_OBJEKTE_ARTEN.includes(artFuehrung)) {
|
||||||
|
setObjekte([]);
|
||||||
|
}
|
||||||
|
}, [artFuehrung]);
|
||||||
|
|
||||||
async function handleSubmit(e: React.FormEvent) {
|
async function handleSubmit(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
@@ -107,7 +122,7 @@ export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved
|
|||||||
Ende: ende,
|
Ende: ende,
|
||||||
Besucher: besucher,
|
Besucher: besucher,
|
||||||
beoIds: beos.map((b) => b.ID),
|
beoIds: beos.map((b) => b.ID),
|
||||||
objekte,
|
objekte: showObjekte ? objekte : [],
|
||||||
Bemerkungen: bemerkungen,
|
Bemerkungen: bemerkungen,
|
||||||
Wetter: wetter,
|
Wetter: wetter,
|
||||||
};
|
};
|
||||||
@@ -139,80 +154,89 @@ export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const inputCls = 'w-full px-3 py-3 border-2 border-gray-400 rounded-lg bg-white text-base focus:border-blue-500 focus:outline-none';
|
||||||
<form onSubmit={handleSubmit} className="space-y-4 max-w-2xl">
|
const labelCls = 'block text-sm font-medium text-gray-700 mb-1';
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">Art der Führung</label>
|
|
||||||
<select
|
|
||||||
value={artFuehrung}
|
|
||||||
onChange={(e) => setArtFuehrung(e.target.value as ArtFuehrung)}
|
|
||||||
className="w-full px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm focus:border-blue-500 focus:outline-none"
|
|
||||||
>
|
|
||||||
{ARTEN.map((a) => (
|
|
||||||
<option key={a} value={a}>{a}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
return (
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">Kuppel</label>
|
<form onSubmit={handleSubmit} className="space-y-5 max-w-2xl">
|
||||||
<input
|
|
||||||
type="text"
|
{/* Art der Führung — volle Breite */}
|
||||||
value={kuppel}
|
<div>
|
||||||
readOnly
|
<label className={labelCls}>Art der Führung</label>
|
||||||
className="w-full px-3 py-2 border-2 border-gray-300 rounded-lg bg-gray-100 text-sm text-gray-600"
|
<select
|
||||||
/>
|
value={artFuehrung}
|
||||||
</div>
|
onChange={(e) => setArtFuehrung(e.target.value as ArtFuehrung)}
|
||||||
|
className={inputCls}
|
||||||
|
>
|
||||||
|
{ARTEN.map((a) => (
|
||||||
|
<option key={a} value={a}>{a}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
{/* Beginn / Ende — nebeneinander auf Desktop, untereinander auf Mobile */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">Beginn</label>
|
<label className={labelCls}>Beginn</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
value={beginn}
|
value={beginn}
|
||||||
onChange={(e) => setBeginn(e.target.value)}
|
onChange={(e) => setBeginn(e.target.value)}
|
||||||
required
|
required
|
||||||
className="w-full px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm focus:border-blue-500 focus:outline-none"
|
className={inputCls}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">Ende</label>
|
<label className={labelCls}>Ende</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
value={ende}
|
value={ende}
|
||||||
onChange={(e) => setEnde(e.target.value)}
|
onChange={(e) => setEnde(e.target.value)}
|
||||||
required
|
required
|
||||||
className="w-full px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm focus:border-blue-500 focus:outline-none"
|
className={inputCls}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Besucher */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">Anzahl Besucher</label>
|
<label className={labelCls}>Anzahl Besucher</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={besucher}
|
value={besucher}
|
||||||
onChange={(e) => setBesucher(parseInt(e.target.value) || 0)}
|
onChange={(e) => setBesucher(parseInt(e.target.value) || 0)}
|
||||||
min={0}
|
min={0}
|
||||||
max={9999}
|
max={9999}
|
||||||
className="w-32 px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm focus:border-blue-500 focus:outline-none"
|
className="w-32 px-3 py-3 border-2 border-gray-400 rounded-lg bg-white text-base focus:border-blue-500 focus:outline-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* BEOs */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">BEOs</label>
|
<label className={labelCls}>BEOs</label>
|
||||||
<BeoSelector selected={beos} onChange={setBeos} />
|
<BeoSelector selected={beos} onChange={setBeos} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
{/* Objekte — abhängig von der Art der Führung */}
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">Beobachtete Objekte</label>
|
{showObjekte && (
|
||||||
<ObjektSelector selected={objekte} onChange={setObjekte} />
|
<div>
|
||||||
</div>
|
<label className={labelCls}>Beobachtete Objekte</label>
|
||||||
|
{isSonne ? (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="inline-flex items-center bg-green-100 text-green-800 text-sm px-3 py-1.5 rounded-full">
|
||||||
|
Sonne
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-gray-500">(bei Sonnenführung fest vorgegeben)</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<ObjektSelector selected={objekte} onChange={setObjekte} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Bemerkungen */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className={labelCls}>
|
||||||
Bemerkungen
|
Bemerkungen
|
||||||
<span className="ml-2 text-gray-400 font-normal text-xs">({bemerkungen.length}/500)</span>
|
<span className="ml-2 text-gray-400 font-normal text-xs">({bemerkungen.length}/500)</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -220,15 +244,16 @@ export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved
|
|||||||
value={bemerkungen}
|
value={bemerkungen}
|
||||||
onChange={(e) => setBemerkungen(e.target.value.slice(0, 500))}
|
onChange={(e) => setBemerkungen(e.target.value.slice(0, 500))}
|
||||||
rows={3}
|
rows={3}
|
||||||
className="w-full px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm focus:border-blue-500 focus:outline-none resize-y"
|
className="w-full px-3 py-3 border-2 border-gray-400 rounded-lg bg-white text-base focus:border-blue-500 focus:outline-none resize-y"
|
||||||
placeholder="Freier Text (max. 500 Zeichen)"
|
placeholder="Freier Text (max. 500 Zeichen)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Wetter */}
|
||||||
{wetter && (
|
{wetter && (
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">Wetter (aktuell)</label>
|
<label className={labelCls}>Wetter (aktuell)</label>
|
||||||
<div className="flex gap-4 text-sm text-gray-600 bg-gray-50 border border-gray-200 rounded-lg px-3 py-2">
|
<div className="flex flex-wrap gap-4 text-sm text-gray-600 bg-gray-50 border border-gray-200 rounded-lg px-3 py-2">
|
||||||
<span>🌡 {wetter.temp} °C</span>
|
<span>🌡 {wetter.temp} °C</span>
|
||||||
<span>💧 {wetter.feuchte} %</span>
|
<span>💧 {wetter.feuchte} %</span>
|
||||||
<span>🌬 {wetter.druck} hPa</span>
|
<span>🌬 {wetter.druck} hPa</span>
|
||||||
@@ -247,11 +272,12 @@ export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex gap-3">
|
{/* Buttons — volle Breite auf Mobile */}
|
||||||
|
<div className="flex flex-col sm:flex-row gap-3">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
className="px-6 py-2 bg-[#85B7D7] hover:bg-[#6a9fc5] text-black font-medium rounded-lg transition-colors disabled:opacity-50 text-sm"
|
className="w-full sm:w-auto px-6 py-3 bg-[#85B7D7] hover:bg-[#6a9fc5] text-black font-medium rounded-lg transition-colors disabled:opacity-50 text-base"
|
||||||
>
|
>
|
||||||
{saving ? 'Speichern...' : editEntry ? 'Änderungen speichern' : 'Eintrag speichern'}
|
{saving ? 'Speichern...' : editEntry ? 'Änderungen speichern' : 'Eintrag speichern'}
|
||||||
</button>
|
</button>
|
||||||
@@ -259,7 +285,7 @@ export default function LogbuchForm({ kuppel, currentUserBeo, editEntry, onSaved
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onSaved}
|
onClick={onSaved}
|
||||||
className="px-6 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 font-medium rounded-lg transition-colors text-sm"
|
className="w-full sm:w-auto px-6 py-3 bg-gray-200 hover:bg-gray-300 text-gray-700 font-medium rounded-lg transition-colors text-base"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user