昨天我們替微光採集瓶加上了首頁與採集主畫面的轉場動態,在畫面呈現和體驗更完整。
但在每天放入微光的過程中,我發現了一個體驗上的問題:這些預設的色彩,背後到底代表了什麼心情?
原本系統裡的顏色其實沒有綁定明確的情緒,大家可能只是憑直覺選個順眼的顏色放進去。但如果沒有定義,過了一兩週回頭看,很可能早就忘記當初選擇這個顏色時是帶著什麼心情;更重要的是,到了月底回顧「月度微光色卡」時,這些顏色如果有了自己的定義,就能讓原本單純的比例數據多一層情緒上的意義。
因此今天(Day 26),我們要來替每道微光賦予名字,並且讓使用者隨時能修改。
在規劃這個功能時,我原本想過要不要在第一次進入時自動彈出視窗,引導大家先把四個顏色命名好。
但後來想想,這樣其實很不合理:大家一進來根本還沒看過採集瓶長怎樣、不知道這個系統在幹嘛,這時候突然要人幫顏色取名字只會覺得莫名其妙,大概也只會隨便填填急著關掉。
最自然的流程,應該是讓使用者先進到頁面看見瓶子、知道核心互動後,等他對這些顏色產生自己的想法,再主動點擊按鈕去修改。因此我直接給定一組預設名稱(平靜、喜悅、溫柔、安心),想改的人隨時能自訂,不想改的人也能立刻開始記錄,完全不打擾當下的探索流程。
因此最後決定的做法是:
比起把原本的陣列全部打掉重練,我採用更簡單直覺的物件 Key-Value 方式,讓「色碼」直接對應「心情名稱」:
// ==========================================
// 心情名稱(色碼 → 名字)
// ==========================================
const paletteColors = ['#8db3d4', '#e6c683', '#d7a9b8', '#9bb89f']
const defaultLabels = {
'#8db3d4': '平靜',
'#e6c683': '喜悅',
'#d7a9b8': '溫柔',
'#9bb89f': '安心'
}
// 使用者改過的名字會覆蓋預設值
const labels = ref({
...defaultLabels,
...JSON.parse(localStorage.getItem('store_color_labels') || '{}')
})
// 透過 watch 深度監聽自動存檔
watch(
labels,
(val) => {
localStorage.setItem('store_color_labels', JSON.stringify(val))
},
{ deep: true }
)
// 查詢色碼對應的心情
function labelOf(color) {
if (!color) return ''
// 系統自動補上的白色光珠,就叫做留白
if (color.toLowerCase() === '#ffffff') return '留白'
return labels.value[color] || ''
}
const showLabelEditor = ref(false)
watch(..., { deep: true }) 監聽 labels 的變化,當使用者修改心情名稱時,系統就會自動將最新資料寫入 localStorage,不需要另外設置儲存按鈕。#ffffff)」在查名字時會自動回傳「留白」,讓沒寫小事的日子也擁有一種名稱。原本調色盤是手動寫死四顆按鈕,今天將他們改成 v-for 搭配 :style 動態上色:
<div class="palette">
<button
v-for="color in paletteColors"
:key="color"
class="color-dot"
:class="{ 'is-active': selectedColor === color }"
:style="{ backgroundColor: color }"
@click="selectColor(color)"
></button>
</div>
<!-- 目前選中的顏色名稱與修改入口 -->
<p class="selected-label">{{ labelOf(selectedColor) }}</p>
<button class="btn-edit-labels" @click="showLabelEditor = true">
修改心情名稱
</button>
.color-dot.blue、.gold、.pink、.green 全部都可以直接刪掉。彈窗放在 .main-content 的彈窗區塊,結構簡單,點擊旁邊空白處或完成按鈕即可關閉:
<div v-if="showLabelEditor" class="modal-backdrop" @click="showLabelEditor = false">
<div class="label-editor" @click.stop>
<h3 class="editor-title">這些顏色,對你來說是什麼心情?</h3>
<div v-for="color in paletteColors" :key="color" class="label-row">
<span class="setting-dot" :style="{ backgroundColor: color }"></span>
<input
v-model="labels[color]"
class="label-input"
type="text"
maxlength="6"
placeholder="替這個顏色取名字"
/>
</div>
<button class="btn-close" @click="showLabelEditor = false">完成</button>
</div>
</div>
自訂的心情名稱不能只停留在主畫面,最關鍵的是要帶進月度色卡與時光相簿。
在計算比例的 colorStats 裡,多補上一個 label 欄位:
return Object.entries(counts)
.map(([color, count]) => ({
color,
count,
label: labelOf(color), // 新增心情名稱
ratio: Math.round((count / total) * 100)
}))
.sort((a, b) => b.count - a.count)
在月度色卡與相簿大圖的色票列表裡,加入文字顯示:
<div v-for="(item, index) in colorStats" :key="index" class="swatch-item">
<span class="swatch-bubble" :style="{ backgroundColor: item.color }"></span>
<!-- 加上 v-if="item.label" 相容舊資料 -->
<span v-if="item.label" class="swatch-label">{{ item.label }}</span>
<span class="swatch-ratio">{{ item.ratio }}%</span>
</div>
小提醒
sealMonthlyCard存的是當下colorStats.value的快照,所以封存時的心情名字會跟著一起被存進時光相簿。就算使用者以後改了名字,已經珍藏的歷史色卡依然會保留當初的心情。
加上 v-if="item.label" 是為了相容舊資料:今天之前存的色卡雖然顏色沒有定義名字,但畫面依然能正常顯示,排版完全不會跑掉。
主畫面選色器即時提示
切換不同顏色時,下方會呈現該色彩對應的心情名稱,點擊「修改心情名稱」即可隨時叫出彈窗。
自訂心情編輯彈窗
四個微光色塊一字排開,輸入框上限 6 個字,修改完點擊「完成」即可關閉彈窗,名稱也會自動儲存。
點擊影片:選中顏色顯示心情文字並進行修改
月度色卡上的心情標記
色票除了顯示顏色與佔比,現在每一行都清楚列出了屬於自己的心情定義。

明天(Day 27)我們要來做一件重要的事情——移除手動點擊的「查看本月色卡」按鈕。
原本主畫面上保留了「查看本月色卡」按鈕,方便開發與測試期間隨時檢視成果。明天我們會將它移除,讓月度色卡回歸月底專屬的回顧儀式,同時重新整理頁面佈局,讓整個採集流程更加完整。我們明天見!