Skip to content

Commit bd4e355

Browse files
committed
[frontend] refactor and only show downloads icon if there are downloads this session
1 parent d4e65a1 commit bd4e355

File tree

3 files changed

+245
-237
lines changed

3 files changed

+245
-237
lines changed

frontend/src/Browser.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { focusOmnibox } from "./components/UrlInput";
88

99
import * as tldts from "tldts";
1010
import { scramjet } from "./main";
11-
import { animateDownloadFly, showDownloadsPopup } from "./components/Omnibox";
11+
import { animateDownloadFly } from "./components/Omnibox";
12+
import { showDownloadsPopup } from "./components/DownloadsPopup";
1213
export const pushTab = createDelegate<Tab>();
1314
export const popTab = createDelegate<Tab>();
1415
export const forceScreenshot = createDelegate<Tab>();
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import { css, type Component } from "dreamland/core";
2+
import { browser } from "../Browser";
3+
import { Icon } from "./Icon";
4+
import { closeMenu, createMenuCustom } from "./Menu";
5+
import iconClose from "@ktibow/iconset-ion/close";
6+
import iconFolder from "@ktibow/iconset-ion/folder-outline";
7+
import iconOpen from "@ktibow/iconset-ion/open-outline";
8+
import iconPause from "@ktibow/iconset-ion/pause-outline";
9+
import { formatBytes } from "../pages/DownloadsPage";
10+
11+
export const DownloadsPopup: Component<{}> = function (cx) {
12+
return (
13+
<div>
14+
<div class="title">
15+
<span>Recent Downloads</span>
16+
<div class="buttoniconcontainer">
17+
<button
18+
on:click={() => {
19+
closeMenu();
20+
}}
21+
>
22+
<Icon icon={iconClose}></Icon>
23+
</button>
24+
</div>
25+
</div>
26+
<div class="entries">
27+
{use(browser.sessionDownloadHistory).mapEach((b) => (
28+
<div class="entry">
29+
<div class="iconcontainer">
30+
<img src="/defaultfavicon.png"></img>
31+
</div>
32+
<div class="contents">
33+
<span>{b.filename}</span>
34+
{use(b.progressbytes).andThen(
35+
<span class="data">
36+
{use(b.progressbytes).map((s) => formatBytes(s!))}/
37+
{formatBytes(b.size)}
38+
</span>
39+
)}
40+
{use(b.progressbytes)
41+
.map((b) => !b)
42+
.andThen(<span class="data">{formatBytes(b.size)}</span>)}
43+
{use(b.progress).andThen(
44+
<progress value={use(b.progress).map((p) => p || 0)} max="1">
45+
50%
46+
</progress>
47+
)}
48+
</div>
49+
<div class="buttoniconcontainer">
50+
{use(b.progress)
51+
.map((b) => !b)
52+
.andThen(
53+
<>
54+
<button>
55+
<Icon icon={iconFolder}></Icon>
56+
</button>
57+
<button>
58+
<Icon icon={iconOpen}></Icon>
59+
</button>
60+
</>
61+
)}
62+
{use(b.progress).andThen(
63+
<>
64+
<button
65+
on:click={() => {
66+
b.pause!();
67+
}}
68+
>
69+
<Icon icon={iconPause}></Icon>
70+
</button>
71+
<button
72+
on:click={() => {
73+
b.cancel!();
74+
}}
75+
>
76+
<Icon icon={iconClose}></Icon>
77+
</button>
78+
</>
79+
)}
80+
</div>
81+
</div>
82+
))}
83+
</div>
84+
<div
85+
class="footer"
86+
on:click={() => {
87+
browser.newTab(new URL("puter://downloads"));
88+
closeMenu();
89+
}}
90+
>
91+
<span>Full Download History</span>
92+
<div class="buttoniconcontainer">
93+
<Icon icon={iconOpen}></Icon>
94+
</div>
95+
</div>
96+
</div>
97+
);
98+
};
99+
DownloadsPopup.style = css`
100+
:scope {
101+
width: 20em;
102+
display: flex;
103+
flex-direction: column;
104+
user-select: none;
105+
}
106+
107+
.title {
108+
padding: 1em;
109+
display: flex;
110+
border-bottom: 1px solid var(--fg4);
111+
}
112+
.title p {
113+
font-size: 1.25em;
114+
}
115+
.title button {
116+
display: flex;
117+
align-items: center;
118+
font-size: 1em;
119+
position: relative;
120+
}
121+
.title button:hover::before {
122+
content: "";
123+
z-index: -1;
124+
position: absolute;
125+
width: 150%;
126+
height: 150%;
127+
top: 50%;
128+
left: 50%;
129+
transform: translate(-50%, -50%);
130+
background: var(--bg20);
131+
border-radius: 50%;
132+
}
133+
134+
.entries {
135+
max-height: 30em;
136+
display: flex;
137+
flex-direction: column;
138+
overflow-y: auto;
139+
overflow-x: hidden;
140+
}
141+
142+
.entry {
143+
padding: 1em;
144+
display: flex;
145+
gap: 1em;
146+
font-size: 0.9em;
147+
position: relative;
148+
}
149+
.entry:hover {
150+
background: var(--bg20);
151+
}
152+
.contents {
153+
display: flex;
154+
overflow: hidden;
155+
flex-direction: column;
156+
gap: 0.5em;
157+
}
158+
.entry .buttoniconcontainer {
159+
display: none;
160+
}
161+
.entry:hover .buttoniconcontainer {
162+
display: flex;
163+
}
164+
.entry .buttoniconcontainer {
165+
position: absolute;
166+
right: 0;
167+
top: 0;
168+
padding: 1em;
169+
background: var(--bg20);
170+
height: 100%;
171+
align-items: start;
172+
gap: 1em;
173+
}
174+
.entry .buttoniconcontainer button {
175+
font-size: 1.15em;
176+
position: relative;
177+
z-index: 1;
178+
display: flex;
179+
}
180+
.entry .buttoniconcontainer button:hover::before {
181+
content: "";
182+
z-index: -1;
183+
position: absolute;
184+
width: 150%;
185+
height: 150%;
186+
top: 50%;
187+
left: 50%;
188+
transform: translate(-50%, -50%);
189+
background: var(--fg4);
190+
border-radius: 50%;
191+
}
192+
193+
.contents .data {
194+
color: var(--fg2);
195+
}
196+
.footer {
197+
border-top: 1px solid var(--fg4);
198+
padding: 1em;
199+
cursor: pointer;
200+
display: flex;
201+
align-items: center;
202+
}
203+
.footer:hover {
204+
background: var(--bg20);
205+
}
206+
207+
.buttoniconcontainer {
208+
flex: 1;
209+
display: flex;
210+
justify-content: right;
211+
}
212+
`;
213+
214+
export function showDownloadsPopup() {
215+
createMenuCustom(
216+
window.innerWidth - 350,
217+
80,
218+
<DownloadsPopup></DownloadsPopup>
219+
);
220+
}

0 commit comments

Comments
 (0)