Component split, UI enhancement and Light, airy, generous whitespace. Sharp editorial typography using DM Sans + Playfair Display. Thin borders, subtle vote progress bars, clean status indicators. Nothing heavy.
This commit is contained in:
79
src/utils/store.js
Normal file
79
src/utils/store.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import * as Y from 'yjs';
|
||||
import { WebrtcProvider } from 'y-webrtc';
|
||||
|
||||
// --- Peer ID (stable across reloads) ---
|
||||
|
||||
function getOrCreatePeerId() {
|
||||
let id = localStorage.getItem('peer-id');
|
||||
if (!id) {
|
||||
id = crypto.randomUUID();
|
||||
localStorage.setItem('peer-id', id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
// --- Room name from URL ---
|
||||
|
||||
function getRoomName() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return params.get('room') || 'default-poll';
|
||||
}
|
||||
|
||||
// --- Yjs setup ---
|
||||
|
||||
export const peerId = getOrCreatePeerId();
|
||||
export const roomName = getRoomName();
|
||||
|
||||
export const ydoc = new Y.Doc();
|
||||
export const provider = new WebrtcProvider(roomName, ydoc);
|
||||
export const yOptions = ydoc.getMap('poll-options');
|
||||
export const yTitle = ydoc.getText('poll-title');
|
||||
|
||||
// --- Data operations ---
|
||||
|
||||
export function addOption(name) {
|
||||
const id = crypto.randomUUID();
|
||||
const optionMap = new Y.Map();
|
||||
optionMap.set('name', name);
|
||||
optionMap.set('votes', new Y.Map());
|
||||
yOptions.set(id, optionMap);
|
||||
}
|
||||
|
||||
export function toggleVote(optionId) {
|
||||
const optionMap = yOptions.get(optionId);
|
||||
if (!optionMap) return;
|
||||
const votes = optionMap.get('votes');
|
||||
if (votes.has(peerId)) {
|
||||
votes.delete(peerId);
|
||||
} else {
|
||||
votes.set(peerId, true);
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteOption(optionId) {
|
||||
yOptions.delete(optionId);
|
||||
}
|
||||
|
||||
// --- Derived read helpers ---
|
||||
|
||||
export function getEntries() {
|
||||
const entries = [];
|
||||
yOptions.forEach((optionMap, id) => {
|
||||
entries.push({
|
||||
id,
|
||||
name: optionMap.get('name'),
|
||||
votes: optionMap.get('votes').size,
|
||||
voted: optionMap.get('votes').has(peerId),
|
||||
});
|
||||
});
|
||||
entries.sort((a, b) => b.votes - a.votes || a.name.localeCompare(b.name));
|
||||
return entries;
|
||||
}
|
||||
|
||||
export function getTotalVotes() {
|
||||
let total = 0;
|
||||
yOptions.forEach((optionMap) => {
|
||||
total += optionMap.get('votes').size;
|
||||
});
|
||||
return total;
|
||||
}
|
||||
Reference in New Issue
Block a user