@@ -279,17 +259,14 @@ export function GsvDesktop({
bubble to the section handler to deselect. Interactive children below
stop propagation so they don't trigger a deselect. */}
@@ -386,18 +338,50 @@ export function GsvDesktop({
{/* No empty state: an object with no children simply shows the
"connect new" card below. Messengers always lists Telegram
and Discord, so it is never empty. */}
- {activeObject.children.map((child) => (
- onOpenObject(child)}
- />
- ))}
+ {activeObject.children.map((child) => {
+ // External (imported) applications carry a provenance band
+ // above the card; native and non-application children keep
+ // an empty band so card tops stay aligned across the grid.
+ const external = activeObject.id === "applications" && !child.native;
+ return (
+
+ >
+ );
+}
+
+const repoLineStyle = { color: "var(--text-muted)", letterSpacing: "0.08em", textTransform: "none" as const };
+
+// ── Variant renderers ────────────────────────────────────────────────────────
+
+/** A — Eyebrow: typography only. The eyebrow reads "EXTERNAL · WEB UI" and the
+ * row sub names the source repo. */
+function variantA() {
+ return (
+
+ {variantHead(
+ "A",
+ "Eyebrow",
+ "Typography only — the eyebrow reads “EXTERNAL · WEB UI” against the native “APPLICATION · GSV”, and the list-row sub names the source repo. No new chrome: cheapest to ship, softest at a glance.",
+ )}
+
Object strip · desktop
+
+
+ {EXTERNAL_APPS.map((app) => (
+
+ ))}
+
+
List rows
+
+
+ {EXTERNAL_APPS.map((app) => (
+
+ ))}
+
+
+ );
+}
+
+/** B — Dashed frame: reuses the dashed "non-native / add" affordance as a frame
+ * around the whole tile/row. */
+function variantB() {
+ return (
+
+ {variantHead(
+ "B",
+ "Dashed frame",
+ "Reuses the dashed “non-native / add” affordance (var(--dashed)) as a frame around the whole tile/row. Strong glanceable signal in the console's own visual language, but adds weight to every external item.",
+ )}
+
+ );
+}
+
+/** C — Provenance tag: a boxed EXTERNAL tag + a PUBLIC/PRIVATE tag from
+ * sourcePublic + the source repo. */
+function provenanceCard(app: ExtApp) {
+ // Mirrors the shipped strip: one provenance band (tags + ellipsized repo)
+ // above the card — see .gsv-object-strip-prov in gsvShell.css.
+ return (
+
+
+
+
+
+ {app.repo}
+
+
+
+
+ );
+}
+
+function variantC() {
+ return (
+
+ {variantHead(
+ "C",
+ "Provenance tag · CHOSEN",
+ "A boxed provenance cluster — an EXTERNAL tag plus a PUBLIC/PRIVATE tag derived from sourcePublic, and the source repo. Jessica's pick (2026-07-20), with one edit: only external applications are labeled — natives carry no tag, just an empty band so card tops stay aligned. This section mirrors what ships.",
+ )}
+
+ );
+}
+
+/** D — Icon chip: swaps the generic satellite glyph for the package's own
+ * 2-letter identity chip and pins a corner EXTERNAL marker. */
+function chipCard(app: ExtApp) {
+ return (
+
+ {cornerMark("EXTERNAL")}
+
+
+ );
+}
+
+function variantD() {
+ return (
+
+ {variantHead(
+ "D",
+ "Icon chip",
+ "Swaps the generic satellite glyph for the package's own 2-letter identity chip and pins a corner EXTERNAL marker; natives keep their real product icon. Gives each imported app a face, while the marker still says “imported”. In the row the marker rides the tag slot.",
+ )}
+
+ );
+}
+
+const story: Story = {
+ title: "External Application Tile",
+ group: "Data Display",
+ blurb: "candidate treatments to mark imported apps as distinct from native GSV surfaces",
+ render: () => (
+
+
+ APPLICATIONS now holds two kinds of thing: native GSV surfaces (FILES, LIBRARY, TERMINAL, REPOS —
+ eyebrow “APPLICATION · GSV”, status “SYSTEM”) and imported web packages pulled from a source
+ repo. The native presentation is fixed; the open question is how to mark the external ones so
+ they read as distinct at a glance — in both the desktop object strip (ObjectCard) and the console list
+ (ListRow). Four candidates follow, each external tile/row shown beside its native FILES counterpart for
+ contrast, across both contexts and with two real-ish apps (one PUBLIC, one PRIVATE).{" "}
+ Variant C was chosen (2026-07-20) — with the edit that
+ only external applications get labeled; natives carry no tag. A, B and D are kept for the record.
+