Skip to content

Commit fad2311

Browse files
committed
[frontend] link tabs to scramjet frames
1 parent e16db09 commit fad2311

File tree

5 files changed

+132
-33
lines changed

5 files changed

+132
-33
lines changed

frontend/src/Omnibox.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ Spacer.css = `
2222
`;
2323

2424
export const UrlInput: Component<
25-
{},
2625
{
2726
value: string;
27+
},
28+
{
2829
active: boolean;
2930
input: HTMLInputElement;
3031

@@ -34,7 +35,6 @@ export const UrlInput: Component<
3435
}
3536
> = function (cx) {
3637
this.focusindex = 0;
37-
this.value = "";
3838
this.overflowItems = ["test", "test2", "test3", "test4", "test5"];
3939
const fetchSuggestions = async () => {
4040
let resp = await client.fetch(
@@ -218,14 +218,16 @@ IconButton.css = `
218218
}
219219
`;
220220

221-
export const Omnibox: Component<{}> = function (cx) {
221+
export const Omnibox: Component<{
222+
value: string;
223+
}> = function (cx) {
222224
return (
223225
<div>
224226
<IconButton icon={iconBack}></IconButton>
225227
<IconButton icon={iconForwards}></IconButton>
226228
<IconButton icon={iconRefresh}></IconButton>
227229
<Spacer></Spacer>
228-
<UrlInput></UrlInput>
230+
<UrlInput value={use(this.value)}></UrlInput>
229231
<Spacer></Spacer>
230232
<IconButton icon={iconExtension}></IconButton>
231233
<IconButton

frontend/src/Shell.tsx

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,50 @@
11
import type { Component } from "dreamland/core";
2-
import type { Tab } from "./Tab";
2+
import type { Tab } from "./tabs";
33

4-
export const Shell: Component<
5-
{
6-
tabs: Tab[];
7-
activeTab: Tab;
8-
},
9-
{},
10-
{
11-
pushFrame: (frame: ScramjetFrame) => void;
12-
}
13-
> = function (cx) {
14-
this.pushFrame = (frame) => {
4+
export let pushTab: (tab: Tab) => void;
5+
export let popTab: (tab: Tab) => void;
6+
7+
export const Shell: Component<{
8+
tabs: Tab[];
9+
activetab: Tab;
10+
}> = function (cx) {
11+
pushTab = (tab) => {
12+
tab.frame.frame.classList.add(cx.id);
1513
cx.root.appendChild(
1614
<div
17-
class="container"
18-
class:active={use(this.activeTab).map(
19-
(t) => t && t.$.state.frame === frame
20-
)}
15+
class={`container ${cx.id}`}
16+
class:active={use(this.activetab).map((t) => t === tab)}
2117
>
22-
{frame.frame}
18+
{tab.frame.frame}
2319
</div>
2420
);
2521
};
22+
popTab = (tab) => {
23+
for (let el of cx.root.children) {
24+
if (el.children[0] == tab.frame.frame) {
25+
el.remove();
26+
break;
27+
}
28+
}
29+
};
2630

2731
return <div></div>;
2832
};
2933
Shell.css = `
34+
:scope {
35+
flex: 1;
36+
}
37+
.container {
38+
width: 100%;
39+
height: 100%;
40+
display: none;
41+
}
42+
.container.active {
43+
display: block;
44+
}
3045
iframe {
31-
46+
width: 100%;
47+
height: 100%;
48+
border: none;
3249
}
3350
`;

frontend/src/browser.tsx

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import { Tabs, Tab } from "./tabs";
44
import { IconButton, Omnibox } from "./Omnibox";
55
import { scramjet } from "./main";
66
import iconAdd from "@ktibow/iconset-material-symbols/add";
7+
import { popTab, pushTab, Shell } from "./Shell";
8+
9+
// let a = createState({
10+
// b: createState({
11+
// c: "test",
12+
// }),
13+
// });
14+
// use(a.b.c).listen((v) => {
15+
// console.log("a.b.c changed to", v);
16+
// });
17+
// a.b.c = "test2";
718

819
class StatefulClass {
920
constructor(state: Stateful<any>) {
@@ -16,7 +27,7 @@ export class Browser extends StatefulClass {
1627

1728
theme: Theme;
1829
tabs: Tab[] = [];
19-
activetab: number;
30+
activetab: Tab;
2031

2132
constructor(state: Stateful<any>) {
2233
super(state);
@@ -47,23 +58,51 @@ export class Browser extends StatefulClass {
4758
newTab(title: string) {
4859
let frame = scramjet.createFrame();
4960
let tab = new Tab(title, frame);
61+
frame.go("https://google.com");
62+
frame.addEventListener("navigate", (e) => {
63+
console.error(e);
64+
tab.url = frame.client.url.href;
65+
});
66+
frame.frame.addEventListener("load", (e) => {
67+
tab.url = frame.client.url.href;
68+
});
69+
use(tab.url).listen(() => {
70+
this.activetab = this.activetab;
71+
});
72+
pushTab(tab);
5073
this.tabs = [...this.tabs, tab];
74+
this.activetab = tab;
5175
return tab;
5276
}
5377

78+
destroyTab(tab: Tab) {
79+
this.tabs = this.tabs.filter((t) => t !== tab);
80+
console.log(this.tabs);
81+
if (this.activetab === tab) {
82+
this.activetab = this.tabs[0] || this.newTab("New Tab");
83+
}
84+
console.log(this.tabs);
85+
86+
console.log(this.activetab);
87+
popTab(tab);
88+
}
89+
5490
build(): HTMLElement {
91+
let shell = <Shell tabs={use(this.tabs)} activetab={use(this.activetab)} />;
92+
5593
let tab = this.newTab("title");
56-
this.activetab = tab.id;
94+
this.activetab = tab;
5795
if (this.built) throw new Error("already built");
5896
this.built = true;
5997

6098
return (
6199
<div>
62100
<ThemeVars colors={use(this.theme)} />
63-
<div style="display: flex">
101+
<div style="display: flex; align-items: center; background: var(--aboutbrowser-frame-bg)">
64102
<Tabs
65103
tabs={use(this.tabs).bind()}
66104
activetab={use(this.activetab).bind()}
105+
destroyTab={(tab) => this.destroyTab(tab)}
67106
/>
68107
<IconButton
69108
icon={iconAdd}
@@ -72,7 +111,8 @@ export class Browser extends StatefulClass {
72111
}}
73112
></IconButton>
74113
</div>
75-
<Omnibox />
114+
<Omnibox value={use(this.activetab.url)} />
115+
{shell}
76116
</div>
77117
);
78118
}

frontend/src/style.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ html,
66
margin: 0;
77
padding: 0;
88
overflow: hidden;
9+
display: flex;
10+
flex-direction: column;
911
}
1012

1113
:root {

frontend/src/tabs.tsx

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export const DragTab: Component<{
1414
icon: string;
1515
title: string;
1616
mousedown: (e: MouseEvent) => void;
17+
click: () => void;
18+
destroy: () => void;
1719
transitionend: () => void;
1820
}> = function (cx) {
1921
return (
@@ -29,11 +31,23 @@ export const DragTab: Component<{
2931
this.transitionend();
3032
}}
3133
>
32-
<div class="dragroot" style="position: unset;">
34+
<div
35+
class="dragroot"
36+
style="position: unset;"
37+
on:click={() => this.click()}
38+
>
3339
<div class={use(this.active).map((x) => `main ${x ? "active" : ""}`)}>
3440
<img src={use(this.icon)} />
3541
<span>{use(this.title)}</span>
36-
<Icon class="close" icon={iconClose} />
42+
<button
43+
class="close"
44+
on:click={(e) => {
45+
e.stopPropagation();
46+
this.destroy();
47+
}}
48+
>
49+
<Icon icon={iconClose} />
50+
</button>
3751
</div>
3852
{/* <div class="belowcontainer">
3953
{use(this.active).andThen(<div class="below"></div>)}
@@ -79,10 +93,23 @@ DragTab.css = `
7993
white-space: nowrap;
8094
text-overflow: ellipsis;
8195
}
82-
.main .close {
96+
.main .close > * {
8397
width: 14px;
8498
height: 14px;
8599
}
100+
.close {
101+
outline: none;
102+
border: none;
103+
background: none;
104+
cursor: pointer;
105+
106+
display: flex;
107+
align-items: center;
108+
justify-content: center;
109+
110+
padding: 0;
111+
margin-left: 8px;
112+
}
86113
87114
.main:not(.active):hover {
88115
transition: background 250ms;
@@ -134,6 +161,7 @@ export class Tab {
134161
id: number;
135162
title: string;
136163
frame: ScramjetFrame;
164+
url: string;
137165

138166
dragoffset: number;
139167
dragpos: number;
@@ -146,6 +174,7 @@ export class Tab {
146174
id: id++,
147175
frame,
148176
title,
177+
url: "puter://blank",
149178
dragoffset: -1,
150179
dragpos: -1,
151180
width: 0,
@@ -156,7 +185,8 @@ export class Tab {
156185
export const Tabs: Component<
157186
{
158187
tabs: Tab[];
159-
activetab: number;
188+
activetab: Tab;
189+
destroyTab: (tab: Tab) => void;
160190
},
161191
{
162192
container: HTMLElement;
@@ -302,7 +332,7 @@ export const Tabs: Component<
302332
this.currentlydragging = -1;
303333
});
304334

305-
const mosueDown = (e: MouseEvent, tab: Tab) => {
335+
const mouseDown = (e: MouseEvent, tab: Tab) => {
306336
this.currentlydragging = tab.id;
307337

308338
const root = getTabFromIndex(tab.id);
@@ -333,8 +363,16 @@ export const Tabs: Component<
333363
id={tab.id}
334364
title={tab.title}
335365
icon="/vite.svg"
336-
active={use(this.activetab).map((x) => x === tab.id)}
337-
mousedown={(e) => mosueDown(e, tab)}
366+
active={use(this.activetab).map((x) => x === tab)}
367+
mousedown={(e) => mouseDown(e, tab)}
368+
click={() => {
369+
if (this.activetab !== tab) {
370+
this.activetab = tab;
371+
}
372+
}}
373+
destroy={() => {
374+
this.destroyTab(tab);
375+
}}
338376
transitionend={transitionend}
339377
/>
340378
))}

0 commit comments

Comments
 (0)