Skip to content

Commit fd25321

Browse files
committed
[chrome] further split and refactor omnibox, prepare for more agressive autocomplete behavior
1 parent 4c2d6ea commit fd25321

File tree

7 files changed

+748
-698
lines changed

7 files changed

+748
-698
lines changed

packages/chrome/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { Component } from "dreamland/core";
2-
import { Omnibox } from "./components/Omnibar/Omnibox";
32
import { Tabs } from "./components/TabStrip";
43
import { browser } from "./Browser";
54
import type { Tab } from "./Tab";
65
import { BookmarksStrip } from "./components/BookmarksStrip";
6+
import { Omnibar } from "./components/Omnibar/Omnibar";
77

88
export const App: Component = function (cx) {
99
const applyTheme = () => {
@@ -44,7 +44,7 @@ export const App: Component = function (cx) {
4444
browser.destroyTab(tab);
4545
}}
4646
/>
47-
<Omnibox tab={use(browser.activetab)} />
47+
<Omnibar tab={use(browser.activetab)} />
4848
{use(browser.activetab.url, browser.settings.bookmarksPinned)
4949
.map(([u, pinned]) => pinned || u.href === "puter://newtab")
5050
.andThen(<BookmarksStrip />)}

packages/chrome/src/Browser.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import { Tab, type SerializedTab } from "./Tab";
44
import { createDelegate } from "dreamland/core";
55
import type { SerializedHistoryState } from "./History";
66
import { HistoryState } from "./History";
7-
import { focusOmnibox } from "./components/Omnibar/UrlInput";
7+
import { focusOmnibox } from "./components/Omnibar/Omnibox";
88

99
import * as tldts from "tldts";
1010
import { isPuter } from "./main";
1111
import {
1212
animateDownloadFly,
1313
showDownloadsPopup,
14-
} from "./components/Omnibar/Omnibox";
14+
} from "./components/Omnibar/Omnibar";
1515
export const pushTab = createDelegate<Tab>();
1616
export const popTab = createDelegate<Tab>();
1717
export const forceScreenshot = createDelegate<Tab>();
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
import { css, type Component } from "dreamland/core";
2+
import {
3+
iconBack,
4+
iconForwards,
5+
iconRefresh,
6+
iconExtension,
7+
iconDownload,
8+
iconMore,
9+
iconExit,
10+
iconNew,
11+
iconTime,
12+
iconInfo,
13+
iconSettings,
14+
} from "../../icons";
15+
import { createMenu, createMenuCustom } from "../Menu";
16+
import { OmnibarButton } from "./OmnibarButton";
17+
import { createDelegate } from "dreamland/core";
18+
import type { Tab } from "../../Tab";
19+
import { Omnibox } from "./Omnibox";
20+
import { browser } from "../../Browser";
21+
import { Icon } from "../Icon";
22+
import { defaultFaviconUrl } from "../../assets/favicon";
23+
24+
import type { HistoryState } from "../../History";
25+
import { isPuter } from "../../main";
26+
import { DownloadsPopup } from "../DownloadsPopup";
27+
import { CircularProgress } from "./CircularProgress";
28+
29+
export const animateDownloadFly = createDelegate<void>();
30+
export const showDownloadsPopup = createDelegate<void>();
31+
32+
export const Spacer: Component = function (cx) {
33+
return <div></div>;
34+
};
35+
Spacer.style = css`
36+
:scope {
37+
width: 2em;
38+
}
39+
`;
40+
41+
export const Omnibar: Component<{
42+
tab: Tab;
43+
}> = function (cx) {
44+
const selectContent = createDelegate<void>();
45+
46+
animateDownloadFly.listen(async () => {
47+
await new Promise((r) => setTimeout(r, 10));
48+
let fly: HTMLElement = cx.root.querySelector(".downloadfly")!;
49+
fly.addEventListener(
50+
"transitionend",
51+
() => {
52+
fly.style.opacity = "0";
53+
fly.classList.add("down");
54+
},
55+
{ once: true }
56+
);
57+
fly.style.opacity = "1";
58+
fly.classList.remove("down");
59+
});
60+
61+
const historyMenu = (e: MouseEvent, states: HistoryState[]) => {
62+
if (states.length > 0) {
63+
createMenu(
64+
{ left: e.clientX, top: cx.root.clientTop + cx.root.clientHeight * 2 },
65+
[
66+
...states.map((s) => ({
67+
label: s.title || "New Tab",
68+
image: s.favicon || defaultFaviconUrl,
69+
action: () => {
70+
let rel =
71+
browser.activetab.history.states.indexOf(s) -
72+
browser.activetab.history.index;
73+
browser.activetab.history.go(rel);
74+
},
75+
})),
76+
"-",
77+
{
78+
icon: iconTime,
79+
label: "Show Full History",
80+
action: () => {
81+
browser.newTab(new URL("puter://history"));
82+
},
83+
},
84+
]
85+
);
86+
}
87+
e.preventDefault();
88+
e.stopPropagation();
89+
};
90+
91+
const downloadsButton = (
92+
<OmnibarButton
93+
click={() => {
94+
showDownloadsPopup();
95+
}}
96+
icon={iconDownload}
97+
></OmnibarButton>
98+
);
99+
showDownloadsPopup.listen(() => {
100+
const { right } = downloadsButton.getBoundingClientRect();
101+
createMenuCustom(
102+
{
103+
top: cx.root.clientTop + cx.root.clientHeight * 2,
104+
right,
105+
},
106+
<DownloadsPopup></DownloadsPopup>
107+
);
108+
});
109+
110+
return (
111+
<div>
112+
<OmnibarButton
113+
tooltip="Go back one page (Alt+Left Arrow)"
114+
active={use(this.tab.canGoBack)}
115+
click={() => this.tab.back()}
116+
icon={iconBack}
117+
rightclick={(e: MouseEvent) =>
118+
historyMenu(
119+
e,
120+
browser.activetab.history.states
121+
.slice(0, browser.activetab.history.index)
122+
.reverse()
123+
)
124+
}
125+
></OmnibarButton>
126+
<OmnibarButton
127+
tooltip="Go forward one page (Alt+Right Arrow)"
128+
active={use(this.tab.canGoForward)}
129+
click={() => this.tab.forward()}
130+
icon={iconForwards}
131+
rightclick={(e: MouseEvent) =>
132+
historyMenu(
133+
e,
134+
browser.activetab.history.states.slice(
135+
browser.activetab.history.index + 1,
136+
browser.activetab.history.states.length
137+
)
138+
)
139+
}
140+
></OmnibarButton>
141+
<OmnibarButton
142+
tooltip="Refresh current page (Ctrl+R)"
143+
click={() => this.tab.reload()}
144+
icon={iconRefresh}
145+
></OmnibarButton>
146+
<Spacer></Spacer>
147+
<Omnibox selectContent={selectContent} url={use(this.tab.url)}></Omnibox>
148+
<Spacer></Spacer>
149+
<OmnibarButton active={false} icon={iconExtension}></OmnibarButton>
150+
{use(browser.sessionDownloadHistory)
151+
.map((s) => s.length > 0)
152+
.andThen(
153+
<div style="position: relative">
154+
{downloadsButton}
155+
156+
<div class="downloadfly down">
157+
<Icon icon={iconDownload}></Icon>
158+
</div>
159+
<CircularProgress
160+
progress={use(browser.downloadProgress)}
161+
></CircularProgress>
162+
</div>
163+
)}
164+
165+
<OmnibarButton
166+
tooltip="More Options"
167+
icon={iconMore}
168+
click={(e: MouseEvent) => {
169+
createMenu(
170+
{ left: e.x, top: cx.root.clientTop + cx.root.clientHeight * 2 },
171+
[
172+
{
173+
label: "New Tab",
174+
action: () => {
175+
browser.newTab(new URL("puter://newtab"), true);
176+
},
177+
icon: iconNew,
178+
},
179+
"-",
180+
{
181+
label: "History",
182+
action: () => {
183+
browser.newTab(new URL("puter://history"));
184+
},
185+
icon: iconTime,
186+
},
187+
{
188+
label: "Downloads",
189+
action: () => {
190+
browser.newTab(new URL("puter://downloads"));
191+
},
192+
icon: iconDownload,
193+
},
194+
"-",
195+
{
196+
label: "About",
197+
action: () => {
198+
browser.newTab(new URL("puter://version"));
199+
},
200+
icon: iconInfo,
201+
},
202+
{
203+
label: "Settings",
204+
action: () => {
205+
browser.newTab(new URL("puter://settings"));
206+
},
207+
icon: iconSettings,
208+
},
209+
...(isPuter
210+
? [
211+
{
212+
label: "Exit",
213+
action: () => {
214+
puter.exit();
215+
},
216+
icon: iconExit,
217+
},
218+
]
219+
: []),
220+
]
221+
);
222+
e.stopPropagation();
223+
}}
224+
></OmnibarButton>
225+
</div>
226+
);
227+
};
228+
Omnibar.style = css`
229+
:scope {
230+
z-index: 1;
231+
background: var(--bg01);
232+
display: flex;
233+
padding: 0 7px 0 7px;
234+
height: 2.5em;
235+
align-items: center;
236+
position: relative;
237+
gap: 0.2em;
238+
}
239+
240+
.downloadfly {
241+
position: absolute;
242+
top: 0;
243+
box-sizing: border-box;
244+
aspect-ratio: 1/1;
245+
align-items: center;
246+
justify-content: center;
247+
width: 100%;
248+
249+
display: flex;
250+
outline: none;
251+
border: none;
252+
font-size: 1.25em;
253+
background: none;
254+
color: var(--fg);
255+
border-radius: 0.2em;
256+
257+
transition: top 0.5s ease;
258+
}
259+
.downloadfly.down {
260+
top: 100vh;
261+
}
262+
.downloadfly::before {
263+
position: absolute;
264+
content: "";
265+
z-index: -1;
266+
height: 2em;
267+
width: 2em;
268+
border-radius: 50%;
269+
opacity: 0.5;
270+
background: var(--bg20);
271+
}
272+
`;

0 commit comments

Comments
 (0)