Skip to content

Commit

Permalink
Feat/inline url preview (#240)
Browse files Browse the repository at this point in the history
* #227: Move the HoverPopover spawning mechanism to the patched onLinkHover method

* omit the waitTime parameter of overPopover, set the time out in onLinkHover to 100ms

* fix: page preview enable and disable will cause core.json return {}

* fix: update

* fix: update

* fix: update

* feat: support live preview widget preview

* fix: update the fix of page preview, and revert the update to 0.9.5

* fix: conficts

* fix: conficts

* fix: conficts

* fix: conficts

* fix: conficts

* chore: remove unused code

* chore: bump version

* chore: bump version

* fix: cannot drag and drop when open tab tree

---------

Co-authored-by: RyotaUshio <ushio@ms.k.u-tokyo.ac.jp>
  • Loading branch information
Quorafind and RyotaUshio committed Apr 25, 2024
1 parent 7a95f43 commit a502a22
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 72 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "surfing",
"name": "Surfing",
"version": "0.9.9",
"version": "0.9.10",
"minAppVersion": "1.4.0",
"description": "Surf the Net in Obsidian.",
"author": "Boninall & Windily-cloud",
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "surfing",
"version": "0.9.9",
"version": "0.9.10",
"description": "Use surfing to surf the net in Obsidian.",
"main": "main.js",
"scripts": {
Expand All @@ -20,7 +20,7 @@
"@codemirror/language": "^6.2.1",
"@codemirror/state": "^6.1.2",
"@codemirror/view": "^6.3.0",
"@minoru/react-dnd-treeview": "^3.4.1",
"@minoru/react-dnd-treeview": "^3.4.4",
"@mui/icons-material": "^5.11.0",
"@popperjs/core": "^2.11.6",
"@rollup/plugin-commonjs": "^25.0.7",
Expand Down
131 changes: 73 additions & 58 deletions src/component/TabTreeView/TabTree.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import SurfingPlugin from "../../surfingIndex";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { DndProvider } from "react-dnd";
import {
Tree,
Expand All @@ -24,17 +24,23 @@ interface Props {
export const useDndProvider = () => {
const [dndArea, setDndArea] = useState<Node | undefined>();
const handleRef = React.useCallback((node: Node | undefined | null) => setDndArea(node as Node), []);

useEffect(() => {
const view = document.body.find(`div[data-type="surfing-tab-tree"]`);
setDndArea(view);
}, []);

const html5Options = React.useMemo(
() => ({ rootElement: dndArea }),
() => ({rootElement: dndArea}),
[dndArea]
);
return { dndArea, handleRef, html5Options };
return {dndArea, handleRef, html5Options};
};

export default function TabTree(props: Props) {
const [treeData, setTreeData] = useState<NodeModel<CustomData>[]>(props.plugin.settings.treeData || []);
const handleDrop = (newTree: NodeModel<CustomData>[]) => setTreeData(newTree);
const { dndArea, handleRef, html5Options } = useDndProvider();
const {dndArea, handleRef, html5Options} = useDndProvider();

const [selectedNode, setSelectedNode] = useState<NodeModel<CustomData> | null>(null);
const handleSelect = (node: NodeModel) => {
Expand Down Expand Up @@ -64,7 +70,7 @@ export default function TabTree(props: Props) {
}).open();
});
});
menu.showAtPosition({ x: e.clientX, y: e.clientY });
menu.showAtPosition({x: e.clientX, y: e.clientY});
};


Expand All @@ -82,7 +88,7 @@ export default function TabTree(props: Props) {
if (!treeData) return;
props.plugin.settings.treeData = treeData;
props.plugin.settingsTab.applySettingsUpdate();
}, [treeData])
}, [treeData]);

React.useEffect(() => {
if (treeData.length > 0) return;
Expand Down Expand Up @@ -118,14 +124,14 @@ export default function TabTree(props: Props) {
}
]);
(leaf.view as SurfingView).webviewEl.addEventListener("dom-ready", () => {
updateTabsData(leaf.view as SurfingView);
updateTabsData(leaf.view as SurfingView, '');
});
}
});
};
}, []);

const updateTabsData = React.useCallback((activeView: SurfingView) => {
const updateTabsData = React.useCallback((activeView: SurfingView, url: string) => {
//@ts-ignore
setTreeData((prevTreeData) => {
const existingNodeIndex = prevTreeData.findIndex(node => node.id === activeView.leaf.id);
Expand All @@ -136,7 +142,7 @@ export default function TabTree(props: Props) {
...prevTreeData.slice(0, existingNodeIndex),
{
...existingNode,
text: activeView.currentTitle,
text: url || activeView.currentTitle,
data: {
...existingNode.data,
icon: activeView.favicon,
Expand All @@ -152,7 +158,7 @@ export default function TabTree(props: Props) {
"id": activeView.leaf.id,
"parent": 0,
"droppable": true,
"text": activeView.currentTitle,
"text": url || activeView.currentTitle,
"data": {
"fileType": "site",
"fileSize": "",
Expand All @@ -168,78 +174,87 @@ export default function TabTree(props: Props) {
return !treeData.some(obj => obj.id === leafID);
};

props.plugin.app.workspace.on("layout-change", () => {
const activeView = props.plugin.app.workspace.getActiveViewOfType(ItemView);
if (activeView?.getViewType() === WEB_BROWSER_VIEW_ID && checkExist(activeView.leaf.id)) {
updateTabsData(activeView as SurfingView);
(activeView as SurfingView).webviewEl.addEventListener("dom-ready", () => {
updateTabsData(activeView as SurfingView);
});
return;
}
useEffect(() => {
props.plugin.app.workspace.on('surfing:page-change', (url: string, view: SurfingView) => {
if (checkExist(view.leaf.id)) {
updateTabsData(view, url);
}
});

const leaves = props.plugin.app.workspace.getLeavesOfType(WEB_BROWSER_VIEW_ID);
if (leaves.length === 0) {
setTreeData([]);
return;
}
});

props.plugin.app.workspace.on("layout-change", () => {
// const activeView = props.plugin.app.workspace.getActiveViewOfType(ItemView);
// if (activeView?.getViewType() === WEB_BROWSER_VIEW_ID && checkExist(activeView.leaf.id)) {
// updateTabsData(activeView as SurfingView);
// (activeView as SurfingView).webviewEl.addEventListener("dom-ready", () => {
// updateTabsData(activeView as SurfingView);
// });
// return;
// }

const leaves = props.plugin.app.workspace.getLeavesOfType(WEB_BROWSER_VIEW_ID);
if (leaves.length === 0) {
setTreeData([]);
return;
}
});
}, []);

return (
treeData.length > 0 ? (
<div ref={ handleRef } className={ styles.container }>
<DndProvider backend={ MultiBackend } options={ getBackendOptions(
<div ref={handleRef} className={styles.container}>
<DndProvider backend={MultiBackend} options={getBackendOptions(
{
html5: {
rootElement: dndArea
}
}
) }>
<div className={ styles.app } onContextMenu={ handleContextMenu }>
)}>
<div className={styles.app} onContextMenu={handleContextMenu}>
<Tree
tree={ treeData }
rootId={ 0 }
render={ (node, { depth, isOpen, hasChild, onToggle }) => (
tree={treeData}
rootId={0}
render={(node, {depth, isOpen, hasChild, onToggle}) => (
<CustomNode
node={ node }
depth={ depth }
isOpen={ isOpen }
onToggle={ onToggle }
hasChild={ hasChild }
isSelected={ node.id === selectedNode?.id }
onSelect={ handleSelect }
node={node}
depth={depth}
isOpen={isOpen}
onToggle={onToggle}
hasChild={hasChild}
isSelected={node.id === selectedNode?.id}
onSelect={handleSelect}
/>
) }
dragPreviewRender={ (monitorProps) => (
<CustomDragPreview monitorProps={ monitorProps }/>
) }
onDrop={ handleDrop }
classes={ {
)}
dragPreviewRender={(monitorProps) => (
<CustomDragPreview monitorProps={monitorProps}/>
)}
onDrop={handleDrop}
classes={{
root: styles.treeRoot,
draggingSource: styles.draggingSource,
placeholder: styles.placeholderContainer
} }
sort={ false }
insertDroppableFirst={ false }
canDrop={ (tree, { dragSource, dropTargetId }) => {
}}
sort={false}
insertDroppableFirst={false}
canDrop={(tree, {dragSource, dropTargetId}) => {
if (dragSource?.parent === dropTargetId) {
return true;
}
} }
dropTargetOffset={ 10 }
placeholderRender={ (node, { depth }) => (
<Placeholder node={ node } depth={ depth }/>
) }
}}
dropTargetOffset={10}
placeholderRender={(node, {depth}) => (
<Placeholder node={node} depth={depth}/>
)}
/>
</div>
</DndProvider>
</div>

) : (<div className={ `${ styles.app } tab-tree-empty-container` }>
<div className={ `tab-tree-empty-state` }>
<CrownTwoTone size={ 64 } width={ 64 } height={ 64 }/>
) : (<div className={`${styles.app} tab-tree-empty-container`}>
<div className={`tab-tree-empty-state`}>
<CrownTwoTone size={64} width={64} height={64}/>
<span>
{ "No surfing tabs open" }
{"No surfing tabs open"}
</span>
</div>
</div>)
Expand Down
12 changes: 6 additions & 6 deletions src/surfingIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export default class SurfingPlugin extends Plugin {
if (currentView.getViewType() != "empty" && currentView.getViewType() !== 'home-tab-view') return;
// Check if the "New tab" view has already been processed and has a header bar already.
if (!currentView.headerEl.children[2].hasClass("web-browser-header-bar")) {
const headerBar = new HeaderBar(currentView.headerEl.children[2], this, currentView);
const headerBar = new HeaderBar(currentView.titleContainerEl, this, currentView);
headerBar.onLoad();
// Focus on current inputEl
if (!this.settings.showSearchBarInPage) headerBar.focus();
Expand Down Expand Up @@ -194,9 +194,9 @@ export default class SurfingPlugin extends Plugin {
if (currentView.getViewType() != "empty" && currentView.getViewType() !== 'home-tab-view') return;

// Check if the "New tab" view has already been processed and has a header bar already.
if (currentView.headerEl.children[2].hasClass("wb-header-bar")) {
currentView.headerEl.children[2].empty();
currentView.headerEl.children[2].removeClass("wb-header-bar");
if (currentView.titleContainerEl.hasClass("wb-header-bar")) {
currentView.titleContainerEl.empty();
currentView.titleContainerEl.removeClass("wb-header-bar");
}

// Remove config icon
Expand Down Expand Up @@ -623,14 +623,14 @@ export default class SurfingPlugin extends Plugin {
onLinkHover(old: any) {
return function (hoverParent: HoverParent, targetEl: HTMLElement | null, linktext: string, sourcePath: string, state: any, ...args: any[]) {
if (linktext.startsWith('http://') || linktext.startsWith('https://')) {

let { hoverPopover } = hoverParent;

if (hoverPopover && hoverPopover.state !== (PopoverState as any).Hidden && hoverPopover.targetEl === targetEl) {
return;
}
hoverPopover = new HoverPopover(hoverParent, targetEl);
hoverPopover.hoverEl.addClass('surfing-hover-popover');

setTimeout(() => {
if (hoverPopover!.state !== (PopoverState as any).Hidden) {
const parentEl = hoverPopover!.hoverEl.createDiv('surfing-hover-popover-container');
Expand Down
6 changes: 5 additions & 1 deletion src/surfingView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ export class SurfingView extends ItemView {
if (this.omnisearchEnabled) this.updateSearchBox();
this.leaf.tabHeaderInnerTitleEl.innerText = event.title;
this.currentTitle = event.title;


this.app.workspace.trigger('surfing:page-change', event.title, this);
});

this.webviewEl.addEventListener("will-navigate", (event: any) => {
Expand Down Expand Up @@ -376,7 +379,7 @@ export class SurfingView extends ItemView {
this.navigation = true;

// Create search bar in the header bar.
this.headerBar = new HeaderBar(this.headerEl.children[2], this.plugin, this, true);
this.headerBar = new HeaderBar(this.titleContainerEl, this.plugin, this, true);
this.headerBar.onLoad();

// Create favicon image element.
Expand Down Expand Up @@ -971,6 +974,7 @@ export class SurfingView extends ItemView {
}
}


// TODO: move this to utils.ts
// Support both http:// and https://
// TODO: ?Should we support Localhost?
Expand Down
15 changes: 12 additions & 3 deletions src/types/obsidian.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import * as obsidian from 'obsidian';
import { EditorPosition, MarkdownPreviewRenderer, Scope } from "obsidian";
import { EditorPosition, EventRef, MarkdownPreviewRenderer, Scope } from "obsidian";
import { SurfingView } from "../surfingView";

declare module "obsidian" {
export interface ItemView {
headerEl: HTMLDivElement;
titleContainerEl: HTMLDivElement;
}

interface FileView {
allowNoFile: boolean;
}

interface FileView {
Expand Down Expand Up @@ -42,8 +48,7 @@ declare module "obsidian" {
}

interface HoverPopover {

targetEl: HTMLElement;
targetEl: HTMLElement;

hide(): void;

Expand Down Expand Up @@ -72,6 +77,10 @@ declare module "obsidian" {
setDimension: (dimension: any) => void;
}

interface Workspace {
on(name: 'surfing:page-change', callback: (url: string, view: SurfingView) => any, ctx?: any): EventRef;
}

export interface WorkspaceItem {
type: string;
}
Expand Down
21 changes: 21 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -1982,3 +1982,24 @@ div[data-type^="surfing-tab-tree"] ul li {
.popover.hover-editor .popover-content:has(div[data-type^="surfing-view"]) {
width: 100%;
}

.cm-browser-widget {
border: 1px solid var(--background-modifier-border);
}

.cm-browser-widget .wb-browser-inline {
height: max(4vw, 400px);
}

.cm-browser-widget .wb-show-original-code {
position: absolute;
right: var(--size-4-2);
top: var(--size-4-2);
visibility: hidden;
}

.cm-browser-widget:hover .wb-show-original-code {
visibility: visible;
}


3 changes: 2 additions & 1 deletion versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@
"0.9.4": "1.4.0",
"0.9.5": "1.4.0",
"0.9.8": "1.4.0",
"0.9.9": "1.4.0"
"0.9.9": "1.4.0",
"0.9.10": "1.4.0"
}

0 comments on commit a502a22

Please sign in to comment.