Skip to content

Commit d4e05d7

Browse files
committed
refactor: Improve layout and spacing in book edit page and cover image picker
1 parent 82da330 commit d4e05d7

2 files changed

Lines changed: 70 additions & 99 deletions

File tree

client/lib/pages/book_edit_page.dart

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,13 @@ class _BookEditPageState extends State<BookEditPage> {
261261
return ListView(
262262
padding: const EdgeInsets.all(Spacing.md),
263263
children: [
264-
_buildCoverSection(context, provider, isDesktop: false),
265-
const SizedBox(height: Spacing.lg),
264+
Card(
265+
margin: const EdgeInsets.only(bottom: Spacing.xs),
266+
child: Padding(
267+
padding: const EdgeInsets.all(Spacing.md),
268+
child: _buildCoverSection(context, provider, isDesktop: false),
269+
),
270+
),
266271
..._buildFormSections(context, provider),
267272
],
268273
);
@@ -283,6 +288,7 @@ class _BookEditPageState extends State<BookEditPage> {
283288
child: Column(
284289
children: [
285290
Card(
291+
margin: const EdgeInsets.only(bottom: Spacing.xs),
286292
child: Padding(
287293
padding: const EdgeInsets.all(Spacing.md),
288294
child: _buildCoverSection(
@@ -292,7 +298,6 @@ class _BookEditPageState extends State<BookEditPage> {
292298
),
293299
),
294300
),
295-
const SizedBox(height: Spacing.sm),
296301
_buildSectionCard(
297302
title: 'Fetch metadata',
298303
children: [_buildMetadataSection(context, provider)],
@@ -326,26 +331,11 @@ class _BookEditPageState extends State<BookEditPage> {
326331
}) {
327332
return [
328333
_buildBasicInfoSection(context, provider),
329-
const SizedBox(height: Spacing.sm),
330334
_buildPublicationSection(),
331-
const SizedBox(height: Spacing.sm),
332335
_buildIdentifiersSection(),
333-
const SizedBox(height: Spacing.sm),
334-
_buildSectionCard(
335-
title: 'Description',
336-
children: [
337-
BookTextField(
338-
controller: _descriptionController,
339-
label: 'Description',
340-
maxLines: 5,
341-
onChanged: _provider.updateDescription,
342-
),
343-
],
344-
),
345-
const SizedBox(height: Spacing.sm),
346336
_buildSeriesSection(),
347-
const SizedBox(height: Spacing.sm),
348337
Card(
338+
margin: const EdgeInsets.only(bottom: Spacing.xs),
349339
child: Padding(
350340
padding: const EdgeInsets.symmetric(
351341
horizontal: Spacing.md,
@@ -354,13 +344,11 @@ class _BookEditPageState extends State<BookEditPage> {
354344
child: _buildPhysicalBookSection(context, provider),
355345
),
356346
),
357-
if (!skipMetadata) ...[
358-
const SizedBox(height: Spacing.sm),
347+
if (!skipMetadata)
359348
_buildSectionCard(
360349
title: 'Fetch metadata',
361350
children: [_buildMetadataSection(context, provider)],
362351
),
363-
],
364352
const SizedBox(height: Spacing.xl),
365353
];
366354
}
@@ -385,6 +373,13 @@ class _BookEditPageState extends State<BookEditPage> {
385373
onChanged: _provider.updateSubtitle,
386374
),
387375
const SizedBox(height: Spacing.md),
376+
BookTextField(
377+
controller: _descriptionController,
378+
label: 'Description',
379+
maxLines: 5,
380+
onChanged: _provider.updateDescription,
381+
),
382+
const SizedBox(height: Spacing.md),
388383
ResponsiveFormRow(
389384
isDesktop: _isDesktop,
390385
children: [
@@ -515,6 +510,7 @@ class _BookEditPageState extends State<BookEditPage> {
515510
required List<Widget> children,
516511
}) {
517512
return Card(
513+
margin: const EdgeInsets.only(bottom: Spacing.xs),
518514
child: Padding(
519515
padding: const EdgeInsets.all(Spacing.md),
520516
child: Column(

client/lib/widgets/book_edit/cover_image_picker.dart

Lines changed: 52 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -80,113 +80,88 @@ class _CoverImagePickerState extends State<CoverImagePicker> {
8080
}
8181

8282
double get _coverWidth =>
83-
widget.coverWidth ?? (widget.isDesktop ? 280.0 : 150.0);
83+
widget.coverWidth ?? (widget.isDesktop ? 280.0 : 180.0);
8484
double get _coverHeight =>
85-
widget.coverHeight ?? (widget.isDesktop ? 420.0 : 225.0);
86-
// Mobile controls width for comfortable touch targets
87-
double get _mobileControlsWidth => 280.0;
88-
89-
/// On desktop, let widget stretch to fill container.
90-
/// On mobile, constrain to fixed width.
91-
Widget _wrapWithWidth(Widget child) {
92-
if (widget.isDesktop) {
93-
return child;
94-
}
95-
return SizedBox(width: _mobileControlsWidth, child: child);
96-
}
85+
widget.coverHeight ?? (widget.isDesktop ? 420.0 : 270.0);
9786

9887
@override
9988
Widget build(BuildContext context) {
10089
final colorScheme = Theme.of(context).colorScheme;
10190

10291
return Column(
103-
// On desktop, stretch controls to fill container width
104-
crossAxisAlignment: widget.isDesktop
105-
? CrossAxisAlignment.stretch
106-
: CrossAxisAlignment.center,
92+
crossAxisAlignment: CrossAxisAlignment.stretch,
10793
children: [
10894
// Cover preview (always centered)
10995
Center(child: _buildCoverPreview(context)),
11096
SizedBox(height: widget.isDesktop ? Spacing.md : Spacing.lg),
11197

11298
// Action buttons
113-
_wrapWithWidth(
114-
Row(
115-
children: [
116-
Expanded(
117-
child: OutlinedButton.icon(
118-
onPressed: _pickImage,
119-
icon: const Icon(Icons.upload, size: 18),
120-
label: const Text('Upload'),
121-
style: OutlinedButton.styleFrom(
122-
padding: EdgeInsets.symmetric(
123-
vertical: widget.isDesktop ? 8 : 12,
124-
),
125-
),
99+
Row(
100+
children: [
101+
Expanded(
102+
child: OutlinedButton.icon(
103+
onPressed: _pickImage,
104+
icon: const Icon(Icons.upload, size: 18),
105+
label: const Text('Upload'),
106+
style: OutlinedButton.styleFrom(
107+
padding: const EdgeInsets.symmetric(vertical: 12),
126108
),
127109
),
128-
SizedBox(width: widget.isDesktop ? Spacing.md : Spacing.md),
129-
Expanded(
130-
child: OutlinedButton.icon(
131-
onPressed: () =>
132-
setState(() => _showUrlInput = !_showUrlInput),
133-
icon: const Icon(Icons.link, size: 18),
134-
label: const Text('URL'),
135-
style: OutlinedButton.styleFrom(
136-
padding: EdgeInsets.symmetric(
137-
vertical: widget.isDesktop ? 8 : 12,
138-
),
139-
backgroundColor: _showUrlInput
140-
? colorScheme.secondaryContainer
141-
: null,
142-
),
110+
),
111+
const SizedBox(width: Spacing.md),
112+
Expanded(
113+
child: OutlinedButton.icon(
114+
onPressed: () => setState(() => _showUrlInput = !_showUrlInput),
115+
icon: const Icon(Icons.link, size: 18),
116+
label: const Text('URL'),
117+
style: OutlinedButton.styleFrom(
118+
padding: const EdgeInsets.symmetric(vertical: 12),
119+
backgroundColor: _showUrlInput
120+
? colorScheme.secondaryContainer
121+
: null,
143122
),
144123
),
145-
],
146-
),
124+
),
125+
],
147126
),
148127

149128
// URL input
150129
if (_showUrlInput) ...[
151130
const SizedBox(height: Spacing.md),
152-
_wrapWithWidth(
153-
TextField(
154-
controller: _urlController,
155-
decoration: InputDecoration(
156-
labelText: 'Image URL',
157-
hintText: 'https://...',
158-
isDense: true,
159-
border: OutlineInputBorder(
160-
borderRadius: BorderRadius.circular(AppRadius.md),
161-
),
162-
suffixIcon: _urlController.text.isNotEmpty
163-
? IconButton(
164-
icon: const Icon(Icons.clear, size: 20),
165-
onPressed: () {
166-
_urlController.clear();
167-
_onUrlChanged('');
168-
},
169-
tooltip: 'Clear URL',
170-
)
171-
: null,
131+
TextField(
132+
controller: _urlController,
133+
decoration: InputDecoration(
134+
labelText: 'Image URL',
135+
hintText: 'https://...',
136+
isDense: true,
137+
border: OutlineInputBorder(
138+
borderRadius: BorderRadius.circular(AppRadius.md),
172139
),
173-
keyboardType: TextInputType.url,
174-
style: Theme.of(context).textTheme.bodySmall,
175-
onChanged: _onUrlChanged,
176-
onSubmitted: (_) => _applyUrl(),
140+
suffixIcon: _urlController.text.isNotEmpty
141+
? IconButton(
142+
icon: const Icon(Icons.clear, size: 20),
143+
onPressed: () {
144+
_urlController.clear();
145+
_onUrlChanged('');
146+
},
147+
tooltip: 'Clear URL',
148+
)
149+
: null,
177150
),
151+
keyboardType: TextInputType.url,
152+
style: Theme.of(context).textTheme.bodySmall,
153+
onChanged: _onUrlChanged,
154+
onSubmitted: (_) => _applyUrl(),
178155
),
179156
],
180157

181158
// Error message
182159
if (_error != null) ...[
183160
const SizedBox(height: Spacing.sm),
184-
_wrapWithWidth(
185-
Text(
186-
_error!,
187-
style: TextStyle(color: colorScheme.error, fontSize: 12),
188-
textAlign: TextAlign.center,
189-
),
161+
Text(
162+
_error!,
163+
style: TextStyle(color: colorScheme.error, fontSize: 12),
164+
textAlign: TextAlign.center,
190165
),
191166
],
192167
],

0 commit comments

Comments
 (0)