Skip to content

Commit 1843236

Browse files
committed
[frontend] new tab button
1 parent 5202c9a commit 1843236

File tree

2 files changed

+63
-39
lines changed

2 files changed

+63
-39
lines changed

frontend/src/browser.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { createState, type Stateful } from "dreamland/core";
22
import { ThemeVars, type Theme } from "./ui/theme";
3-
import { Tab, Tabs } from "./tabs";
4-
import { Omnibox } from "./Omnibox";
3+
import { Tabs, Tab } from "./tabs";
4+
import { IconButton, Omnibox } from "./Omnibox";
5+
import { scramjet } from "./main";
6+
import iconAdd from "@ktibow/iconset-material-symbols/add";
57

68
class StatefulClass {
79
constructor(state: Stateful<any>) {
@@ -13,6 +15,9 @@ export class Browser extends StatefulClass {
1315
built: boolean = false;
1416

1517
theme: Theme;
18+
tabs: Tab[] = [];
19+
activetab: number;
20+
1621
constructor(state: Stateful<any>) {
1722
super(state);
1823

@@ -39,14 +44,34 @@ export class Browser extends StatefulClass {
3944
};
4045
}
4146

47+
newTab(title: string) {
48+
let frame = scramjet.createFrame();
49+
let tab = new Tab(title, frame);
50+
this.tabs = [...this.tabs, tab];
51+
return tab;
52+
}
53+
4254
build(): HTMLElement {
55+
let tab = this.newTab("title");
56+
this.activetab = tab.id;
4357
if (this.built) throw new Error("already built");
4458
this.built = true;
4559

4660
return (
4761
<div>
4862
<ThemeVars colors={use(this.theme)} />
49-
<Tabs />
63+
<div style="display: flex">
64+
<Tabs
65+
tabs={use(this.tabs).bind()}
66+
activetab={use(this.activetab).bind()}
67+
/>
68+
<IconButton
69+
icon={iconAdd}
70+
click={() => {
71+
this.newTab("tab 2");
72+
}}
73+
></IconButton>
74+
</div>
5075
<Omnibox />
5176
</div>
5277
);

frontend/src/tabs.tsx

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
11
import iconClose from "@ktibow/iconset-material-symbols/close";
2-
import iconAdd from "@ktibow/iconset-material-symbols/add";
32
import {
43
createState,
54
type Component,
65
type ComponentInstance,
6+
type Stateful,
77
} from "dreamland/core";
88
import { Icon } from "./ui/Icon";
9+
import { IconButton } from "./Omnibox";
910

10-
type TabCallbacks = {
11-
relayout: () => void;
12-
getMaxDragPos: () => number;
13-
getLayoutStart: () => number;
14-
getAbsoluteStart: () => number;
15-
16-
"on:transitionend": () => void;
17-
"on:setactive": (id: Symbol) => void;
18-
};
19-
20-
export const Tab: Component<{
11+
export const DragTab: Component<{
2112
active: boolean;
2213
id: number;
2314
icon: string;
@@ -51,7 +42,7 @@ export const Tab: Component<{
5142
</div>
5243
);
5344
};
54-
Tab.css = `
45+
DragTab.css = `
5546
:scope {
5647
display: inline-block;
5748
user-select: none;
@@ -138,43 +129,46 @@ Tab.css = `
138129
}
139130
`;
140131

141-
type TabData = Stateful<{
132+
let id = 0;
133+
export class Tab {
142134
id: number;
143135
title: string;
144-
active: boolean;
136+
frame: ScramjetFrame;
145137

146138
dragoffset: number;
147139
dragpos: number;
148140

149141
width: number;
150142
pos: number;
151-
}>;
143+
144+
constructor(title: string, frame: ScramjetFrame) {
145+
return createState({
146+
id: id++,
147+
frame,
148+
title,
149+
dragoffset: -1,
150+
dragpos: -1,
151+
width: 0,
152+
pos: 0,
153+
});
154+
}
155+
}
152156
export const Tabs: Component<
153-
{},
157+
{
158+
tabs: Tab[];
159+
activetab: number;
160+
},
154161
{
155162
container: HTMLElement;
156163
leftEl: HTMLElement;
157164
rightEl: HTMLElement;
158165
afterEl: HTMLElement;
159166

160-
tabs: TabData[];
161167
currentlydragging: number;
162168
},
163169
{}
164170
> = function (cx) {
165171
this.currentlydragging = -1;
166-
let id = 0;
167-
function mktab(title) {
168-
return createState({
169-
id: id++,
170-
title,
171-
dragoffset: -1,
172-
dragpos: -1,
173-
width: 0,
174-
pos: 0,
175-
});
176-
}
177-
this.tabs = [mktab("T 1"), mktab("T 2")];
178172

179173
const TAB_PADDING = 6;
180174
const TAB_MAX_SIZE = 231;
@@ -264,6 +258,11 @@ export const Tabs: Component<
264258
const afterpos = Math.max(dragpos, currpos);
265259
this.afterEl.style.transform = `translateX(${afterpos}px)`;
266260
};
261+
use(this.tabs).listen(() => {
262+
setTimeout(() => {
263+
layoutTabs(true);
264+
}, 10);
265+
});
267266

268267
cx.mount = () => {
269268
requestAnimationFrame(() => layoutTabs(false));
@@ -274,7 +273,7 @@ export const Tabs: Component<
274273
return getLayoutStart() + getRootWidth();
275274
};
276275

277-
const calcDragPos = (e: MouseEvent, tab: TabData) => {
276+
const calcDragPos = (e: MouseEvent, tab: Tab) => {
278277
const root = getTabFromIndex(tab.id);
279278
const maxPos = getMaxDragPos() - root.offsetWidth;
280279

@@ -291,7 +290,7 @@ export const Tabs: Component<
291290

292291
window.addEventListener("mouseup", (e) => {
293292
if (this.currentlydragging == -1) return;
294-
const tab = this.tabs.find((tab) => tab.id === this.currentlydragging);
293+
const tab = this.tabs.find((tab) => tab.id === this.currentlydragging)!;
295294
const root = getTabFromIndex(tab.id);
296295
const dragroot = root.querySelector(".dragroot") as HTMLElement;
297296

@@ -303,8 +302,7 @@ export const Tabs: Component<
303302
this.currentlydragging = -1;
304303
});
305304

306-
const mosueDown = (e: MouseEvent, tab: TabData) => {
307-
tab.active = true;
305+
const mosueDown = (e: MouseEvent, tab: Tab) => {
308306
this.currentlydragging = tab.id;
309307

310308
const root = getTabFromIndex(tab.id);
@@ -331,11 +329,11 @@ export const Tabs: Component<
331329
<div this={use(this.container).bind()}>
332330
<div class="extra left" this={use(this.leftEl).bind()}></div>
333331
{use(this.tabs).mapEach((tab) => (
334-
<Tab
332+
<DragTab
335333
id={tab.id}
336334
title={tab.title}
337335
icon="/vite.svg"
338-
active={use(tab.id).map((id) => id === this.currentlydragging)}
336+
active={use(this.activetab).map((x) => x === tab.id)}
339337
mousedown={(e) => mosueDown(e, tab)}
340338
transitionend={transitionend}
341339
/>
@@ -347,6 +345,7 @@ export const Tabs: Component<
347345
};
348346
Tabs.css = `
349347
:scope {
348+
flex: 1;
350349
background: var(--aboutbrowser-frame-bg);
351350
padding: 6px 12px;
352351
height: calc(28px + 12px);

0 commit comments

Comments
 (0)