Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 132 additions & 19 deletions packages/chrome/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { FC } from "dreamland/core";
import { css } from "dreamland/core";
import { TabStrip } from "@components/TabStrip/TabStrip";
import { Sidebar } from "@components/TabStrip/Sidebar";
import { Tab } from "./Tab/Tab";
import { BookmarksStrip } from "@components/BookmarksStrip";
import { Omnibar } from "@components/Omnibar/Omnibar";
Expand All @@ -10,6 +11,19 @@ import { INTERNAL_URL_PROTOCOL } from "./consts";
import { Shell } from "@components/Shell";
import { settingsService, tabsService } from ".";

const DEFAULT_HYBRID_SIDEBAR_WIDTH = 225;
const DEFAULT_VERTICAL_SIDEBAR_WIDTH = 280;

function getSidebarWidth(
layout: "horizontal" | "bottom" | "hybrid" | "vertical" | "compact",
savedWidth: number | null
) {
if (savedWidth !== null) return savedWidth;
return layout === "vertical"
? DEFAULT_VERTICAL_SIDEBAR_WIDTH
: DEFAULT_HYBRID_SIDEBAR_WIDTH;
}

export function App(
this: FC<
{},
Expand Down Expand Up @@ -57,6 +71,25 @@ export function App(

applyProfile();

const applyLayout = () => {
const layout = settingsService.settings.tabLayout;
document.body.classList.toggle("layout-bottom", layout === "bottom");
document.body.classList.toggle("layout-compact", layout === "compact");
const verticalTabs = layout === "hybrid" || layout === "vertical";
document.body.classList.toggle("vertical-tabs", verticalTabs);
document.body.classList.toggle("full-vertical-tabs", layout === "vertical");
document.body.classList.toggle(
"sidebar-left",
settingsService.settings.verticalTabJustify === "left"
);
document.body.classList.toggle(
"sidebar-right",
settingsService.settings.verticalTabJustify === "right"
);
};

applyLayout();

const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleThemeChange = () => {
if (settingsService.settings.appearance === "system") {
Expand All @@ -70,32 +103,100 @@ export function App(
use(settingsService.settings.themeId).listen(applyTheme);

use(settingsService.settings.uiProfile).listen(applyProfile);
use(settingsService.settings.tabLayout).listen(applyLayout);
use(settingsService.settings.verticalTabJustify).listen(applyLayout);

this.cx.mount = () => {
applyTheme();
};

return (
<div id="app">
<TabStrip
tabs={use(tabsService.tabs)}
activetab={use(tabsService.activetab)}
addTab={() => {
tabsService.newTab(new URL(`${INTERNAL_URL_PROTOCOL}//newtab`), true);
}}
destroyTab={(tab: Tab) => {
tabsService.destroyTab(tab);
}}
/>
<Omnibar tab={use(tabsService.activetab)} />
{use(tabsService.activetab.url, settingsService.settings.showBookmarksBar)
.map(
([u, pinned]) =>
pinned || u.href === `${INTERNAL_URL_PROTOCOL}//newtab`
<div
id="app"
class={use(settingsService.settings.tabLayout).map((layout) =>
[
layout === "hybrid" || layout === "vertical" ? "vertical-tabs" : "",
`layout-${layout}`,
]
.filter(Boolean)
.join(" ")
)}
>
{use(settingsService.settings.tabLayout).map((layout) =>
layout === "hybrid" || layout === "vertical" ? (
<Sidebar
layout={layout}
justify={use(settingsService.settings.verticalTabJustify)}
tabs={use(tabsService.tabs)}
activetab={use(tabsService.activetab)}
sidebarWidth={use(
settingsService.settings.tabLayout,
settingsService.settings.sidebarWidth
).map(([currentLayout, sidebarWidth]) =>
getSidebarWidth(currentLayout, sidebarWidth)
)}
setSidebarWidth={(width: number) => {
settingsService.settings.sidebarWidth = Math.round(width);
}}
addTab={() => {
tabsService.newTab(
new URL(`${INTERNAL_URL_PROTOCOL}//newtab`),
true
);
}}
destroyTab={(tab: Tab) => {
tabsService.destroyTab(tab);
}}
topContent={
layout === "vertical" ? (
<div class="vertical-sidebar-header">
<Omnibar tab={use(tabsService.activetab)} layout="vertical" />
<div class="vertical-sidebar-bookmarks">
<BookmarksStrip orientation="vertical" />
</div>
</div>
) : null
}
/>
) : layout === "compact" ? null : (
<TabStrip
tabs={use(tabsService.tabs)}
activetab={use(tabsService.activetab)}
addTab={() => {
tabsService.newTab(
new URL(`${INTERNAL_URL_PROTOCOL}//newtab`),
true
);
}}
destroyTab={(tab: Tab) => {
tabsService.destroyTab(tab);
}}
/>
)
.and(<BookmarksStrip />)}
<div class="separator"></div>
{this.children}
)}
<div id="main">
{use(settingsService.settings.tabLayout).map((layout) =>
layout === "vertical" ? null : (
<>
<Omnibar
tab={use(tabsService.activetab)}
layout={layout === "compact" ? "compact" : "horizontal"}
/>
{use(
tabsService.activetab.url,
settingsService.settings.showBookmarksBar
)
.map(
([u, pinned]) =>
pinned || u.href === `${INTERNAL_URL_PROTOCOL}//newtab`
)
.and(<BookmarksStrip />)}
<div class="separator"></div>
</>
)
)}
{this.children}
</div>
</div>
);
}
Expand All @@ -104,6 +205,7 @@ App.style = css`
background-color: var(--frame);
--separator-color: color-mix(in srgb, currentColor 10%, transparent);
}

.separator {
color: var(--toolbar);
position: relative;
Expand All @@ -112,6 +214,17 @@ App.style = css`
/*box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);*/
border-top: 1px solid var(--text-15);
}

.vertical-sidebar-header {
display: flex;
flex-direction: column;
gap: 0.75rem;
}

.vertical-sidebar-bookmarks {
padding-bottom: 0.25rem;
border-bottom: 1px solid var(--text-10);
}
`;

const app = document.getElementById("app")!;
Expand Down
3 changes: 3 additions & 0 deletions packages/chrome/src/Tab/Tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ export class Tab extends StatefulClass {
// only caller should be history.ts for this
_directnavigate(url: URL) {
this.url = url;
this.icon = "/defaultfavicon.png";
if (url.protocol == INTERNAL_URL_PROTOCOL) {
this.icon = null;
this.history.current().favicon = "/icon.png";
switch (url.host) {
case "newtab":
this.history.current().title = this.title = "New Tab";
Expand Down
35 changes: 30 additions & 5 deletions packages/chrome/src/components/BookmarksStrip.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { createState, css, type FC } from "dreamland/core";
import { Icon } from "@components/Icon";
import { css, type FC } from "dreamland/core";
import { iconAdd, iconOpen, iconLink, iconBrush, iconTrash } from "../icons";
import { createMenu, createMenuCustom, setContextMenu } from "@components/Menu";
import { BookmarkPopup } from "@components/BookmarkPopup";
import { profileService, settingsService, tabsService } from "..";

export function BookmarksStrip(this: FC<{}>) {
export function BookmarksStrip(
this: FC<{
orientation?: "horizontal" | "vertical";
}>
) {
this.orientation ??= "horizontal";

this.cx.mount = () => {
setContextMenu(this.root, [
{
Expand All @@ -20,7 +25,7 @@ export function BookmarksStrip(this: FC<{}>) {
]);
};
return (
<div>
<div class:vertical={this.orientation === "vertical"}>
{use(profileService.bookmarks).mapEach((b) => (
<button
on:auxclick={(e: MouseEvent) => {
Expand Down Expand Up @@ -84,11 +89,19 @@ BookmarksStrip.style = css`
:scope {
padding: 0.25em;
padding-left: 0.5em;
height: 2em;
display: flex;
gap: 0.5em;
background: var(--toolbar);
color: var(--toolbar_text);
height: 2em;
}

:scope.vertical {
padding: 0;
height: auto;
flex-direction: column;
gap: 0.35em;
background: none;
}

button {
Expand All @@ -102,11 +115,23 @@ BookmarksStrip.style = css`
border-radius: 3px;
color: var(--toolbar_text);
}

:scope.vertical button {
width: 100%;
height: auto;
min-height: var(--tab-height);
padding: 0.6em 0.75em;
border-radius: calc(var(--radius) + 1px);
background: var(--toolbar_field);
}

button:hover {
background: var(--toolbarbutton-hover-background);
}
button span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

button img {
Expand Down
9 changes: 9 additions & 0 deletions packages/chrome/src/components/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export function Checkbox(
this: FC<{
value: boolean;
id?: string;
disabled?: boolean;
"on:change"?: (value: boolean) => void;
}>
) {
Expand All @@ -13,6 +14,7 @@ export function Checkbox(
type="checkbox"
id={use(this.id)}
checked={use(this.value)}
disabled={use(this.disabled).map((v) => (v ? true : undefined))}
onChange={(e) => this["on:change"]?.(e.target.checked)}
></input>
</label>
Expand All @@ -33,6 +35,7 @@ Checkbox.style = css`
background 120ms ease,
border-color 120ms ease;
box-sizing: border-box;
margin: 0;
}

:scope::after {
Expand Down Expand Up @@ -67,6 +70,12 @@ Checkbox.style = css`
transform: scale(1) translateY(0.5px);
}

:scope:has(input:disabled) {
opacity: 0.5;
filter: grayscale(100%);
cursor: not-allowed;
}

input {
visibility: hidden;
display: block;
Expand Down
13 changes: 12 additions & 1 deletion packages/chrome/src/components/Favicon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,18 @@ export function Favicon(
this.domain = this.domain;
this.iconUrl = this.iconUrl;

return <img src={use(this.url)} class={use(this.size)}></img>;
return (
<img
src={use(this.url)}
width={use(this.size).map((s) =>
s === "small" ? 16 : s === "medium" ? 32 : 64
)}
height={use(this.size).map((s) =>
s === "small" ? 16 : s === "medium" ? 32 : 64
)}
class={use(this.size)}
></img>
);
}
Favicon.style = css`
:scope.small {
Expand Down
10 changes: 5 additions & 5 deletions packages/chrome/src/components/Omnibar/BookmarkButton.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { createState, css, type FC } from "dreamland/core";
import { OmnibarButton } from "@components/Omnibar/OmnibarButton";
import { css, type FC } from "dreamland/core";
import { createMenuCustom } from "@components/Menu";
import { BookmarkPopup } from "@components/BookmarkPopup";
import { emToPx } from "../../util";

import { iconStar, iconStarFilled } from "../../icons";
import { Icon } from "@components/Icon";
Expand All @@ -15,6 +13,8 @@ export function BookmarkButton(this: FC<{ url: URL }>) {
on:click={(e) => {
e.stopPropagation();
e.preventDefault();
const target = e.currentTarget as HTMLElement;
const rect = target.getBoundingClientRect();
let bookmark = profileService.bookmarks.find(
(b) => b.url.href == this.url.href
);
Expand All @@ -32,8 +32,8 @@ export function BookmarkButton(this: FC<{ url: URL }>) {

createMenuCustom(
{
right: (e.target as HTMLElement).getBoundingClientRect().right,
top: emToPx(2.5) + 40,
right: rect.right,
top: rect.bottom + 6,
},
<BookmarkPopup new={isnew} bookmark={bookmark}></BookmarkPopup>
);
Expand Down
Loading