From 5c676f06d8d78129444bfb86d36f0eb5f88bbd43 Mon Sep 17 00:00:00 2001
From: FelisDiligens <47528453+FelisDiligens@users.noreply.github.com>
Date: Tue, 2 May 2023 09:46:08 +0200
Subject: [PATCH 1/2] Remove iframe border
---
src/iframe.css | 8 ++++++++
src/index.ts | 5 +++++
2 files changed, 13 insertions(+)
create mode 100644 src/iframe.css
diff --git a/src/iframe.css b/src/iframe.css
new file mode 100644
index 0000000..bf515db
--- /dev/null
+++ b/src/iframe.css
@@ -0,0 +1,8 @@
+/*
+ Remove the bottom border for plugin iframes,
+ such that the tabs can "connect" to the rest of Joplin's UI.
+*/
+
+iframe {
+ border-bottom: none !important;
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index d6a94a2..752326b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -23,6 +23,11 @@ joplin.plugins.register({
// panel
const panel = new Panel(tabs, settings);
await panel.register();
+ // custom CSS (to disable iframe border)
+ // source: https://github.com/andrejilderda/joplin-macos-native-theme/blob/main/src/index.ts#LL22C5-L22C5
+ const installDir = await joplin.plugins.installationDir();
+ const cssFilePath = installDir + '/iframe.css';
+ await (joplin as any).window.loadChromeCssFile(cssFilePath);
//#region HELPERS
From 28166a294ceb14b5721c5af3ef44793da2579a81 Mon Sep 17 00:00:00 2001
From: FelisDiligens <47528453+FelisDiligens@users.noreply.github.com>
Date: Tue, 2 May 2023 09:48:55 +0200
Subject: [PATCH 2/2] Style tabs to resemble Chrome's
---
src/panel.ts | 39 ++++++++++++++++-
src/settings.ts | 10 +++--
src/webview.css | 70 +++++++++++++++++++++++++++----
src/webview_auto.css | 8 ++++
src/webview_horizontal_bottom.css | 33 +++++++++++++++
src/webview_vertical.css | 8 ++++
6 files changed, 153 insertions(+), 15 deletions(-)
create mode 100644 src/webview_horizontal_bottom.css
diff --git a/src/panel.ts b/src/panel.ts
index 648e650..3fc78de 100644
--- a/src/panel.ts
+++ b/src/panel.ts
@@ -46,6 +46,9 @@ export class Panel {
if (this.sets.hasLayoutMode(LayoutMode.Vertical)) {
await joplin.views.panels.addScript(this._panel, './webview_vertical.css');
}
+ if (this.sets.hasLayoutMode(LayoutMode.HorizontalBottom)) {
+ await joplin.views.panels.addScript(this._panel, './webview_horizontal_bottom.css');
+ }
await joplin.views.panels.addScript(this._panel, './webview.js');
// message handler
@@ -172,6 +175,15 @@ export class Panel {
const iconTitle: string = (NoteTabs.isPinned(noteTab)) ? 'Unpin' : 'Pin';
const textDecoration: string = (note.is_todo && note.todo_completed) ? 'line-through' : '';
+ // prepare tab style CSS
+ const tabStyle = `
+ height: ${this.sets.tabHeight}px;
+ min-width: ${this.sets.minTabWidth}px;
+ max-width: ${this.sets.maxTabWidth}px;
+ border-color: ${this.sets.dividerColor};
+ background: ${bg};
+ `.replace(/[\n\s]+/g, ""); // remove whitespace
+
// prepare checkbox for todo
let checkboxHtml: string = '';
if (this.sets.showTodoCheckboxes && note.is_todo) {
@@ -182,7 +194,7 @@ export class Panel {
+ style="${tabStyle}">
${checkboxHtml}
@@ -308,17 +320,40 @@ export class Panel {
const noteTabsHtml: string = await this.getNoteTabsHtml(selectedNote);
const controlsHtml: string = this.getControlsHtml();
const infoBarHtml: string = await this.getInfoBarHtml(selectedNote);
+ const placedBelow: boolean = this.sets.hasLayoutMode(LayoutMode.HorizontalBottom);
+
+ const tabBeforeAfterStyle = `
+
+ `;
// add entries to container and push to panel
await joplin.views.panels.setHtml(this._panel, `
+ ${placedBelow ? infoBarHtml : ""}
${noteTabsHtml}
${controlsHtml}
- ${infoBarHtml}
+ ${!placedBelow ? infoBarHtml : ""}
+ ${tabBeforeAfterStyle}
`);
}
diff --git a/src/settings.ts b/src/settings.ts
index f741f27..b8c3bec 100644
--- a/src/settings.ts
+++ b/src/settings.ts
@@ -32,7 +32,8 @@ export enum UnpinBehavior {
export enum LayoutMode {
Auto,
- Horizontal,
+ HorizontalTop,
+ HorizontalBottom,
Vertical
}
@@ -54,7 +55,7 @@ export class Settings {
private _unpinBehavior: UnpinBehavior = UnpinBehavior.Keep;
private _layoutMode: number = LayoutMode.Auto;
// advanced settings
- private _tabHeight: number = 35;
+ private _tabHeight: number = 30;
private _minTabWidth: number = 50;
private _maxTabWidth: number = 150;
private _breadcrumbsMaxWidth: number = 100;
@@ -298,8 +299,9 @@ export class Settings {
description: 'Force tabs horizontal or vertical layout. If Auto, the layout switches automatically at a width of about 400px. Requires restart to be applied.',
options: {
'0': 'Auto',
- '1': 'Horizontal',
- '2': 'Vertical'
+ '1': 'Horizontal (tabs above)',
+ '2': 'Horizontal (tabs below)',
+ '3': 'Vertical'
}
},
// advanced settings
diff --git a/src/webview.css b/src/webview.css
index 28c70be..0f48977 100644
--- a/src/webview.css
+++ b/src/webview.css
@@ -9,15 +9,20 @@ body > div,
div#joplin-plugin-content {
height: 100%;
}
+
a {
text-decoration: none;
}
+
span {
cursor: default;
}
/* HORIZONTAL LAYOUT */
#container {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
height: 100%;
overflow-x: hidden;
overflow-y: overlay;
@@ -26,40 +31,69 @@ span {
#tabs-container {
display: flex;
+ align-items: flex-end;
+ flex-grow: 1;
+ /*padding: 0px 5px 0 5px;*/
float: left;
overflow-x: overlay;
+ overflow-y: hidden;
width: 100%;
}
+
#tab {
- border-style: solid;
- border-width: 0;
- border-right-width: 1px;
display: flex;
+ position: relative;
padding: 0 8px;
transition: 0.2s;
+ flex-grow: 1;
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
}
+
#tab .fas {
margin-left: auto;
margin-right: 0;
padding: 2px;
- visibility: hidden;
}
-#tab:hover .fas {
- visibility: visible;
+
+#tab[active]:before,
+#tab[active]:after {
+ position: absolute;
+ bottom: -1px;
+ width: 6px;
+ height: 6px;
+ content: " ";
+ transition: 0.2s;
+}
+
+#tab[active]:before {
+ z-index: 1;
+ left: -6px;
+ border-bottom-right-radius: 6px;
+}
+
+#tab[active]:after {
+ z-index: 1;
+ right: -6px;
+ border-bottom-left-radius: 6px;
}
+
.new {
font-style: italic;
}
+
.tab-inner {
align-items: center;
display: flex;
height: 100%;
width: 100%;
}
-.tab-inner > input {
+
+.tab-inner>input {
margin: 0;
margin-right: 3px;
}
+
.tab-title {
overflow: hidden;
padding-right: 3px;
@@ -75,6 +109,7 @@ span {
margin-left: auto;
margin-right: 0;
}
+
#controls .fas {
align-items: center;
display: flex;
@@ -86,6 +121,7 @@ span {
opacity: 0.8;
width: 26px;
}
+
#controls .fas:hover {
opacity: 1;
}
@@ -96,9 +132,11 @@ span {
height: var(--infobarHeight);
width: 100%;
}
+
#infobar-container .fas {
font-size: 1.3em;
}
+
#infobar-container .fas.fa-book {
font-size: 1.2em;
}
@@ -111,10 +149,12 @@ span {
min-width: fit-content;
padding: 0 4px;
}
+
.navigation-icons a:hover {
background: var(--joplin-background-color-hover3);
border-radius: 3px;
}
+
.navigation-icons .fas {
line-height: calc(var(--infobarHeight) - 2px);
min-width: 12px;
@@ -129,20 +169,24 @@ span {
min-width: fit-content;
padding: 0 4px;
}
+
.checklist-state-inner {
align-items: center;
display: flex;
line-height: calc(var(--infobarHeight) - 2px);
}
+
.checklist-state-text {
align-items: center;
display: flex;
margin: 0 2px;
padding: 0 4px;
}
-.checklist-state-text > .fas {
+
+.checklist-state-text>.fas {
padding-right: 4px;
}
+
.checklist-state-text.completed {
background: #46ba61;
color: white;
@@ -153,6 +197,7 @@ span {
margin: auto 0;
padding-left: 8px;
}
+
#breadcrumbs-container {
display: flex;
float: left;
@@ -160,28 +205,34 @@ span {
overflow-y: hidden;
width: 100%;
}
+
.breadcrumb {
display: flex;
height: var(--infobarHeight);
min-width: 36px;
}
+
.breadcrumb:last-of-type .fas {
display: none;
}
+
.breadcrumb-inner {
align-items: center;
display: flex;
line-height: calc(var(--infobarHeight) - 2px);
width: 100%;
}
+
.breadcrumb-inner a:hover {
background: var(--joplin-background-color-hover3);
border-radius: 3px;
}
+
.breadcrumb-inner .fas {
margin-left: auto;
margin-right: 0px;
}
+
.breadcrumb-title {
margin: 0 2px;
overflow: hidden;
@@ -206,7 +257,8 @@ span {
height: 4px;
width: 7px;
}
+
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.2);
border-radius: 5px;
-}
+}
\ No newline at end of file
diff --git a/src/webview_auto.css b/src/webview_auto.css
index 3ece6d7..074764d 100644
--- a/src/webview_auto.css
+++ b/src/webview_auto.css
@@ -3,14 +3,22 @@
#tabs-container {
display: block;
height: 100%;
+ padding: 0;
}
#tab {
border-right-width: 0;
border-bottom-width: 1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
max-width: 100% !important;
}
+ #tab[active]:before,
+ #tab[active]:after {
+ visibility: hidden;
+ }
+
#breadcrumbs-container {
display: none !important;
}
diff --git a/src/webview_horizontal_bottom.css b/src/webview_horizontal_bottom.css
new file mode 100644
index 0000000..2853bd9
--- /dev/null
+++ b/src/webview_horizontal_bottom.css
@@ -0,0 +1,33 @@
+/*
+ If the user places the tabs on the bottom,
+ we want to make the tabs connect to the upper border instead.
+*/
+
+#container {
+ align-items: flex-start;
+}
+
+#tabs-container {
+ align-items: flex-start;
+}
+
+#tab {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: 8px;
+ border-bottom-right-radius: 8px;
+}
+
+#tab[active]:before {
+ top: 0;
+ left: -6px;
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 0;
+}
+
+#tab[active]:after {
+ top: 0;
+ right: -6px;
+ border-top-left-radius: 6px;
+ border-bottom-left-radius: 0;
+}
\ No newline at end of file
diff --git a/src/webview_vertical.css b/src/webview_vertical.css
index 88831f9..8220b2a 100644
--- a/src/webview_vertical.css
+++ b/src/webview_vertical.css
@@ -2,14 +2,22 @@
#tabs-container {
display: block;
height: 100%;
+ padding: 0;
}
#tab {
border-right-width: 0;
border-bottom-width: 1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
max-width: 100% !important;
}
+#tab[active]:before,
+#tab[active]:after {
+ visibility: hidden;
+}
+
#breadcrumbs-container {
display: none !important;
}