Skip to content

Commit 01d3ed4

Browse files
authored
fix(app): preserve text formatting in view dialogs
* fix: format issue (eslint) * fix: set pre-wrap as default * fix: eslint * chore: add changeset for text formatting fix
1 parent 1df9778 commit 01d3ed4

9 files changed

Lines changed: 65 additions & 46 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@dm-hero/app": patch
3+
---
4+
5+
Fix text formatting (newlines) being lost in view/preview dialogs

packages/app/app/components/factions/FactionViewDialog.vue

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
<h3 class="text-subtitle-1 font-weight-bold mb-2">
9898
{{ $t('factions.description') }}
9999
</h3>
100-
<p class="text-body-2">{{ faction.description }}</p>
100+
<p class="text-body-2" style="white-space: pre-wrap">{{ faction.description }}</p>
101101
</div>
102102

103103
<!-- Metadata Grid -->
@@ -123,7 +123,7 @@
123123
<div class="text-caption text-medium-emphasis">
124124
{{ $t('factions.goals') }}
125125
</div>
126-
<div class="font-weight-medium">{{ faction.metadata.goals }}</div>
126+
<div class="font-weight-medium" style="white-space: pre-wrap">{{ faction.metadata.goals }}</div>
127127
</div>
128128
</div>
129129
</v-card>
@@ -136,7 +136,7 @@
136136
<div class="text-caption text-medium-emphasis">
137137
{{ $t('factions.notes') }}
138138
</div>
139-
<div class="font-weight-medium">{{ faction.metadata.notes }}</div>
139+
<div class="font-weight-medium" style="white-space: pre-wrap">{{ faction.metadata.notes }}</div>
140140
</div>
141141
</div>
142142
</v-card>
@@ -269,13 +269,13 @@ const props = defineProps<Props>()
269269
270270
const emit = defineEmits<{
271271
'update:modelValue': [value: boolean]
272-
edit: [faction: Faction]
272+
'edit': [faction: Faction]
273273
'preview-image': [imageUrl: string, title: string]
274274
}>()
275275
276276
const internalShow = computed({
277277
get: () => props.modelValue,
278-
set: (value) => emit('update:modelValue', value),
278+
set: value => emit('update:modelValue', value),
279279
})
280280
281281
const activeTab = ref('overview')
@@ -287,19 +287,19 @@ const counts = computed(() => (props.faction ? getCounts(props.faction.id) || pr
287287
288288
// Data refs
289289
const members = ref<
290-
Array<{ id: number; name: string; description: string | null; image_url: string | null }>
290+
Array<{ id: number, name: string, description: string | null, image_url: string | null }>
291291
>([])
292292
const items = ref<
293-
Array<{ id: number; name: string; description: string | null; image_url: string | null }>
293+
Array<{ id: number, name: string, description: string | null, image_url: string | null }>
294294
>([])
295295
const locations = ref<
296-
Array<{ id: number; name: string; description: string | null; image_url: string | null }>
296+
Array<{ id: number, name: string, description: string | null, image_url: string | null }>
297297
>([])
298298
const loreEntries = ref<
299-
Array<{ id: number; name: string; description: string | null; image_url: string | null }>
299+
Array<{ id: number, name: string, description: string | null, image_url: string | null }>
300300
>([])
301301
const players = ref<
302-
Array<{ id: number; name: string; description: string | null; image_url: string | null }>
302+
Array<{ id: number, name: string, description: string | null, image_url: string | null }>
303303
>([])
304304
const documents = ref<Document[]>([])
305305
const images = ref<Image[]>([])
@@ -311,8 +311,8 @@ watch(
311311
if (isVisible && newFactionId) {
312312
loading.value = true
313313
try {
314-
const [countsData, membersData, itemsData, locationsData, loreData, playersData, documentsData, imagesData] =
315-
await Promise.all([
314+
const [countsData, membersData, itemsData, locationsData, loreData, playersData, documentsData, imagesData]
315+
= await Promise.all([
316316
$fetch<FactionCounts>(`/api/factions/${newFactionId}/counts`),
317317
$fetch<typeof members.value>(`/api/entities/${newFactionId}/related/npcs`).catch(() => []),
318318
$fetch<typeof items.value>(`/api/entities/${newFactionId}/related/items`).catch(() => []),
@@ -338,9 +338,11 @@ watch(
338338
players.value = playersData
339339
documents.value = documentsData
340340
images.value = imagesData
341-
} catch (error) {
341+
}
342+
catch (error) {
342343
console.error('Failed to load faction data:', error)
343-
} finally {
344+
}
345+
finally {
344346
loading.value = false
345347
}
346348
}

packages/app/app/components/items/ItemViewDialog.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
<h3 class="text-h6 mb-2">
9494
{{ $t('items.description') }}
9595
</h3>
96-
<p class="text-body-1">
96+
<p class="text-body-1" style="white-space: pre-wrap">
9797
{{ item.description }}
9898
</p>
9999
</div>

packages/app/app/components/locations/LocationViewDialog.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
<h3 class="text-h6 mb-2">
8080
{{ $t('locations.description') }}
8181
</h3>
82-
<p class="text-body-1">
82+
<p class="text-body-1" style="white-space: pre-wrap">
8383
{{ location.description }}
8484
</p>
8585
</div>
@@ -114,7 +114,7 @@
114114
<v-icon class="mr-3 mt-1">mdi-note-text</v-icon>
115115
<div>
116116
<div class="text-caption text-medium-emphasis">{{ $t('locations.notes') }}</div>
117-
<div class="font-weight-medium">{{ location.metadata.notes }}</div>
117+
<div class="font-weight-medium" style="white-space: pre-wrap">{{ location.metadata.notes }}</div>
118118
</div>
119119
</div>
120120
</v-card>

packages/app/app/components/lore/LoreViewDialog.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
<div class="text-caption text-medium-emphasis mb-2">
9191
{{ $t('lore.description') }}
9292
</div>
93-
<div class="text-body-1">
93+
<div class="text-body-1" style="white-space: pre-wrap">
9494
{{ lore.description }}
9595
</div>
9696
</v-card-text>

packages/app/app/components/npcs/NpcViewDialog.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
<!-- Description -->
100100
<div v-if="npc.description" class="mb-6">
101101
<h3 class="text-subtitle-1 font-weight-bold mb-2">{{ $t('npcs.description') }}</h3>
102-
<p class="text-body-2">{{ npc.description }}</p>
102+
<p class="text-body-2" style="white-space: pre-wrap">{{ npc.description }}</p>
103103
</div>
104104

105105
<!-- Metadata Grid -->

packages/app/app/components/players/PlayerViewDialog.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
<!-- Description -->
9494
<div v-if="player.description" class="mb-6">
9595
<h3 class="text-subtitle-1 font-weight-bold mb-2">{{ $t('players.description') }}</h3>
96-
<p class="text-body-2">{{ player.description }}</p>
96+
<p class="text-body-2" style="white-space: pre-wrap">{{ player.description }}</p>
9797
</div>
9898

9999
<!-- Contact Info -->

packages/app/app/components/shared/EntityPreviewDialog.vue

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
class="mb-4 rounded"
2525
cover
2626
/>
27-
<div v-if="entity.description" class="text-body-1 mb-4">
27+
<div v-if="entity.description" class="text-body-1 mb-4" style="white-space: pre-wrap">
2828
{{ entity.description }}
2929
</div>
3030
<v-divider class="my-4" />
@@ -41,7 +41,7 @@
4141
</div>
4242
<div v-if="entity.notes" class="mt-4">
4343
<strong>{{ $t('common.notes') }}:</strong>
44-
<div class="text-body-2 mt-2">{{ entity.notes }}</div>
44+
<div class="text-body-2 mt-2" style="white-space: pre-wrap">{{ entity.notes }}</div>
4545
</div>
4646
</template>
4747

@@ -55,7 +55,7 @@
5555
class="mb-4 rounded"
5656
cover
5757
/>
58-
<div v-if="entity.description" class="text-body-1 mb-4">
58+
<div v-if="entity.description" class="text-body-1 mb-4" style="white-space: pre-wrap">
5959
{{ entity.description }}
6060
</div>
6161
<v-divider class="my-4" />
@@ -69,7 +69,7 @@
6969
</div>
7070
<div v-if="entity.notes" class="mt-4">
7171
<strong>{{ $t('common.notes') }}:</strong>
72-
<div class="text-body-2 mt-2">{{ entity.notes }}</div>
72+
<div class="text-body-2 mt-2" style="white-space: pre-wrap">{{ entity.notes }}</div>
7373
</div>
7474
</template>
7575

@@ -93,7 +93,7 @@
9393
{{ $t(`items.rarities.${entity.rarity}`) }}
9494
</v-chip>
9595
</div>
96-
<div v-if="entity.description" class="text-body-1 mb-4">
96+
<div v-if="entity.description" class="text-body-1 mb-4" style="white-space: pre-wrap">
9797
{{ entity.description }}
9898
</div>
9999
<v-divider class="my-4" />
@@ -109,7 +109,7 @@
109109
</div>
110110
<div v-if="entity.notes" class="mt-4">
111111
<strong>{{ $t('common.notes') }}:</strong>
112-
<div class="text-body-2 mt-2">{{ entity.notes }}</div>
112+
<div class="text-body-2 mt-2" style="white-space: pre-wrap">{{ entity.notes }}</div>
113113
</div>
114114
</template>
115115

@@ -123,7 +123,7 @@
123123
class="mb-4 rounded"
124124
cover
125125
/>
126-
<div v-if="entity.description" class="text-body-1 mb-4">
126+
<div v-if="entity.description" class="text-body-1 mb-4" style="white-space: pre-wrap">
127127
{{ entity.description }}
128128
</div>
129129
<v-divider class="my-4" />
@@ -137,11 +137,11 @@
137137
</div>
138138
<div v-if="entity.goals" class="mt-4">
139139
<strong>{{ $t('factions.goals') }}:</strong>
140-
<div class="text-body-2 mt-2">{{ entity.goals }}</div>
140+
<div class="text-body-2 mt-2" style="white-space: pre-wrap">{{ entity.goals }}</div>
141141
</div>
142142
<div v-if="entity.notes" class="mt-4">
143143
<strong>{{ $t('common.notes') }}:</strong>
144-
<div class="text-body-2 mt-2">{{ entity.notes }}</div>
144+
<div class="text-body-2 mt-2" style="white-space: pre-wrap">{{ entity.notes }}</div>
145145
</div>
146146
</template>
147147

@@ -155,7 +155,7 @@
155155
class="mb-4 rounded"
156156
cover
157157
/>
158-
<div v-if="entity.description" class="text-body-1 mb-4">
158+
<div v-if="entity.description" class="text-body-1 mb-4" style="white-space: pre-wrap">
159159
{{ entity.description }}
160160
</div>
161161
<v-divider class="my-4" />
@@ -170,7 +170,7 @@
170170
</div>
171171
<div v-if="entity.notes" class="mt-4">
172172
<strong>{{ $t('common.notes') }}:</strong>
173-
<div class="text-body-2 mt-2">{{ entity.notes }}</div>
173+
<div class="text-body-2 mt-2" style="white-space: pre-wrap">{{ entity.notes }}</div>
174174
</div>
175175
</template>
176176

@@ -184,7 +184,7 @@
184184
class="mb-4 rounded"
185185
cover
186186
/>
187-
<div v-if="entity.description" class="text-body-1 mb-4">
187+
<div v-if="entity.description" class="text-body-1 mb-4" style="white-space: pre-wrap">
188188
{{ entity.description }}
189189
</div>
190190
<v-divider class="my-4" />
@@ -201,7 +201,7 @@
201201
</div>
202202
<div v-if="entity.notes" class="mt-4">
203203
<strong>{{ $t('common.notes') }}:</strong>
204-
<div class="text-body-2 mt-2">{{ entity.notes }}</div>
204+
<div class="text-body-2 mt-2" style="white-space: pre-wrap">{{ entity.notes }}</div>
205205
</div>
206206
</template>
207207
</v-card-text>

packages/app/electron/main.js

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import pkg from 'electron-updater'
33
import path from 'path'
44
import { existsSync, mkdirSync, copyFileSync, writeFileSync, appendFileSync } from 'fs'
55
import { fileURLToPath } from 'url'
6+
67
const { autoUpdater } = pkg
78

89
const __filename = fileURLToPath(import.meta.url)
@@ -179,10 +180,11 @@ async function waitForServer(url, timeout = 30000) {
179180
if (response.ok || response.status === 404) {
180181
return true
181182
}
182-
} catch {
183+
}
184+
catch {
183185
// Server not ready yet
184186
}
185-
await new Promise((resolve) => setTimeout(resolve, 500))
187+
await new Promise(resolve => setTimeout(resolve, 500))
186188
}
187189

188190
throw new Error(`Server did not start within ${timeout}ms`)
@@ -277,7 +279,8 @@ function createWindow() {
277279
if (isWindows) {
278280
windowOptions.titleBarStyle = 'hidden'
279281
windowOptions.titleBarOverlay = currentTheme.titleBarOverlay
280-
} else {
282+
}
283+
else {
281284
// Linux/macOS: Hide menu bar for cleaner look
282285
windowOptions.autoHideMenuBar = true
283286
// Set window icon (Linux needs this explicitly, Windows/macOS use app bundle icon)
@@ -344,7 +347,8 @@ ipcMain.handle('export-database', async () => {
344347
try {
345348
copyFileSync(paths.databasePath, result.filePath)
346349
return { success: true, filePath: result.filePath }
347-
} catch (error) {
350+
}
351+
catch (error) {
348352
return { success: false, error: error.message }
349353
}
350354
})
@@ -361,7 +365,8 @@ ipcMain.handle('open-uploads-folder', async () => {
361365
try {
362366
await shell.openPath(paths.uploadPath)
363367
return { success: true }
364-
} catch (error) {
368+
}
369+
catch (error) {
365370
return { success: false, error: error.message }
366371
}
367372
})
@@ -378,7 +383,8 @@ ipcMain.handle('open-logs-folder', async () => {
378383
try {
379384
await shell.openPath(paths.logsPath)
380385
return { success: true }
381-
} catch (error) {
386+
}
387+
catch (error) {
382388
return { success: false, error: error.message }
383389
}
384390
})
@@ -388,7 +394,8 @@ ipcMain.handle('open-external-url', async (event, url) => {
388394
try {
389395
await shell.openExternal(url)
390396
return { success: true }
391-
} catch (error) {
397+
}
398+
catch (error) {
392399
return { success: false, error: error.message }
393400
}
394401
})
@@ -426,7 +433,8 @@ ipcMain.handle('check-for-updates', async () => {
426433
}
427434
}
428435
return { updateAvailable: false }
429-
} catch (error) {
436+
}
437+
catch (error) {
430438
console.error('[AutoUpdater] Check failed:', error.message)
431439
return { updateAvailable: false, error: error.message }
432440
}
@@ -441,7 +449,7 @@ ipcMain.handle('download-update', async () => {
441449
// Simulate progress events
442450
const simulateProgress = async () => {
443451
for (let percent = 0; percent <= 100; percent += 10) {
444-
await new Promise((resolve) => setTimeout(resolve, 300))
452+
await new Promise(resolve => setTimeout(resolve, 300))
445453
if (mainWindow) {
446454
mainWindow.webContents.send('update-download-progress', {
447455
percent,
@@ -464,7 +472,8 @@ ipcMain.handle('download-update', async () => {
464472
try {
465473
await autoUpdater.downloadUpdate()
466474
return { started: true }
467-
} catch (error) {
475+
}
476+
catch (error) {
468477
console.error('[AutoUpdater] Download failed:', error.message)
469478
return { started: false, error: error.message }
470479
}
@@ -558,7 +567,8 @@ ipcMain.handle('save-file-dialog', async (event, options) => {
558567
const buffer = Buffer.from(fileData)
559568
writeFileSync(result.filePath, buffer)
560569
return { success: true, filePath: result.filePath }
561-
} catch (error) {
570+
}
571+
catch (error) {
562572
return { success: false, error: error.message }
563573
}
564574
})
@@ -582,7 +592,8 @@ function logToFile(message) {
582592
const logLine = `[${timestamp}] [FATAL] [Electron Main] ${message}\n`
583593

584594
appendFileSync(logFile, logLine, 'utf-8')
585-
} catch (err) {
595+
}
596+
catch (err) {
586597
console.error('[Electron] Failed to write to log file:', err)
587598
}
588599
}
@@ -604,7 +615,8 @@ app.whenReady().then(async () => {
604615
try {
605616
await startServer()
606617
createWindow()
607-
} catch (error) {
618+
}
619+
catch (error) {
608620
console.error('[Electron] Failed to start:', error)
609621
app.quit()
610622
}

0 commit comments

Comments
 (0)