< Summary

Information
Class: theme-chrome.tsx
Assembly: app.components
File(s): /home/runner/work/ClutterStock/ClutterStock/frontend/app/components/theme-chrome.tsx
Tag: 58_25416222083
Line coverage
0%
Covered lines: 0
Uncovered lines: 25
Coverable lines: 25
Total lines: 96
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 8
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/ClutterStock/ClutterStock/frontend/app/components/theme-chrome.tsx

#LineLine coverage
 1import { useSyncExternalStore } from "react";
 2import type { LocationResponse, RoomResponse } from "~/api/client";
 3
 04const noopSubscribe = () => () => {};
 05const getClientDate = () => new Date().toLocaleDateString();
 06const getServerDate = () => "";
 7
 08export function CDEMenuBar() {
 09  const menus = ["File", "Selected", "View", "Items", "Help"];
 010  return (
 11    <div className="cde-menubar">
 012      {menus.map(m => (
 013        <span key={m} className="cde-menubar-item">{m}</span>
 14      ))}
 15    </div>
 16  );
 17}
 18
 019export function CDEFootRow({ onNewItem }: { onNewItem: () => void }) {
 020  const slots: [string, (() => void) | null][] = [
 21    ["Items", null], ["Rooms", null], ["Stats", null],
 22    ["Add",   onNewItem],
 23    ["Print", null], ["Trash", null], ["Help", null],
 24  ];
 025  return (
 26    <div className="cde-footrow">
 027      {slots.map(([label, action], i) => (
 028        <button
 29          key={label}
 30          className={`cde-footrow-btn${i === 0 ? " cde-footrow-btn--primary" : ""}`}
 31          onClick={action ?? undefined}
 32          type="button"
 33        >
 34          {label}
 35        </button>
 36      ))}
 37    </div>
 38  );
 39}
 40
 041export function Win98MenuBar() {
 042  const menus = ["File", "Edit", "View", "Items", "Tools", "Help"];
 043  return (
 44    <div className="win98-menubar">
 045      {menus.map(m => (
 046        <span key={m} className="win98-menubar-item">
 47          <u>{m[0]}</u>{m.slice(1)}
 48        </span>
 49      ))}
 50    </div>
 51  );
 52}
 53
 054export function Win98AddressBar({ location, room }: {
 55  location?: LocationResponse | null;
 56  room?: RoomResponse | null;
 57}) {
 058  const path = room && location
 59    ? `C:\\ClutterStock\\${location.name}\\${room.name}`
 60    : location
 61    ? `C:\\ClutterStock\\${location.name}`
 62    : `C:\\ClutterStock\\All Items`;
 063  return (
 64    <div className="win98-addressbar">
 65      <span className="win98-addressbar-label">Address</span>
 66      <div className="win98-addressbar-field">
 67        <span>📁</span>
 68        <span>{path}</span>
 69      </div>
 70      <button className="win98-addressbar-go">Go</button>
 71    </div>
 72  );
 73}
 74
 075export function Win98StatusBar({ count, location, room }: {
 76  count: number;
 77  location?: LocationResponse | null;
 78  room?: RoomResponse | null;
 79}) {
 080  const path = room && location
 81    ? `${location.name}\\${room.name}`
 82    : location?.name ?? "All Items";
 83  // toLocaleDateString resolves to the host's locale, which differs between the
 84  // SSR Node process and the browser — useSyncExternalStore returns the empty
 85  // server snapshot during SSR and switches to the client value after hydration.
 086  const date = useSyncExternalStore(noopSubscribe, getClientDate, getServerDate);
 087  return (
 88    <div className="win98-statusbar">
 89      <div className="win98-statusbar-seg">{count} object(s)</div>
 90      <div className="win98-statusbar-seg">{path}</div>
 91      <div className="win98-statusbar-seg win98-statusbar-seg--narrow">
 92        {date}
 93      </div>
 94    </div>
 95  );
 96}