// 상세 패널 (300px) — 헤더(썸네일·이름·닫기) → 밑줄 탭(정보/태그) → 스크롤 본문.
// 색은 예외 없이 var() 경유 — 다크·라이트 두 팔레트에서 동시에 성립해야 한다.
// 헤더 썸네일 슬롯은 '사진 면'이 아니라 24px 크롬 슬롯이라 --bg-panel-raised를 쓴다
// (--grid-cell-bg는 테마 무관 고정 다크라 흰 카드 안에 검은 사각형이 박힌다).
import { IconCalendar, IconClock, IconFile, IconFolder, IconImage, IconLayers, IconTag, IconX } from "../ui/icons";
import {
  createMemo,
  createResource,
  createSignal,
  For,
  onCleanup,
  onMount,
  Show,
  type Component,
} from "solid-js";
import type { JSX } from "solid-js";
import { ko } from "../i18n/ko";
import {
  applyTagSet,
  assignTags,
  createTag,
  createTagSet,
  deleteTagSet,
  fileDetails,
  fileTagsOf,
  listTags,
  listTagSets,
  setRating,
  thumbUrl,
  unassignTags,
  updateTagSet,
  type FileDetails,
  type Tag,
  type TagSet,
} from "../ipc/commands";
import { StarRating } from "../ui/StarRating";
import { performMarkDelete, performTrash } from "../features/fileops/ContextMenu";
import { openMoveDialog } from "../features/fileops/MoveDialog";
import {
  bumpTagVersion,
  detailsTab,
  focusItemView,
  info,
  refreshSidebar,
  refreshSnapshot,
  selected,
  setDetailsOpen,
  setDetailsTab,
  thumbVersions,
  toast,
} from "../state/store";

function fmtSize(bytes: number): string {
  if (bytes >= 1 << 30) return `${(bytes / (1 << 30)).toFixed(2)} GB`;
  if (bytes >= 1 << 20) return `${(bytes / (1 << 20)).toFixed(1)} MB`;
  if (bytes >= 1 << 10) return `${(bytes / (1 << 10)).toFixed(0)} KB`;
  return `${bytes} B`;
}

/** ListView와 같은 형식 — YYYY-MM-DD HH:mm */
function fmtDate(ms: number | null | undefined): string {
  if (!ms) return "—";
  const d = new Date(ms);
  const p = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
}

/** 0:42 / 1:03:20 — 현행 "212초" 표기 폐기 */
function fmtDuration(ms: number | null | undefined): string {
  if (!ms) return "";
  const s = Math.round(ms / 1000);
  const m = Math.floor(s / 60);
  const h = Math.floor(m / 60);
  return h > 0
    ? `${h}:${String(m % 60).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`
    : `${m}:${String(s % 60).padStart(2, "0")}`;
}

/** 정보 타일 1칸 */
const Tile: Component<{
  icon: JSX.Element;
  label: string;
  value: string;
  clamp?: boolean;
  title?: string;
}> = (props) => (
  <div class="info-tile">
    <span class="info-tile__icon">{props.icon}</span>
    <div class="info-tile__body">
      <div class="info-tile__label">{props.label}</div>
      <div
        class="info-tile__value"
        classList={{ "info-tile__value--clamp": props.clamp }}
        title={props.title}
      >
        {props.value}
      </div>
    </div>
  </div>
);

/** 정보 타일 2분할 — 300px 폭에서 깨지지 않는 상한이 2칸이다 */
const SplitTile: Component<{
  icon: JSX.Element;
  labelA: string;
  valueA: string;
  labelB: string;
  valueB: string;
}> = (props) => (
  <div class="info-tile info-tile--split">
    <span class="info-tile__icon">{props.icon}</span>
    <div class="info-tile__body">
      <div class="min-w-0">
        <div class="info-tile__label">{props.labelA}</div>
        <div class="info-tile__value">{props.valueA}</div>
      </div>
      <div class="min-w-0">
        <div class="info-tile__label">{props.labelB}</div>
        <div class="info-tile__value">{props.valueB}</div>
      </div>
    </div>
  </div>
);

/** 선택 없음 — 두 탭이 공유한다 */
const EmptyState: Component = () => (
  <div class="flex h-[180px] flex-col items-center justify-center gap-2 px-6 text-center">
    <IconImage size={32} class="text-[var(--text-muted)] opacity-50" />
    <span class="text-[11px] leading-4 text-[var(--text-muted)]">{ko.details.noSelection}</span>
  </div>
);

/**
 * 세트 만들기·고치기. 태그 편집기 위에 겹쳐 뜬다 — 모달 3종과 같은 언어(스크림 + 카드 + Esc).
 *
 * 단축키는 **눌러서 지정한다**. 문자열로 적게 하면 "Ctrl+1"과 "ctrl+1"과 "^1"이 섞이고,
 * 실제로 그 조합이 브라우저에서 어떤 key로 오는지 사용자가 알 수 없다.
 */
const TagSetEditor: Component<{
  target: TagSet | "new";
  allTags: Tag[];
  onClose: () => void;
  onSaved: () => void;
}> = (props) => {
  const existing = () => (props.target === "new" ? undefined : props.target);
  const [name, setName] = createSignal(existing()?.name ?? "");
  const [hotkey, setHotkey] = createSignal<string | null>(existing()?.hotkey ?? null);
  const [picked, setPicked] = createSignal<Set<number>>(
    new Set((existing()?.tags ?? []).map((t) => t.id)),
  );
  const [capturing, setCapturing] = createSignal(false);

  const toggle = (id: number) =>
    setPicked((p) => {
      const n = new Set(p);
      if (n.has(id)) n.delete(id);
      else n.add(id);
      return n;
    });

  const save = async () => {
    const n = name().trim();
    if (!n) return;
    try {
      const ex = existing();
      if (ex) {
        await updateTagSet(ex.id, { name: n, hotkey: hotkey(), tagIds: [...picked()] });
      } else {
        const id = await createTagSet(n, [...picked()]);
        if (hotkey()) await updateTagSet(id, { hotkey: hotkey() });
      }
      props.onSaved();
    } catch (e) {
      toast(String(e));
    }
  };

  const remove = async () => {
    const ex = existing();
    if (!ex) return;
    try {
      await deleteTagSet(ex.id);
      props.onSaved();
    } catch (e) {
      toast(String(e));
    }
  };

  // 키 캡처 — 수식키만 눌린 상태는 무시한다(Ctrl을 누르는 중에 확정되면 안 된다)
  const onCapture = (e: KeyboardEvent) => {
    if (!capturing()) return;
    e.preventDefault();
    e.stopPropagation();
    if (e.key === "Escape") {
      setCapturing(false);
      return;
    }
    if (["Control", "Shift", "Alt", "Meta"].includes(e.key)) return;
    setHotkey(`${e.ctrlKey ? "Ctrl+" : ""}${e.shiftKey ? "Shift+" : ""}${e.key}`);
    setCapturing(false);
  };
  onMount(() => {
    window.addEventListener("keydown", onCapture, { capture: true });
    onCleanup(() => window.removeEventListener("keydown", onCapture, { capture: true }));
  });

  return (
    <div class="modal-scrim" onClick={props.onClose}>
      <div class="modal-card w-[420px]" onClick={(e) => e.stopPropagation()}>
        <div class="modal-head">
          <span class="modal-head__title">
            {existing() ? ko.tags.editSet : ko.tags.newSet}
          </span>
          <button class="icon-btn ml-auto" onClick={props.onClose} title={ko.common.close}>
            <IconX size={14} />
          </button>
        </div>
        <div class="modal-body">
          <div class="section-label">{ko.tags.setName}</div>
          <input
            class="field field--block mt-1.5"
            value={name()}
            placeholder={ko.tags.setNamePlaceholder}
            onInput={(e) => setName(e.currentTarget.value)}
          />

          <div class="section-label mt-3">{ko.tags.setHotkey}</div>
          <div class="mt-1.5 flex items-center gap-2">
            <button
              class="toolbar-btn"
              classList={{ "is-on": capturing() }}
              onClick={() => setCapturing(true)}
            >
              {capturing() ? ko.tags.pressKey : (hotkey() ?? ko.tags.noHotkey)}
            </button>
            <Show when={hotkey()}>
              <button class="link-btn" onClick={() => setHotkey(null)}>
                {ko.tags.clearHotkey}
              </button>
            </Show>
          </div>
          <div class="mt-1 text-[10px] leading-4 text-[var(--text-muted)]">
            {ko.tags.hotkeyNote}
          </div>

          <div class="section-label mt-3">{ko.tags.setMembers(picked().size)}</div>
          <div class="tag-pick mt-1.5">
            <For each={props.allTags}>
              {(t) => (
                <button
                  class="chip chip--button"
                  classList={{ "is-on": picked().has(t.id) }}
                  onClick={() => toggle(t.id)}
                >
                  {t.name}
                </button>
              )}
            </For>
          </div>
        </div>
        <div class="modal-bar">
          <Show when={existing()}>
            <button class="toolbar-btn toolbar-btn--danger-fill" onClick={() => void remove()}>
              {ko.common.delete}
            </button>
          </Show>
          <button
            class="toolbar-btn toolbar-btn--primary ml-auto"
            disabled={!name().trim()}
            onClick={() => void save()}
          >
            {ko.common.save}
          </button>
        </div>
      </div>
    </div>
  );
};

/**
 * 별점 편집기 — 선택한 전부에 같은 값을 준다. 태그 편집기와 같은 자리(태그 탭 위)에 산다.
 *
 * 여러 항목의 값이 서로 다르면 채우지 않고 '여러 값'이라고 말한다. 아무 값이나 골라
 * 채워 보이면 사용자는 그게 이미 매겨진 점수라고 읽고, 건드리지 않은 항목까지 덮어쓴다.
 */
const RatingEditor: Component = () => {
  const [bump, setBump] = createSignal(0);
  const ids = () => [...selected()];
  const [details] = createResource(
    () => (ids().length > 0 ? `${ids().join(",")}:${bump()}` : undefined),
    async () => fileDetails(ids().slice(0, 500)),
  );
  const values = () => (details() ?? []).map((d) => d.rating);
  const mixed = () => new Set(values()).size > 1;
  const value = () => (mixed() ? 0 : (values()[0] ?? 0));

  const apply = async (next: number) => {
    const list = ids();
    if (list.length === 0) return;
    try {
      const n = await setRating(list, next);
      toast(ko.rating.applied(n, next));
      setBump((v) => v + 1);
      // 그리드 오버레이의 별은 스냅샷에서 온다 — 다시 읽어야 반영된다
      await refreshSnapshot();
    } catch (e) {
      toast(String(e));
    }
  };

  return (
    <div class="flex items-center gap-2 px-3 pt-2.5">
      <span class="section-label !mb-0">{ko.rating.label}</span>
      <StarRating value={value()} mixed={mixed()} onChange={(n) => void apply(n)} />
      <Show when={mixed()}>
        <span class="text-[10px] text-[var(--text-muted)]">{ko.rating.mixed}</span>
      </Show>
    </div>
  );
};

/** 선택 항목 태그 편집기 (단일/다중 선택 공용) */
const TagEditor: Component = () => {
  const [tagVersion, setTagVersion] = createSignal(0);
  const singleId = () => {
    const s = selected();
    return s.size === 1 ? [...s][0] : undefined;
  };
  const [currentTags] = createResource(
    () => (singleId() != null ? `${singleId()}:${tagVersion()}` : undefined),
    async () => fileTagsOf(singleId()!),
  );
  const [allTags] = createResource(
    () => tagVersion(),
    () => listTags(),
  );

  const addTag = async (name: string) => {
    const trimmed = name.trim();
    if (!trimmed) return;
    const ids = [...selected()];
    if (ids.length === 0) return;
    try {
      const existing = (allTags() ?? []).find((t) => t.name === trimmed);
      const tagId = existing ? existing.id : await createTag(trimmed);
      const r = await assignTags(ids, tagId);
      toast(ko.tags.assignTo(r.count, trimmed));
      setTagVersion((v) => v + 1);
      bumpTagVersion();
      refreshSidebar();
    } catch (e) {
      toast(String(e));
    }
  };

  const removeTag = async (tagId: number, name: string) => {
    const ids = [...selected()];
    const r = await unassignTags(ids, tagId);
    toast(ko.tags.removedFrom(r.count, name));
    setTagVersion((v) => v + 1);
    bumpTagVersion();
    refreshSidebar();
  };

  // ── 붙이기: 검색이 아니라 클릭 ──────────────────────────────
  // 예전에는 입력창에 매번 이름을 쳐야 했다. 태그는 몇 개~수십 개고 그중 같은 것을 반복해서
  // 붙이는 작업이라, 목록을 보여주고 누르게 하는 편이 훨씬 빠르다.
  // 입력창은 **새 태그를 만들 때와 목록이 길 때 좁히는 용도**로만 남긴다.
  const [filter, setFilter] = createSignal("");
  const attachedIds = () => new Set((currentTags() ?? []).map((t) => t.id));
  const pickable = createMemo(() => {
    const q = filter().trim().toLowerCase();
    const all = allTags() ?? [];
    return q ? all.filter((t) => t.name.toLowerCase().includes(q)) : all;
  });
  /** 입력한 이름이 기존에 없으면 '새로 만들기'를 내민다 */
  const canCreate = () => {
    const q = filter().trim();
    return q.length > 0 && !(allTags() ?? []).some((t) => t.name === q);
  };

  const toggleTag = async (t: Tag) => {
    if (selected().size === 0) return;
    if (attachedIds().has(t.id)) await removeTag(t.id, t.name);
    else await addTag(t.name);
  };

  // ── 세트 ────────────────────────────────────────────────────
  const [sets, { refetch: refetchSets }] = createResource(() => tagVersion(), listTagSets);
  const [setEditor, setSetEditor] = createSignal<TagSet | "new" | undefined>();

  const runSet = async (s: TagSet) => {
    const ids = [...selected()];
    if (ids.length === 0 || s.tags.length === 0) return;
    try {
      const r = await applyTagSet(ids, s.id);
      toast(ko.tags.setApplied(s.name, r.count));
      setTagVersion((v) => v + 1);
      bumpTagVersion();
      refreshSidebar();
    } catch (e) {
      toast(String(e));
    }
  };

  // 세트 단축키 — 선택이 있고 입력창에 포커스가 없을 때만 듣는다.
  // (입력 중에 '1'을 눌렀다고 세트가 적용되면 안 된다)
  onMount(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.altKey || e.metaKey) return;
      const el = document.activeElement;
      if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) return;
      if (selected().size === 0) return;
      const combo = `${e.ctrlKey ? "Ctrl+" : ""}${e.shiftKey ? "Shift+" : ""}${e.key}`;
      const hit = (sets() ?? []).find((s) => s.hotkey && s.hotkey === combo);
      if (!hit) return;
      e.preventDefault();
      e.stopPropagation();
      void runSet(hit);
    };
    window.addEventListener("keydown", onKey);
    onCleanup(() => window.removeEventListener("keydown", onKey));
  });

  return (
    <div class="px-3 pt-2.5 pb-3">
      {/* 붙어 있는 태그 */}
      <div class="section-label">{ko.details.tags}</div>
      <div class="mt-1.5 flex flex-wrap gap-1.5">
        <Show
          when={(currentTags()?.length ?? 0) > 0}
          fallback={<span class="text-[11px] text-[var(--text-muted)]">{ko.tags.noneYet}</span>}
        >
          <For each={currentTags()}>
            {(t) => (
              <span class="chip chip--accent">
                <span>{t.name}</span>
                <button class="chip__x" onClick={() => void removeTag(t.id, t.name)}>
                  <IconX size={11} />
                </button>
              </span>
            )}
          </For>
        </Show>
      </div>

      {/* 세트 — 한 번에 여러 개 */}
      <Show when={(sets()?.length ?? 0) > 0}>
        <div class="section-label mt-3">{ko.tags.sets}</div>
        <div class="mt-1.5 flex flex-wrap gap-1.5">
          <For each={sets()}>
            {(s) => (
              <button
                class="chip chip--button"
                disabled={selected().size === 0}
                title={ko.tags.setHint(s.tags.map((t) => t.name).join(", "))}
                onClick={() => void runSet(s)}
                onContextMenu={(e) => {
                  e.preventDefault();
                  setSetEditor(s);
                }}
              >
                {s.name}
                <Show when={s.hotkey}>
                  <kbd class="chip__kbd">{s.hotkey}</kbd>
                </Show>
              </button>
            )}
          </For>
        </div>
      </Show>

      {/* 태그 고르기 — 전체 목록을 눌러서 붙인다 */}
      <div class="section-label mt-3 flex items-center justify-between">
        <span>{ko.tags.pick}</span>
        <button class="link-btn" onClick={() => setSetEditor("new")}>
          {ko.tags.newSet}
        </button>
      </div>
      <input
        class="field field--block mt-1.5"
        placeholder={ko.tags.filterOrCreate}
        value={filter()}
        onInput={(e) => setFilter(e.currentTarget.value)}
        onKeyDown={(e) => {
          if (e.key !== "Enter") return;
          void addTag(e.currentTarget.value);
          setFilter("");
        }}
      />
      <div class="tag-pick mt-1.5">
        <Show when={canCreate()}>
          <button class="chip chip--button chip--new" onClick={() => void addTag(filter())}>
            + {filter().trim()}
          </button>
        </Show>
        <For each={pickable()}>
          {(t) => (
            <button
              class="chip chip--button"
              classList={{ "is-on": attachedIds().has(t.id) }}
              disabled={selected().size === 0}
              onClick={() => void toggleTag(t)}
              title={ko.tags.countHint(t.fileCount)}
            >
              {t.name}
            </button>
          )}
        </For>
        <Show when={(pickable().length ?? 0) === 0 && !canCreate()}>
          <span class="text-[11px] text-[var(--text-muted)]">{ko.tags.noMatch}</span>
        </Show>
      </div>

      <Show when={setEditor()}>
        {(target) => (
          <TagSetEditor
            target={target()}
            allTags={allTags() ?? []}
            onClose={() => setSetEditor(undefined)}
            onSaved={() => {
              setSetEditor(undefined);
              void refetchSets();
              setTagVersion((v) => v + 1);
            }}
          />
        )}
      </Show>
    </div>
  );
};

/** 정보 탭 — 단일 선택 */
const InfoTiles: Component<{ d: FileDetails }> = (props) => (
  <>
    <div class="section-label mx-3 mt-2.5 mb-1.5">{ko.details.sectionMedia}</div>
    <div class="grid gap-1.5 px-3">
      <Show
        when={props.d.width && props.d.height}
        fallback={
          <Tile icon={<IconImage size={14} />} label={ko.details.fileSize} value={fmtSize(props.d.size)} />
        }
      >
        <SplitTile
          icon={<IconImage size={14} />}
          labelA={ko.details.dimensions}
          valueA={`${props.d.width} × ${props.d.height}`}
          labelB={ko.details.fileSize}
          valueB={fmtSize(props.d.size)}
        />
      </Show>
      <Show when={props.d.durationMs}>
        <Tile icon={<IconClock size={14} />} label={ko.details.duration} value={fmtDuration(props.d.durationMs)} />
      </Show>
      <Show
        when={props.d.takenAt}
        fallback={
          <Tile icon={<IconCalendar size={14} />} label={ko.details.modifiedAt} value={fmtDate(props.d.mtimeMs)} />
        }
      >
        <SplitTile
          icon={<IconCalendar size={14} />}
          labelA={ko.details.takenAt}
          valueA={fmtDate(props.d.takenAt)}
          labelB={ko.details.modifiedAt}
          valueB={fmtDate(props.d.mtimeMs)}
        />
      </Show>
      <Tile icon={<IconFolder size={14} />} label={ko.details.filePath} value={props.d.dir} clamp title={props.d.dir} />
    </div>

    <div class="section-label mx-3 mt-2.5 mb-1.5">{ko.details.sectionBasic}</div>
    <div class="grid gap-1.5 px-3 pb-3">
      <Tile
        icon={<IconTag size={14} />}
        label={ko.details.kind}
        value={props.d.kind === 1 ? ko.filter.video : ko.filter.image}
      />
      <Tile
        icon={<IconFile size={14} />}
        label={ko.details.fileName}
        value={props.d.name}
        clamp
        title={props.d.name}
      />
    </div>
  </>
);

/** 정보 탭 — 다중 선택. 용량 합계·종류별 집계는 만들지 않는다(file_details 500 상한) */
const BulkPanel: Component = () => (
  <div class="grid gap-1.5 px-3 py-3">
    <div class="info-tile">
      <span class="info-tile__icon"><IconLayers size={14} /></span>
      <div class="info-tile__body">
        <div class="info-tile__value info-tile__value--big tabular-nums">
          {selected().size.toLocaleString("ko-KR")}
        </div>
        <div class="info-tile__label">{ko.details.selectedUnit}</div>
      </div>
    </div>
    <div class="grid grid-cols-2 gap-1.5">
      <button class="toolbar-btn" tabindex={-1} onClick={() => setDetailsTab("tags")}>
        {ko.details.bulkTag}
      </button>
      <button class="toolbar-btn" tabindex={-1} onClick={openMoveDialog}>
        {ko.ops.moveTo}
      </button>
      <button class="toolbar-btn" tabindex={-1} onClick={() => void performMarkDelete()}>
        {ko.trash.mark}
      </button>
      <button
        class="toolbar-btn toolbar-btn--danger"
        tabindex={-1}
        onClick={() => void performTrash()}
      >
        {ko.ops.trash}
      </button>
    </div>
  </div>
);

export const DetailsPanel: Component = () => {
  const singleId = () => {
    const s = selected();
    return s.size === 1 ? [...s][0] : undefined;
  };
  const [details] = createResource(singleId, async (id) => {
    const list = await fileDetails([id]);
    return list[0] as FileDetails | undefined;
  });

  // 썸네일이 없는 항목은 404가 난다 — 실패한 id만 기억해 두고 선택이 바뀌면 자동 해제된다.
  const [thumbErrId, setThumbErrId] = createSignal<number | undefined>();
  const thumbSrc = () => {
    const id = singleId();
    const i = info();
    if (id == null || !i || thumbErrId() === id) return undefined;
    return `${thumbUrl(i, id)}&v=${thumbVersions[id] ?? 0}`;
  };

  const headTitle = () =>
    details()?.name ??
    (selected().size > 1 ? ko.grid.selected(selected().size) : ko.details.title);

  return (
    <aside class="surface-card surface-card--fill">
      {/* 헤더 h40 */}
      <div class="flex h-10 flex-none items-center gap-2 border-b border-[var(--border)] px-3">
        <div class="h-6 w-6 flex-none overflow-hidden rounded-[var(--r-sm)] bg-[var(--bg-panel-raised)]">
          <Show when={thumbSrc()}>
            {(src) => (
              <img
                src={src()}
                class="h-full w-full object-cover"
                decoding="async"
                draggable={false}
                onError={() => setThumbErrId(singleId())}
              />
            )}
          </Show>
        </div>
        <span
          class="min-w-0 flex-1 truncate text-[13px] font-semibold text-[var(--text-primary)]"
          title={headTitle()}
        >
          {headTitle()}
        </span>
        <button
          class="icon-btn"
          tabindex={-1}
          title={ko.details.close}
          onClick={() => {
            setDetailsOpen(false);
            focusItemView();
          }}
        >
          <IconX size={13} />
        </button>
      </div>

      <div class="tabs">
        <button
          classList={{ "is-on": detailsTab() === "info" }}
          tabindex={-1}
          onClick={() => setDetailsTab("info")}
        >
          {ko.details.tabInfo}
        </button>
        <button
          classList={{ "is-on": detailsTab() === "tags" }}
          tabindex={-1}
          onClick={() => setDetailsTab("tags")}
        >
          {ko.details.tabTags}
        </button>
      </div>

      {/* min-h-0을 빠뜨리면 body{overflow:hidden} 때문에 스크롤바 없이 조용히 잘린다 */}
      <div class="min-h-0 flex-1 overflow-y-auto">
        <Show
          when={detailsTab() === "info"}
          fallback={
            <Show when={selected().size > 0} fallback={<EmptyState />}>
              {/* 별점이 태그 위에 온다 — 분류 작업에서 먼저 손이 가는 쪽이고,
                  한 줄이라 태그 목록을 아래로 많이 밀지 않는다 */}
              <RatingEditor />
              <TagEditor />
            </Show>
          }
        >
          <Show when={selected().size > 0} fallback={<EmptyState />}>
            <Show when={singleId() != null} fallback={<BulkPanel />}>
              <Show when={details()}>{(d) => <InfoTiles d={d()} />}</Show>
            </Show>
          </Show>
        </Show>
      </div>
    </aside>
  );
};
