diff --git a/game.html b/game.html
index 8bd1300..8c8b9ff 100644
--- a/game.html
+++ b/game.html
@@ -626,6 +626,30 @@
}
.tl-chooser-btn:hover { background: rgba(184,138,67,.12); color: var(--paper); }
+ /* Truths */
+ .truth-list { display:flex; flex-direction:column; gap:.6rem; margin-top:.8rem; }
+ .truth-item {
+ display:flex; align-items:flex-start; gap:1rem;
+ padding:.8rem 1rem; border-left:3px solid var(--brass);
+ background:rgba(184,138,67,.05);
+ font:italic 1rem/1.6 var(--serif); color:var(--paper);
+ }
+ .truth-item-text { flex:1; }
+ .project-events {
+ margin-top:.8rem; padding-top:.8rem; border-top:1px solid var(--line);
+ }
+ .project-events-label {
+ font:700 .62rem/1 var(--mono); letter-spacing:.12em; text-transform:uppercase;
+ color:var(--muted); margin-bottom:.5rem;
+ }
+ .project-events-list { display:flex; flex-direction:column; gap:.3rem; }
+ .project-event-link {
+ font:.85rem/1.4 var(--sans); color:var(--muted); text-decoration:none;
+ display:flex; align-items:baseline; gap:.5rem;
+ }
+ .project-event-link:hover { color:var(--paper); }
+ .project-event-date { font:.62rem/1 var(--mono); color:var(--muted); flex-shrink:0; }
+
/* Autocomplete dropdown */
.ac-wrap { position: relative; }
.ac-dropdown {
@@ -747,6 +771,24 @@
+
+
-
-
+
+
+
+
+
+
+
+
+
+
@@ -1427,6 +1511,8 @@
showCard: false,
// Timeline click chooser
tlChooser: { show: false, x: 0, y: 0, date: '' },
+ // Truths
+ newTruth: '',
// Autocomplete
acMode: null,
acQuery: '',
@@ -1989,6 +2075,15 @@
return result.sort((a, b) => a.term.localeCompare(b.term))
},
+ eventsForProject(projectId) {
+ return this.events().filter(e => e.project_id === projectId)
+ },
+
+ projectForEvent(item) {
+ if (!item.project_id) return null
+ return this.projects().find(p => p.id === item.project_id) || null
+ },
+
castUsages(name) {
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const re = new RegExp(`@"${escaped}"`, 'i')
@@ -2113,7 +2208,7 @@
openAddItem(type) {
const env = this.randomEnv(null)
- this.activeForm = { type, title: '', description: '', mood: '', date: '', end_date: '', status: 'active', discipline: '', env, env_layout: env ? this.randomEnvLayout() : 'after' }
+ this.activeForm = { type, title: '', description: '', mood: '', date: '', end_date: '', status: 'active', discipline: '', env, env_layout: env ? this.randomEnvLayout() : 'after', project_id: '' }
this.editingId = null
this.formError = null
this.modalType = 'item'
@@ -2121,7 +2216,7 @@
},
openEditItem(item) {
- this.activeForm = Object.assign({ env: '', env_layout: 'after' }, item)
+ this.activeForm = Object.assign({ env: '', env_layout: 'after', project_id: '' }, item)
this.editingId = item.id
this.formError = null
this.modalType = 'item'
@@ -2138,7 +2233,8 @@
},
openEditGame() {
- this.activeForm = Object.assign({ deck_id: '' }, this.game)
+ this.activeForm = Object.assign({ deck_id: '', truths: [] }, this.game)
+ this.activeForm.truths = [...(this.game.truths || [])]
this.formError = null
this.modalType = 'editGame'
this.showModal = true
diff --git a/server.js b/server.js
index e910128..0491851 100644
--- a/server.js
+++ b/server.js
@@ -90,6 +90,7 @@ function publicGame(g) {
start_title: g.start_title || '', start_description: g.start_description || '', start_mood: g.start_mood || '',
end_title: g.end_title || '', end_description: g.end_description || '', end_mood: g.end_mood || '',
deck_id: g.deck_id || '',
+ truths: g.truths || [],
created_at: g.created_at
}
}
@@ -183,6 +184,7 @@ app.put('/api/games/:slug', requirePassword, (req, res) => {
game.end_description = end_description || ''
game.end_mood = end_mood || ''
game.deck_id = req.body.deck_id || ''
+ game.truths = req.body.truths || []
saveDB(req.db); broadcast(req.params.slug)
res.json(publicGame(game))
})
@@ -209,7 +211,7 @@ app.get('/api/games/:slug/items', (req, res) => {
})
app.post('/api/games/:slug/items', requirePassword, (req, res) => {
- const { type, title, description, mood, date, end_date, status, discipline, env } = req.body
+ const { type, title, description, mood, date, end_date, status, discipline, env, project_id } = req.body
if (!type || !title || !date) return res.status(400).json({ error: 'type, title, date required' })
if (!['event', 'project', 'person'].includes(type)) {
return res.status(400).json({ error: 'type must be event, project, or person' })
@@ -218,7 +220,8 @@ app.post('/api/games/:slug/items', requirePassword, (req, res) => {
id: newId(), type, title, description: description || '',
mood: mood || null, date, end_date: end_date || null,
status: status || null, discipline: discipline || null,
- env: env || null, env_layout: req.body.env_layout || null, created_at: now()
+ env: env || null, env_layout: req.body.env_layout || null,
+ project_id: project_id || null, created_at: now()
}
req.game.items = req.game.items || []
req.game.items.push(item)
@@ -233,7 +236,7 @@ app.put('/api/games/:slug/items/:id', requirePassword, (req, res) => {
const { title, description, mood, date, end_date, status, discipline } = req.body
if (!title || !date) return res.status(400).json({ error: 'title, date required' })
const { env, env_layout } = req.body
- items[idx] = { ...items[idx], title, description: description || '', mood: mood || null, date, end_date: end_date || null, status: status || null, discipline: discipline || null, env: env || null, env_layout: env_layout || null }
+ items[idx] = { ...items[idx], title, description: description || '', mood: mood || null, date, end_date: end_date || null, status: status || null, discipline: discipline || null, env: env || null, env_layout: env_layout || null, project_id: req.body.project_id || null }
saveDB(req.db); broadcast(req.params.slug)
res.json(items[idx])
})