* revert changes

This commit is contained in:
2026-05-10 15:11:24 +02:00
parent 78d872c83e
commit 1ef970fef3
10 changed files with 183 additions and 474 deletions

View File

@@ -1,6 +1,5 @@
import * as Y from "yjs";
import { getDeadline } from "../state";
import { enforceAppendOnly } from "../yDocUtil";
const DEADLINE_DURATION_MS = 2 * 60 * 1000; // 2 minutes
@@ -80,7 +79,7 @@ export function DeadlineTimer(
onClearDeadline();
});
deadlineMap.observe(enforceAppendOnly(deadlineMap,render));
deadlineMap.observe(() => render());
render();
return wrapper;

View File

@@ -1,20 +1,15 @@
import * as Y from "yjs";
import type { OptionRecord } from "../state";
import { PollOption } from "./PollOption";
import { enforceAppendOnly } from "../yDocUtil";
import { User } from "../state";
export function PollList(
yOptions: Y.Map<OptionRecord>,
yVotes: Y.Map<string>,
user: User | undefined,
userId: string,
isVotingClosed: () => boolean,
onVote: (optionId: string) => void,
onDelete: (optionId: string) => void,
): HTMLElement {
var currentOptions : { [x: string]: any; } | undefined = undefined
var currentVotes : { [x: string]: any; } | undefined = undefined
const wrapper = document.createElement("div");
wrapper.className = "poll-list-wrapper";
@@ -46,32 +41,25 @@ export function PollList(
votes: number;
voted: boolean;
}> = [];
if (currentOptions && currentVotes){
// Tally votes per option
const tally = new Map<string, number>();
for (const optionId of Object.values(currentVotes)) {
tally.set(optionId, (tally.get(optionId) ?? 0) + 1);
}
let myVote = null;
if (user) {
myVote = currentVotes[user.userid]
}
Object.entries(currentOptions).forEach(([id,record]) => {
console.log(`${record}: ${id}`)
entries.push({
id,
name: record.label,
votes: tally.get(id) ?? 0,
voted: myVote === id,
});
});
entries.sort((a, b) => b.votes - a.votes || a.name.localeCompare(b.name));
// Tally votes per option
const tally = new Map<string, number>();
for (const optionId of yVotes.values()) {
tally.set(optionId, (tally.get(optionId) ?? 0) + 1);
}
const myVote = yVotes.get(userId) ?? null;
yOptions.forEach((record, id) => {
entries.push({
id,
name: record.label,
votes: tally.get(id) ?? 0,
voted: myVote === id,
});
});
entries.sort((a, b) => b.votes - a.votes || a.name.localeCompare(b.name));
return entries;
}
@@ -115,6 +103,7 @@ export function PollList(
totalVotes: total,
votingClosed,
onVote,
onDelete,
});
const currentEl = list.children[i] as HTMLElement | undefined;
@@ -129,10 +118,9 @@ export function PollList(
}
});
}
yOptions.observe(enforceAppendOnly(yOptions,(update : { [x: string]: any; }) => {currentOptions = update}, render));
yVotes.observe(enforceAppendOnly(yVotes,(update : { [x: string]: any; }) => {currentVotes = update},render));
currentOptions=yOptions.toJSON()
currentVotes=yVotes.toJSON()
yOptions.observeDeep(() => render());
yVotes.observe(() => render());
render();
return wrapper;

View File

@@ -8,10 +8,11 @@ export interface PollOptionProps {
totalVotes: number;
votingClosed: boolean;
onVote: (id: string) => void;
onDelete: (id: string) => void;
}
export function PollOption(props: PollOptionProps): HTMLElement {
const { id, name, votes, voted, totalVotes, votingClosed, onVote } = props;
const { id, name, votes, voted, totalVotes, votingClosed, onVote, onDelete } = props;
const row = document.createElement("div");
row.className = `poll-option${voted ? " poll-option--voted" : ""}`;
@@ -29,11 +30,17 @@ export function PollOption(props: PollOptionProps): HTMLElement {
<button class="poll-option__vote-btn" aria-pressed="${voted}"${votingClosed ? " disabled" : ""}>
${voted ? "Voted" : "Vote"}
</button>
<button class="poll-option__delete-btn" aria-label="Remove option">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 2l10 10M12 2L2 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</button>
</div>
</div>
`;
row.querySelector(".poll-option__vote-btn")!.addEventListener("click", () => onVote(id));
row.querySelector(".poll-option__delete-btn")!.addEventListener("click", () => onDelete(id));
return row;
}

View File

@@ -1,110 +1,30 @@
import type { WebrtcProvider } from "y-webrtc";
export function StatusBar(provider: WebrtcProvider, user_provider: WebrtcProvider, onLoginLogout: (event: Event) => Promise<boolean>, onCreateUser: (event: Event) => Promise<boolean>): HTMLElement {
export function StatusBar(provider: WebrtcProvider): HTMLElement {
const el = document.createElement("div");
el.className = "status-bar";
const statusPanel=document.createElement("div");
statusPanel.className = "status-bar";
const dot = document.createElement("span");
dot.className = "status-dot connecting";
const statusText = document.createElement("span");
statusText.className = "status-text";
statusText.textContent = "Connecting";
const divider = document.createElement("span");
divider.className = "status-divider";
divider.textContent = "\u00b7";
function getProviderStatus(){
const peerText = document.createElement("span");
peerText.className = "status-peers";
const dot = document.createElement("span");
dot.className = "status-dot connecting";
const statusText = document.createElement("span");
statusText.className = "status-text";
statusText.textContent = "Connecting";
const peerText = document.createElement("span");
peerText.className = "status-peers";
return { dot: dot, statusText: statusText, peerText: peerText}
}
const providerStatusPanel=document.createElement("div");
providerStatusPanel.className = "provider-status-container";
const pollProviderText = document.createElement("span");
pollProviderText.className = "status-text";
pollProviderText.textContent = "Polls: ";
const pollProviderElements = getProviderStatus()
const pollProviderStatusPanel=document.createElement("div");
pollProviderStatusPanel.className = "status-bar";
pollProviderStatusPanel.append(pollProviderText,pollProviderElements.dot, pollProviderElements.statusText, divider, pollProviderElements.peerText);
const userProviderText = document.createElement("span");
userProviderText.className = "status-text";
userProviderText.textContent = "Users: ";
const userProviderElements = getProviderStatus()
const userProviderStatusPanel=document.createElement("div");
userProviderStatusPanel.className = "status-bar";
userProviderStatusPanel.append(userProviderText,userProviderElements.dot, userProviderElements.statusText, divider, userProviderElements.peerText);
providerStatusPanel.append(userProviderStatusPanel,pollProviderStatusPanel)
const userButtons = document.createElement("div");
userButtons.className = "status-bar";
const loginLabel = document.createElement("label");
loginLabel.setAttribute("title", "Select Key File");
const loginSpan = document.createElement("span");
loginSpan.className = "add-option-btn"
loginSpan.textContent = "Login";
const loginInput = document.createElement("input");
loginInput.type = "file"
loginInput.accept = ".pem"
loginInput.hidden = true
loginLabel.append(loginSpan,loginInput)
const logoutButton = document.createElement("button");
logoutButton.className = "add-option-btn";
logoutButton.setAttribute("aria-label", "Logout");
logoutButton.innerHTML="<span>Logout</span>"
logoutButton.style.display = "none";
const createUserButton = document.createElement("button");
createUserButton.className = "add-option-btn";
createUserButton.setAttribute("aria-label", "Create User");
createUserButton.innerHTML="<span>Create User</span>"
async function onLoginLogoutResult(event: Event, loginLogout: (event: Event) => Promise<boolean>){
if(await loginLogout(event)){
console.log('created / logged in')
loginLabel.style.display = "none";
logoutButton.style.display = "block";
createUserButton.style.display = "none";
} else {
console.log('logged out')
loginLabel.style.display = "block";
logoutButton.style.display = "none";
createUserButton.hidden = false;
createUserButton.style.display = "block";
}
}
loginLabel.addEventListener("change", (e) => onLoginLogoutResult(e,onLoginLogout));
logoutButton.addEventListener("click", (e) => onLoginLogoutResult(e,onLoginLogout));
createUserButton.addEventListener("click", (e) => onLoginLogoutResult(e,onCreateUser));
userButtons.append(loginLabel,logoutButton,createUserButton)
el.append(providerStatusPanel, divider, userButtons);
el.append(dot, statusText, divider, peerText);
// --- Connection state ---
let syncTimeout: ReturnType<typeof setTimeout> | undefined = setTimeout(() => {
pollProviderElements.statusText.textContent = "Ready";
pollProviderElements.dot.className = "status-dot ready";
statusText.textContent = "Ready";
dot.className = "status-dot ready";
}, 3000);
provider.on("synced", ({ synced }: { synced: boolean }) => {
@@ -112,37 +32,18 @@ export function StatusBar(provider: WebrtcProvider, user_provider: WebrtcProvide
clearTimeout(syncTimeout);
syncTimeout = undefined;
}
pollProviderElements.dot.className = `status-dot ${synced ? "connected" : "connecting"}`;
pollProviderElements.statusText.textContent = synced ? "Connected" : "Connecting";
});
let syncTimeout2: ReturnType<typeof setTimeout> | undefined = setTimeout(() => {
userProviderElements.statusText.textContent = "Ready";
userProviderElements.dot.className = "status-dot ready";
}, 3000);
user_provider.on("synced", ({ synced }: { synced: boolean }) => {
if (syncTimeout2) {
clearTimeout(syncTimeout2);
syncTimeout2 = undefined;
}
userProviderElements.dot.className = `status-dot ${synced ? "connected" : "connecting"}`;
userProviderElements.statusText.textContent = synced ? "Connected" : "Connecting";
dot.className = `status-dot ${synced ? "connected" : "connecting"}`;
statusText.textContent = synced ? "Connected" : "Connecting";
});
// Online/offline awareness
const handleOffline = () => {
pollProviderElements.dot.className = "status-dot connecting";
pollProviderElements.statusText.textContent = "Offline";
userProviderElements.dot.className = "status-dot connecting";
userProviderElements.statusText.textContent = "Offline";
dot.className = "status-dot connecting";
statusText.textContent = "Offline";
};
const handleOnline = () => {
pollProviderElements.dot.className = "status-dot connecting";
pollProviderElements.statusText.textContent = "Reconnecting";
userProviderElements.dot.className = "status-dot connecting";
userProviderElements.statusText.textContent = "Reconnecting";
dot.className = "status-dot connecting";
statusText.textContent = "Reconnecting";
};
window.addEventListener("offline", handleOffline);
@@ -153,18 +54,10 @@ export function StatusBar(provider: WebrtcProvider, user_provider: WebrtcProvide
function updatePeerCount() {
const total = provider.awareness.getStates().size;
const others = total - 1;
pollProviderElements.peerText.textContent =
peerText.textContent =
others === 0
? "Only you"
: `${others} other${others !== 1 ? "s" : ""}`;
const total2 = user_provider.awareness.getStates().size;
const others2 = total2 - 1;
userProviderElements.peerText.textContent =
others2 === 0
? "Only you"
: `${others2} other${others2 !== 1 ? "s" : ""}`;
}
provider.awareness.on("change", updatePeerCount);