skillok meeting
996ce529a8d705e470aea24a7b7fb9a19578f1e4
Перейти к файлу
Код
meeting srcstate.ts
anc Интерфейс: список встреч слева, заметка справа - Боковая панель: «Записать», «Добавить аудио» (и перетаскивание файла), «Новая заметка», список встреч. - Экран встречи: название правится на месте, шаги «Расшифровать» и команды ИИ с ходом работы, панель записи с уровнями и текстом предупреждения для чата Zoom. - Заметка: «Текст» / «Правка», автосохранение, «Копировать всё», «Как текст», копирование раздела, живые галочки задач. - Сообщения внизу экрана вместо ошибок в тексте страницы. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 996ce52 30 сентября 2026 г.
state.ts
// Общее состояние интерфейса: идёт ли запись и сообщения об ошибках.
// Боковая панель и экран заметки подписываются на изменения.

import { api, errorText, type RecordingView } from "./api";

type Listener = () => void;
const listeners = new Set<Listener>();

export const state = {
  recording: null as RecordingView | null,
};

export function onChange(cb: Listener): () => void {
  listeners.add(cb);
  return () => listeners.delete(cb);
}

export function changed(): void {
  listeners.forEach((cb) => cb());
}

export async function refreshRecording(): Promise<void> {
  state.recording = await api.recorderStatus();
  changed();
}

/** Сообщение внизу экрана: ошибка или «Скопировано». Исчезает само. */
export function toast(message: unknown, kind: "error" | "ok" = "error"): void {
  const el = document.getElementById("toast");
  if (!el) return;
  el.textContent = kind === "error" ? errorText(message) : String(message);
  el.className = `toast is-${kind}`;
  el.hidden = false;
  window.clearTimeout(Number(el.dataset.timer));
  el.dataset.timer = String(window.setTimeout(() => (el.hidden = true), kind === "error" ? 8000 : 2000));
}

export async function copy(text: string, what = "Скопировано"): Promise<void> {
  try {
    await navigator.clipboard.writeText(text);
    toast(what, "ok");
  } catch (e) {
    toast(e);
  }
}