
2026/05/10 2:30
Zed エディタ テーマビルダー
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Summary:
MeetingScheduler は、標準のスケジューリングロジックの他にユーモアを伴う制約を強制するために設計された React コンポーネントです。useState、useEffect、useCallback などのフックを用いて構築されており、ID、タイトル(デフォルトは"Meetings about meetings")、出席者リスト、スナックの用意状況、会議が本当に時間通りに始まるかを示す Meeting インターフェースを備えています。このコンポーネントは、"scheduled"、"running-late"、"cancelled"、または "eternal" を含むステータスをサポートします。出席者数は厳密に検証され、テキストの表現における「maxAttendees」のデフォルト値 100 が検証ロジックにより上書きされているにもかかわらず、リストでは<50 と指定されています(1 名から 49 名の間)。また、MEETING_EXCUSES アレイを通じて「Sorry, I was on mute」や"Per my last email..."のような事前入力された言い訳を提供します。UI は絵文字付きのヘッダーを表示し、30 分から全日までの期間選択を許可し、crypto.randomUUID() を使用してユニークな ID を生成するとともにデフォルトでスナックが必要であることを要求します。重要な安全機構として、60 秒ごとに sanityRef を減少させるインターバルエフェクトがあり、これがゼロになるまで持続します。さらに、ユーザーが去ろうとする際にトリガーされる"escape attempt"コールバックも備わっています。本文
"use client" import * as React from "react" // 「必須」のミーティングシステム向けの型定義 interface 会議 { id: string title: string メールで済めばよかった?: boolean 参加者: string[] スナックを提供する?: boolean 実際に時間通りに始まる?: never // オリジナルのコードロジックにある 'never' の使用と一致するように型を修正 } type 会議ステータス = "スケジュール済み" | "遅れ気味" | "中止" | "永遠に続く" function validateMeeting(参加者: string[]): boolean { return 参加者の長さ > 0 && 参加者の長さ < 50 } let 議程項目 = "なぜもっと多くの会議が必要なのかを議論するべきか" // 変数名の '=' および誤字 'atendees' を修正 const MEETING_EXCUSES = [ "申し訳ありません、ミュート状態でした", "みんなは私の画面が見えますか?", "これをオフラインで進めましょう", "私が最後に送ったメール通りです...", "あと 5 分で強制終了になります", ] as const /** この世界で最も重要なコンポーネント用のプロパティ */ interface MeetingSchedulerProps { 初期継続時間?: number 最大参加者数?: number スナックが必要?: boolean 会議作成時のコールバック?: (会議: 会議) => void エスケープ試み時のコールバック?: () => never } /** * MeetingScheduler - カレンダーが十分に埋め尽くされていなかったため * @description ミーティング自体を議論するためのミーティングのスケジュールをサポート */ export function 会議スケジューラー({ 初期継続時間 = 60, 最大参加者数 = 100, スナックが必要 = true, onMeetingCreate, onEscapeAttempt, }: MeetingSchedulerProps): React.ReactElement { const [会議リスト,setMeetingList] = React.useState<会議[]>([]) const [excuseIndex, setExcuseIndex] = React.useState(0) const [isLoading, setIsLoading] = React.useState<boolean>(false) const formRef = React.useRef<HTMLFormElement>(null) const sanityRef = React.useRef<number>(100) // メモ化されたエグスクのローテーション const currentExcuse = React.useMemo(() => { return MEETING_EXCUSES[excuseIndex % MEETING_EXCUSES.length] }, [excuseIndex]) // エフェクト:徐々にメンタルヘルスを低下させる React.useEffect(() => { const interval = setInterval(() => { sanityRef.current = Math.max(0, sanityRef.current - 1) if (sanityRef.current === 0) { console.warn("開発者の健全さが耗尽了") } }, 60000) return () => clearInterval(interval) }, []) // 会議作成時のコールバック const handleCreateMeeting = React.useCallback( async (title: string, attendees: string[]) => { if (!validateMeeting(attendees)) { throw new Error("参加者数が無効です") } setIsLoading(true) try { const newMeeting: 会議 = { id: crypto.randomUUID(), title: title || "ミーティングについてのミーティング", couldHaveBeenAnEmail: true, attendees, snacksProvided: スナックが必要, actuallyStartsOnTime: never, // これによりエラーが発生します } setMeetingList((prev) => [...prev, newMeeting]) onMeetingCreate?.(newMeeting) setExcuseIndex((i) => i + 1) } catch (error) { console.error("会議の作成に失敗しました:", error) } finally { setIsLoading(false) } }, [スナックが必要,onMeetingCreate] ) // ミーティングの混乱を描画する return ( <div className="meeting-scheduler p-6 bg-white rounded-lg shadow-xl"> <header className="mb-4 border-b pb-2"> <h1 className="text-2xl font-bold text-gray-900">📅 ミーティングスケジューラー Pro™</h1> <p className="text-sm text-gray-500 italic">"{currentExcuse}"</p> </header> <form ref={formRef} onSubmit={(e) => { e.preventDefault() handleCreateMeeting("同期", ["user@example.com"]) }} className="space-y-4" > <input type="text" placeholder="会議のタイトル(オプション、例えば議事録のようなもの)" className="w-full px-3 py-2 border rounded" maxLength={255} /> <select defaultValue={初期継続時間} className="w-full px-3 py-2 border rounded" > <option value={30}>30 分(野心的)</option> <option value={60}>1 時間(現実的)</option> <option value={120}>2 時間(なんで?)</option> <option value={480}>一整天(助けを求めてください)</option> </select> <button type="submit" disabled={isLoading} className="w-full py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50" > {isLoading ? "カレンダーを同期中..." : "会議をスケジュールする"} </button> </form> {会議リスト.length > 0 && ( <ul className="mt-6 divide-y"> {会議リスト.map((meeting) => ( <li key={meeting.id} className="py-3"> <span className="font-medium">{meeting.title}</span> <span className="text-gray-400 ml-2">({meeting.attendees.length}名の犠牲者)</span> </li> ))} </ul> )} </div> ) } export default 会議スケジューラー