Skip to content

Commit c9cf1d8

Browse files
add doc for inline editable section
1 parent c5d1676 commit c9cf1d8

File tree

3 files changed

+274
-0
lines changed

3 files changed

+274
-0
lines changed

docs/frontend/.DS_Store

6 KB
Binary file not shown.
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# Event Editor Inline Editable Section
2+
3+
A self-contained inline-editable section that handles:
4+
5+
- Displaying data
6+
- Switching between read mode ↔ edit mode
7+
- Inline validation
8+
- Local form state & syncing with parent via v-model
9+
- Calling an API to save changes
10+
11+
The below example uses `Basics` for the data
12+
13+
---
14+
15+
## Overview of Uranus Inline Edit Component Structure and Responsibilities
16+
17+
| Layer | Purpose |
18+
|-------|---------|
19+
| `UranusInlineEditSection` | Provides “editable section” layout and styling |
20+
| `UranusInlineEditLabel` | Shows label and edit button |
21+
| `isEditing` | Controls edit/read switching |
22+
| `local` reactive object | Source of truth while editing |
23+
| `watch()` modelValue → local | Parent changes update local |
24+
| `watch() `local → parent` | Two-way binding updates parent |
25+
| Computed `nameError` | Local inline validation for each data item which need error indication |
26+
| `save()` | Sends data to server and emits update |
27+
| `UranusInlineActionBar` | Save and Cancel UX controls |
28+
29+
30+
---
31+
32+
## 1. Template: UI Structure & Render Logic
33+
34+
### Top-Level Layout
35+
```html
36+
<UranusInlineEditSection :active="isEditing">
37+
```
38+
39+
- Provides the “editing frame” (borders, background, etc.)
40+
- Receives the active flag → determines whether edit mode styling is active
41+
42+
43+
### Inline Edit Label
44+
```html
45+
<UranusInlineEditLabel
46+
:label-text="t('label')"
47+
:edit-button-text="t('edit')"
48+
@edit-started="startEditing" />
49+
```
50+
51+
**Responsibilities:**
52+
53+
- Shows a label for the inline section
54+
- Shows an “Edit” button
55+
- Emits edit-started to trigger edit mode
56+
57+
58+
### Edit Mode Content
59+
60+
`<UranusInlineSectionLayout>` only renders when editing:
61+
62+
```html
63+
<UranusInlineSectionLayout v-if="isEditing">
64+
<UranusTextInput ... />
65+
<UranusTextInput ... />
66+
<UranusInlineActionBar>...</UranusInlineActionBar>
67+
</UranusInlineSectionLayout>
68+
```
69+
70+
**Responsibilities:**
71+
72+
- Provides a layout container for editable fields
73+
- Action bar with Save / Cancel buttons
74+
75+
76+
### Read Mode Content
77+
78+
```html
79+
<div v-else>
80+
<h1>{{ ... }}</h1>
81+
<h3>{{ ... }}</h3>
82+
</div>
83+
```
84+
85+
**Responsibilities:**
86+
87+
- Displays the values without editing controls
88+
- Fully decoupled from edit mode
89+
90+
91+
---
92+
93+
## 2. Script: Logic & State Management
94+
95+
### Props
96+
97+
```js
98+
const props = defineProps<{
99+
modelValue?: Basics | null
100+
propAError?: string | null
101+
}>()
102+
```
103+
104+
**Responsibilities:**
105+
106+
- `modelValue`: receives event basics data from parent
107+
- `nameError `: optional external validation error (server or parent UI)
108+
109+
110+
### Emit
111+
112+
```js
113+
const emit = defineEmits<{
114+
(e: 'update:modelValue', v: Basics | null): void
115+
(e: 'updated'): void
116+
}>()
117+
```
118+
119+
**Responsibilities:**
120+
121+
- `update:modelValue` → two-way binding
122+
- `updated` → tells parent to reload data or show success indicator
123+
124+
125+
### Local Editable Copy
126+
127+
```js
128+
const local = reactive<Basics>({
129+
id: props.modelValue?.id,
130+
prop_a: props.modelValue?.prop_a ?? '',
131+
prop_b: props.modelValue?.prop_b ?? null,
132+
})
133+
```
134+
135+
**Responsibilities:**
136+
137+
- Keeps all editing state local
138+
- Independent from props.modelValue so cancel is possible
139+
- Ensures form is always non-null, safe to edit
140+
141+
142+
### Sync: Parent → Local
143+
144+
```js
145+
watch(() => props.modelValue, (nv) => {
146+
if (nv) Object.assign(local, nv)
147+
})
148+
```
149+
150+
**Responsibilities:**
151+
152+
- Updates local state when parent modifies model
153+
- Keeps the component reactive to external changes
154+
155+
156+
### Sync: Local → Parent
157+
158+
```js
159+
watch(local, (nv) => emit('update:modelValue', { ...nv }), { deep: true })
160+
```
161+
162+
**Responsibilities:**
163+
164+
- Emits partial updates to parent
165+
- Keeps external state updated in real-time
166+
167+
168+
---
169+
170+
## 3. Editing State
171+
172+
```js
173+
const isEditing = ref(false)
174+
const isSaving = ref(false)
175+
```
176+
177+
**Responsibilities:**
178+
179+
- isEditing toggles between edit + read view
180+
- isSaving shows busy state to UX components
181+
182+
183+
### Start Editing
184+
185+
```js
186+
const startEditing = () => {
187+
isEditing.value = true
188+
}
189+
```
190+
191+
### Cancel Editing
192+
193+
```js
194+
const cancelEditing = () => {
195+
isEditing.value = false
196+
}
197+
```
198+
199+
Both are consumed by `<UranusInlineEditLabel>` and the action bar.
200+
201+
202+
---
203+
204+
## 4. Save Logic
205+
206+
```js
207+
async function save() {
208+
if (!props.modelValue?.id) return console.error('No event ID available')
209+
210+
isSaving.value = true
211+
try {
212+
await apiFetch(`/api/admin/event/${props.modelValue.id}/header`, {
213+
method: 'PUT',
214+
body: JSON.stringify({
215+
prop_a: local.prop_a.trim(),
216+
prop_b: (local.prop_b ?? '').trim() || null,
217+
}),
218+
})
219+
isEditing.value = false
220+
emit('updated')
221+
} catch (err) {
222+
console.error('Failed to update header', err)
223+
} finally {
224+
isSaving.value = false
225+
}
226+
}
227+
```
228+
229+
**Responsibilities:**
230+
231+
- Validates existence of event ID
232+
- Sends a PUT request with the properties
233+
- Updates external state via emit('updated')
234+
- Closes edit mode
235+
- Prevents double submits via isSaving
236+
237+
238+
---
239+
240+
## 5. Validation Logic
241+
242+
```js
243+
const propAError = computed(() => {
244+
if (props.titleError) return props.propAError
245+
246+
if (!local.prop_a || local.prop_a.trim() === "")
247+
return t('empty_input_field_message')
248+
249+
return ""
250+
})
251+
```
252+
253+
**Responsibilities:**
254+
255+
- Combines internal + external validation
256+
- Ensures empty titles cannot be saved
257+
- Supplies error text to `<UranusTextInput>`
258+
259+
260+
---
261+
262+
## 6. Styling
263+
264+
```css
265+
.basics label { display:block; margin-bottom: .5rem; }
266+
.actions { margin-top: .5rem; }
267+
```
268+
269+
**Responsibilities:**
270+
271+
- Minor layout adjustments for readability
272+

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ nav:
106106
- Dashboard: frontend/dashboard.md
107107
- Import: frontend/import.md
108108
- Export: frontend/export.md
109+
- Vue3 Implementation:
110+
- frontend/implementation/index.md
109111
- Integration:
110112
- integration/index.md
111113
- Use of Standards:

0 commit comments

Comments
 (0)