Skip to content

Commit cabc961

Browse files
committed
Refine terminal copy and inline wrapped clickable link rows
1 parent 4d86a83 commit cabc961

5 files changed

Lines changed: 165 additions & 30 deletions

File tree

src/lib/components/features/terminal/BootSequence.svelte

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { accessibility } from "$lib/stores/accessibility";
44
import { finishBooting } from "$lib/stores/terminalStore";
55
66
const lines = [
7-
"HANDSHAKE: KYLEE-LINK v2.4",
8-
"AUTH: VERIFYING TRANSMISSION KEYS",
7+
"ATZ",
8+
"ATDT KYLEE-BBS",
99
"",
10-
"ROUTING: SYNCHRONIZING RELAY NODES",
11-
"PROFILE: LOADING OPERATOR DATA",
12-
"ACCESS: CLEARANCE CONFIRMED",
13-
"CHANNEL OPEN. WELCOME, GUEST.",
10+
"CONNECT 9600",
11+
"LOGIN: guest",
12+
"MESSAGE BASE: SCANNING NEW",
13+
"MAIN MENU READY. TYPE HELP.",
1414
];
1515
1616
const progressLineIndex = 2;

src/lib/components/features/terminal/FileExplorer.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@
9191
in:fade={{ duration: $accessibility.reducedMotion ? 0 : 150 }}
9292
class="flex h-full min-h-0 flex-col">
9393
<div class="w-full">
94-
<p class="text-ctp-green">RX: ARCHIVE TRAFFIC ONLINE</p>
94+
<p class="text-ctp-green">MESSAGE BASE</p>
9595
<p class="text-xs text-ctp-subtext0">
96-
MODE: RADIO LOG | ARROWS: NAV | ENTER: OPEN TRANSMISSION
96+
COMMANDS: ARROWS MOVE | ENTER READ | ESC BACK
9797
</p>
98-
<p class="mt-1 text-xs text-ctp-subtext1">CHANNELS: 01-09 | STREAM: STABLE</p>
98+
<p class="mt-1 text-xs text-ctp-subtext1">SCAN: NEW MAIL | STATUS: ONLINE</p>
9999
</div>
100100
<div
101101
class="my-4 min-h-0 flex-1 overflow-auto">
@@ -125,7 +125,7 @@
125125
</div>
126126
<div class="mt-1 flex w-full flex-shrink-0 items-center">
127127
<p class="flex items-baseline">
128-
<span>RX_READY&gt;&nbsp;</span>
128+
<span>BBS&gt;&nbsp;</span>
129129
<BlinkingCursor />
130130
</p>
131131
</div>

src/lib/components/features/terminal/ProjectFile.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export let index: number;
55
66
$: seq = String(index + 1).padStart(2, "0");
77
$: id = project.id.slice(-6).toUpperCase();
8-
$: channel = `CH-${String((index % 9) + 1).padStart(2, "0")}`;
8+
$: channel = `AREA-${String((index % 9) + 1).padStart(2, "0")}`;
99
$: stamp = project.date.toUpperCase();
1010
</script>
1111

src/lib/components/features/terminal/ProjectView.svelte

Lines changed: 150 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { crtShutdown } from "$lib/transitions/crtShutdown";
77
import { fade } from "svelte/transition";
88
export let project: Project;
9+
// TODO: Redesign project view layout/content hierarchy while preserving terminal aesthetic.
910
1011
const wrap = (text: string, width: number) => {
1112
const words = text.split(/\s+/);
@@ -27,23 +28,59 @@
2728
const BOX_WIDTH = 60;
2829
const CONTENT_WIDTH = BOX_WIDTH - 2;
2930
const BORDER = `+${"-".repeat(CONTENT_WIDTH)}+`;
31+
const FIELD_LABEL = "SOURCE :: ";
32+
const FIELD_INDENT = " ".repeat(FIELD_LABEL.length);
3033
const line = (label: string, value = "") =>
3134
`|${(` ${label}${value}`).slice(0, CONTENT_WIDTH).padEnd(CONTENT_WIDTH, " ")}|`;
35+
const splitForField = (label: string, value: string) => {
36+
const prefix = ` ${label}`;
37+
const width = Math.max(8, CONTENT_WIDTH - prefix.length);
38+
const normalized = value.trim();
39+
if (!normalized) return [""];
40+
41+
const breakChars = new Set(["/", "?", "&", "=", "#", "-", "_", "."]);
42+
const segments: string[] = [];
43+
let remaining = normalized;
44+
45+
while (remaining.length > width) {
46+
let breakAt = -1;
47+
for (let i = 0; i < width; i++) {
48+
if (breakChars.has(remaining[i])) {
49+
breakAt = i + 1;
50+
}
51+
}
52+
53+
if (breakAt <= 0) {
54+
breakAt = width;
55+
}
56+
57+
segments.push(remaining.slice(0, breakAt));
58+
remaining = remaining.slice(breakAt);
59+
}
60+
61+
segments.push(remaining);
62+
return segments.filter((segment) => segment.length > 0);
63+
};
3264
$: descLines = wrap(project.description, CONTENT_WIDTH - 2);
65+
$: visualSrc = project.visual?.src ?? "";
66+
$: visualSrcLower = visualSrc.toLowerCase();
67+
$: isVideoAsset = visualSrcLower.endsWith(".webm") || visualSrcLower.endsWith(".mp4");
68+
$: videoMimeType = visualSrcLower.endsWith(".webm") ? "video/webm" : "video/mp4";
69+
$: sourceLink = project.links?.github ?? "";
70+
$: previewLink = project.links?.live ?? "";
71+
$: sourceChunks = splitForField(FIELD_LABEL, sourceLink || "NONE");
72+
$: previewChunks = splitForField("PREVIEW :: ", previewLink || "NONE");
3373
$: printout = [
3474
BORDER,
35-
line("RECORD :: ", project.title),
36-
line("ID :: ", project.id.toUpperCase()),
37-
line("STAMP :: ", project.date),
38-
line("CLASS :: ", project.extension.toUpperCase()),
39-
line("TECH :: ", project.tech.join(" | ")),
75+
line("SUBJ :: ", project.title),
76+
line("MSG# :: ", project.id.toUpperCase()),
77+
line("POSTED :: ", project.date),
78+
line("FORMAT :: ", project.extension.toUpperCase()),
79+
line("KEYWORDS:: ", project.tech.join(" | ")),
4080
BORDER,
41-
line("BRIEFING"),
81+
line("TEXT"),
4282
...descLines.map((entry) => line("", entry)),
4383
BORDER,
44-
line("CODE UPLINK :: ", project.links?.github ? "ONLINE" : "OFFLINE"),
45-
line("LIVE UPLINK :: ", project.links?.live ? "ONLINE" : "OFFLINE"),
46-
BORDER,
4784
].join("\n");
4885
4986
let viewEl: HTMLDivElement;
@@ -70,14 +107,14 @@
70107
out:crtShutdown={{ duration: $accessibility.reducedMotion ? 0 : 550 }}
71108
class="project-view absolute inset-0 flex h-full max-h-full min-h-0 flex-col">
72109
<header class="mb-4 flex-shrink-0">
73-
<p>RX: OPEN_RECORD {project.id.toUpperCase()}</p>
110+
<p>READ MAIL {project.id.toUpperCase()}</p>
74111
</header>
75112

76113
<main class="flex-grow overflow-auto min-h-0">
77114
<div class="grid grid-cols-1 md:grid-cols-[1fr_auto_1fr] md:gap-x-4">
78115
<div class="visual-container mb-8 md:mb-0">
79116
{#if project.visual && project.visual.src}
80-
{#if project.visual.type === "image"}
117+
{#if project.visual.type === "image" && !isVideoAsset}
81118
<img
82119
src={project.visual.src}
83120
alt={project.title}
@@ -87,9 +124,14 @@
87124
e.currentTarget as HTMLImageElement
88125
).style.display = "none";
89126
}} />
90-
{:else if project.visual.type === "video"}
91-
<video controls class="w-full h-auto border-2 border-ctp-surface1 p-1">
92-
<source src={project.visual.src} type="video/mp4" />
127+
{:else if project.visual.type === "video" || isVideoAsset}
128+
<video
129+
autoplay
130+
loop
131+
muted
132+
playsinline
133+
class="w-full h-auto border-2 border-ctp-surface1 p-1">
134+
<source src={project.visual.src} type={videoMimeType} />
93135
Your browser does not support the video tag.
94136
</video>
95137
{:else if project.visual.type === "embed"}
@@ -121,6 +163,59 @@
121163

122164
<div class="details-container">
123165
<pre class="text-ctp-text text-xs sm:text-sm overflow-x-auto">{printout}</pre>
166+
<div class="ascii-link-block mt-0 text-xs sm:text-sm">
167+
{#if sourceLink}
168+
<a
169+
href={sourceLink}
170+
target="_blank"
171+
rel="noopener noreferrer"
172+
class="ascii-link-group">
173+
{#each sourceChunks as chunk, index (`source-${index}`)}
174+
<span class="ascii-link-line">
175+
<span class="ascii-side">|</span>
176+
<span class="ascii-label">{index === 0 ? ` ${FIELD_LABEL}` : ` ${FIELD_INDENT}`}</span>
177+
<span class="ascii-link-value">{chunk}</span>
178+
<span class="ascii-side">|</span>
179+
</span>
180+
{/each}
181+
</a>
182+
{:else}
183+
{#each sourceChunks as chunk, index (`source-${index}`)}
184+
<p class="ascii-link-line">
185+
<span class="ascii-side">|</span>
186+
<span class="ascii-label">{index === 0 ? ` ${FIELD_LABEL}` : ` ${FIELD_INDENT}`}</span>
187+
<span class="ascii-link-value">{chunk}</span>
188+
<span class="ascii-side">|</span>
189+
</p>
190+
{/each}
191+
{/if}
192+
{#if previewLink}
193+
<a
194+
href={previewLink}
195+
target="_blank"
196+
rel="noopener noreferrer"
197+
class="ascii-link-group">
198+
{#each previewChunks as chunk, index (`preview-${index}`)}
199+
<span class="ascii-link-line">
200+
<span class="ascii-side">|</span>
201+
<span class="ascii-label">{index === 0 ? " PREVIEW :: " : ` ${FIELD_INDENT}`}</span>
202+
<span class="ascii-link-value">{chunk}</span>
203+
<span class="ascii-side">|</span>
204+
</span>
205+
{/each}
206+
</a>
207+
{:else}
208+
{#each previewChunks as chunk, index (`preview-${index}`)}
209+
<p class="ascii-link-line">
210+
<span class="ascii-side">|</span>
211+
<span class="ascii-label">{index === 0 ? " PREVIEW :: " : ` ${FIELD_INDENT}`}</span>
212+
<span class="ascii-link-value">{chunk}</span>
213+
<span class="ascii-side">|</span>
214+
</p>
215+
{/each}
216+
{/if}
217+
<p class="ascii-border-line">{BORDER}</p>
218+
</div>
124219
</div>
125220
</div>
126221
</main>
@@ -130,7 +225,7 @@
130225
on:click={closeProject}
131226
aria-label="Close project window"
132227
class="text-ctp-red hover:bg-ctp-red hover:text-ctp-base p-1"
133-
>[TERMINATE LINK]</button>
228+
>[RETURN TO MENU]</button>
134229
</footer>
135230
</div>
136231

@@ -151,4 +246,44 @@
151246
footer {
152247
flex-shrink: 0;
153248
}
249+
250+
.ascii-link-block {
251+
max-width: 100%;
252+
}
253+
254+
.ascii-link-line {
255+
display: grid;
256+
grid-template-columns: auto auto minmax(0, 1fr) auto;
257+
align-items: baseline;
258+
margin: 0;
259+
white-space: nowrap;
260+
}
261+
262+
.ascii-link-group {
263+
display: block;
264+
color: inherit;
265+
text-decoration: none;
266+
}
267+
268+
.ascii-side,
269+
.ascii-label {
270+
color: var(--color-ctp-text);
271+
}
272+
273+
.ascii-link-value {
274+
min-width: 0;
275+
white-space: nowrap;
276+
color: var(--color-ctp-blue);
277+
text-decoration: none;
278+
}
279+
280+
.ascii-link-group:hover .ascii-link-value,
281+
.ascii-link-group:focus-visible .ascii-link-value {
282+
text-decoration: underline;
283+
}
284+
285+
.ascii-border-line {
286+
margin: 0;
287+
color: var(--color-ctp-text);
288+
}
154289
</style>

src/lib/components/features/terminal/Terminal.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,19 @@
3131
dir="ltr"
3232
lang="en"
3333
role="region"
34-
aria-label="Terminal project browser"
34+
aria-label="Terminal message browser"
3535
class="relative flex h-[68dvh] min-h-[22rem] w-full flex-col overflow-hidden rounded border-2 border-ctp-surface0 bg-ctp-crust p-4 font-mono text-sm leading-relaxed text-ctp-green sm:h-[38rem] sm:min-h-[38rem] sm:max-h-[38rem] sm:text-base">
3636
<div
3737
class="mb-3 flex flex-shrink-0 gap-3 overflow-x-auto text-xs whitespace-nowrap sm:text-sm">
38-
<p>[COMMS_NODE] KYLEE-LINK</p>
39-
<p>[CHANNEL] PORTFOLIO_FEED</p>
38+
<p>[SYSTEM] KYLEE BBS</p>
39+
<p>[NODE] 1</p>
4040
<p>[STATE] {$terminalStore.state.toUpperCase()}</p>
4141
</div>
4242

4343
<div class="relative min-h-0 flex-1 overflow-hidden">
4444
{#if $terminalStore.state === "waiting"}
4545
<div class="absolute inset-0 overflow-auto p-2">
46-
<p>LINK STATUS: STANDBY_</p>
46+
<p>WAITING FOR CONNECT_</p>
4747
</div>
4848
{:else if $terminalStore.state === "booting"}
4949
<div class="absolute inset-0 overflow-auto p-2">

0 commit comments

Comments
 (0)