Compare commits

..

No commits in common. "master" and "3.5.1" have entirely different histories.

8 changed files with 1371 additions and 3073 deletions

View file

@ -1,10 +1,15 @@
{
"id": "float-search",
"name": "Floating Search",
"version": "4.3.0",
"minAppVersion": "1.2.0",
"version": "3.5.1",
"minAppVersion": "0.15.0",
"description": "You can use search view in modal/leaf/popout window now.",
"author": "Boninall",
"authorUrl": "https://github.com/Quorafind",
"fundingUrl": {
"Buy Me a Coffee": "https://www.buymeacoffee.com/boninall",
"爱发电": "https://afdian.net/a/boninall",
"支付宝": "https://cdn.jsdelivr.net/gh/Quorafind/.github@main/IMAGE/%E6%94%AF%E4%BB%98%E5%AE%9D%E4%BB%98%E6%AC%BE%E7%A0%81.jpg"
},
"isDesktopOnly": false
}

View file

@ -1,6 +1,6 @@
{
"name": "float-search",
"version": "4.3.0",
"version": "3.5.1",
"description": "You can use search view in modal/leaf/popout window now.",
"main": "main.js",
"scripts": {
@ -17,7 +17,7 @@
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
"esbuild": "0.14.47",
"obsidian": "^1.12.3",
"obsidian": "latest",
"tslib": "2.4.0",
"typescript": "4.7.4"
},

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -53,7 +53,7 @@ function nosuper<T>(base: new (...args: unknown[]) => T): new () => T {
export const spawnLeafView = (plugin: FloatSearchPlugin, initiatingEl?: HTMLElement, leaf?: WorkspaceLeaf, onShowCallback?: () => unknown): [WorkspaceLeaf, EmbeddedView] => {
// When Obsidian doesn't set any leaf active, use leaf instead.
let parent = plugin.app.workspace.activeLeaf as unknown as EmbeddedViewParent;
let parent = app.workspace.activeLeaf as unknown as EmbeddedViewParent;
if (!parent) parent = leaf as unknown as EmbeddedViewParent;
if (!initiatingEl) initiatingEl = parent?.containerEl;
@ -72,7 +72,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
detaching = false;
opening = false;
rootSplit: WorkspaceSplit = new (WorkspaceSplit as ConstructableWorkspaceSplit)(this.plugin.app.workspace, "vertical");
rootSplit: WorkspaceSplit = new (WorkspaceSplit as ConstructableWorkspaceSplit)(window.app.workspace, "vertical");
isPinned = true;
@ -86,16 +86,16 @@ export class EmbeddedView extends nosuper(HoverPopover) {
document: Document = this.targetEl?.ownerDocument ?? window.activeDocument ?? window.document;
id = genId(8);
bounce?: number;
bounce?: NodeJS.Timeout;
boundOnZoomOut: () => void;
originalPath: string; // these are kept to avoid adopting targets w/a different link
originalLinkText: string;
static activePopover?: EmbeddedView;
static activeWindows(plugin: FloatSearchPlugin) {
static activeWindows() {
const windows: Window[] = [window];
const {floatingSplit} = plugin.app.workspace;
const {floatingSplit} = app.workspace;
if (floatingSplit) {
for (const split of floatingSplit.children) {
if (split.win) windows.push(split.win);
@ -104,16 +104,16 @@ export class EmbeddedView extends nosuper(HoverPopover) {
return windows;
}
static containerForDocument(doc: Document, plugin: FloatSearchPlugin) {
if (doc !== document && plugin.app.workspace.floatingSplit)
for (const container of plugin.app.workspace.floatingSplit.children) {
static containerForDocument(doc: Document) {
if (doc !== document && app.workspace.floatingSplit)
for (const container of app.workspace.floatingSplit.children) {
if (container.doc === doc) return container;
}
return plugin.app.workspace.rootSplit;
return app.workspace.rootSplit;
}
static activePopovers(plugin: FloatSearchPlugin) {
return this.activeWindows(plugin).flatMap(this.popoversForWindow);
static activePopovers() {
return this.activeWindows().flatMap(this.popoversForWindow);
}
static popoversForWindow(win?: Window) {
@ -128,8 +128,8 @@ export class EmbeddedView extends nosuper(HoverPopover) {
return el ? popovers.get(el) : undefined;
}
static iteratePopoverLeaves(ws: Workspace, cb: (leaf: WorkspaceLeaf) => boolean | void, plugin: FloatSearchPlugin) {
for (const popover of this.activePopovers(plugin)) {
static iteratePopoverLeaves(ws: Workspace, cb: (leaf: WorkspaceLeaf) => boolean | void) {
for (const popover of this.activePopovers()) {
if (popover.rootSplit && ws.iterateLeaves(cb, popover.rootSplit)) return true;
}
return false;
@ -221,7 +221,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
if (this.shouldShow()) {
if (this.state === PopoverState.Hiding) {
this.state = PopoverState.Shown;
window.clearTimeout(this.timer);
clearTimeout(this.timer);
}
} else {
if (this.state === PopoverState.Showing) {
@ -252,7 +252,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
attachLeaf(): WorkspaceLeaf {
this.rootSplit.getRoot = () => this.plugin.app.workspace[this.document === document ? "rootSplit" : "floatingSplit"]!;
this.rootSplit.getContainer = () => EmbeddedView.containerForDocument(this.document, this.plugin);
this.rootSplit.getContainer = () => EmbeddedView.containerForDocument(this.document);
this.titleEl.insertAdjacentElement("afterend", this.rootSplit.containerEl);
const leaf = this.plugin.app.workspace.createLeafInParent(this.rootSplit, 0);
@ -264,7 +264,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
onload(): void {
super.onload();
this.registerEvent(this.plugin.app.workspace.on("layout-change", this.updateLeaves, this));
this.registerEvent(this.plugin.app.workspace.on("layout-change", () => {
this.registerEvent(app.workspace.on("layout-change", () => {
// Ensure that top-level items in a popover are not tabbed
// @ts-ignore
this.rootSplit.children.forEach((item: any, index: any) => {
@ -326,7 +326,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
}
shouldShowChild(): boolean {
return EmbeddedView.activePopovers(this.plugin).some(popover => {
return EmbeddedView.activePopovers().some(popover => {
if (popover !== this && popover.targetEl && this.hoverEl.contains(popover.targetEl)) {
return popover.shouldShow();
}
@ -355,7 +355,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
this.targetEl.appendChild(this.hoverEl);
this.onShow();
this.plugin.app.workspace.onLayoutChange();
app.workspace.onLayoutChange();
// initializingHoverPopovers.remove(this);
// activeHoverPopovers.push(this);
@ -391,7 +391,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
// A timer might be pending to call show() for the first time, make sure
// it doesn't bring us back up after we close
if (this.timer) {
window.clearTimeout(this.timer);
clearTimeout(this.timer);
this.timer = 0;
}
@ -465,7 +465,7 @@ export class EmbeddedView extends nosuper(HoverPopover) {
eState = Object.assign(this.buildEphemeralState(file, link), eState);
const parentMode = this.getDefaultMode();
const state = this.buildState(parentMode, eState);
const leaf = await this.openFile(file, state as OpenViewState, createInLeaf);
const leaf = await this.openFile(file, state, createInLeaf);
const leafViewType = leaf?.view?.getViewType();
// console.log(leaf);
if (leafViewType === "image") {

View file

@ -1,326 +1,290 @@
import "obsidian";
import {
EditorPosition,
EphemeralState,
Loc,
MarkdownPreviewRenderer,
MarkdownSubView,
Plugin,
PluginManifest,
SuggestModal,
TFile,
TFolder,
View,
WorkspaceItem,
WorkspaceLeaf,
EditorPosition,
EphemeralState,
Loc,
MarkdownPreviewRenderer, MarkdownSubView,
Plugin,
PluginManifest,
SuggestModal,
TFile, TFolder,
View, WorkspaceItem,
WorkspaceLeaf
} from "obsidian";
import { EmbeddedViewParent } from "../leafView";
interface InternalPlugins {
switcher: QuickSwitcherPlugin;
"page-preview": InternalPlugin;
graph: GraphPlugin;
switcher: QuickSwitcherPlugin;
"page-preview": InternalPlugin;
graph: GraphPlugin;
}
interface OpenViewState {
eState?: Record<string, unknown>;
state?: { mode: string };
active?: boolean;
eState?: EphemeralState;
state?: { mode: string };
active?: boolean;
}
declare class QuickSwitcherModal extends SuggestModal<TFile> {
getSuggestions(query: string): TFile[] | Promise<TFile[]>;
getSuggestions(query: string): TFile[] | Promise<TFile[]>;
renderSuggestion(value: TFile, el: HTMLElement): unknown;
renderSuggestion(value: TFile, el: HTMLElement): unknown;
onChooseSuggestion(item: TFile, evt: MouseEvent | KeyboardEvent): unknown;
onChooseSuggestion(item: TFile, evt: MouseEvent | KeyboardEvent): unknown;
}
interface InternalPlugin {
disable(): void;
disable(): void;
enable(): void;
enable(): void;
enabled: boolean;
_loaded: boolean;
instance: { name: string; id: string };
enabled: boolean;
_loaded: boolean;
instance: { name: string; id: string };
}
interface GraphPlugin extends InternalPlugin {
views: { localgraph: (leaf: WorkspaceLeaf) => GraphView };
views: { localgraph: (leaf: WorkspaceLeaf) => GraphView };
}
interface GraphView extends View {
engine: typeof Object;
renderer: { worker: { terminate(): void } };
engine: typeof Object;
renderer: { worker: { terminate(): void } };
}
interface QuickSwitcherPlugin extends InternalPlugin {
instance: {
name: string;
id: string;
QuickSwitcherModal: typeof QuickSwitcherModal;
};
instance: {
name: string;
id: string;
QuickSwitcherModal: typeof QuickSwitcherModal;
};
}
declare global {
const i18next: {
t(id: string): string;
};
const i18next: {
t(id: string): string;
};
interface Window {
activeWindow: Window;
activeDocument: Document;
}
interface Window {
activeWindow: Window;
activeDocument: Document;
}
}
declare module "obsidian" {
interface App {
commands: {
listCommands(): Command[];
findCommand(id: string): Command;
removeCommand(id: string): void;
executeCommandById(id: string): void;
commands: Record<string, Command>;
};
internalPlugins: {
plugins: InternalPlugins;
getPluginById<T extends keyof InternalPlugins>(
id: T
): InternalPlugins[T];
};
plugins: {
manifests: Record<string, PluginManifest>;
plugins: Record<string, Plugin> & {
["recent-files-obsidian"]: Plugin & {
shouldAddFile(file: TFile): boolean;
};
};
getPlugin(id: string): Plugin;
getPlugin(id: "calendar"): CalendarPlugin;
};
dom: { appContainerEl: HTMLElement };
viewRegistry: ViewRegistry;
interface App {
commands: {
listCommands(): Command[];
findCommand(id: string): Command;
removeCommand(id: string): void;
executeCommandById(id: string): void;
commands: Record<string, Command>;
};
internalPlugins: {
plugins: InternalPlugins;
getPluginById<T extends keyof InternalPlugins>(id: T): InternalPlugins[T];
};
plugins: {
manifests: Record<string, PluginManifest>;
plugins: Record<string, Plugin> & {
["recent-files-obsidian"]: Plugin & {
shouldAddFile(file: TFile): boolean;
};
};
getPlugin(id: string): Plugin;
getPlugin(id: "calendar"): CalendarPlugin;
};
dom: { appContainerEl: HTMLElement };
viewRegistry: ViewRegistry;
openWithDefaultApp(path: string): void;
openWithDefaultApp(path: string): void;
}
dragManager: any;
}
interface ViewRegistry {
typeByExtension: Record<string, string>; // file extensions to view types
viewByType: Record<string, (leaf: WorkspaceLeaf) => View>; // file extensions to view types
}
interface ViewRegistry {
typeByExtension: Record<string, string>; // file extensions to view types
viewByType: Record<string, (leaf: WorkspaceLeaf) => View>; // file extensions to view types
}
interface CalendarPlugin {
view: View;
}
interface CalendarPlugin {
view: View;
}
interface WorkspaceParent {
insertChild(index: number, child: WorkspaceItem, resize?: boolean): void;
interface WorkspaceParent {
insertChild(
index: number,
child: WorkspaceItem,
resize?: boolean
): void;
replaceChild(index: number, child: WorkspaceItem, resize?: boolean): void;
replaceChild(
index: number,
child: WorkspaceItem,
resize?: boolean
): void;
removeChild(leaf: WorkspaceLeaf, resize?: boolean): void;
removeChild(leaf: WorkspaceLeaf, resize?: boolean): void;
containerEl: HTMLElement;
children: any;
}
containerEl: HTMLElement;
children: any;
parent: any;
}
interface MarkdownEditView {
editorEl: HTMLElement;
}
interface MarkdownEditView {
editorEl: HTMLElement;
}
class MarkdownPreviewRendererStatic extends MarkdownPreviewRenderer {
static registerDomEvents(el: HTMLElement, handlerInstance: unknown, cb: (el: HTMLElement) => unknown): void;
}
class MarkdownPreviewRendererStatic extends MarkdownPreviewRenderer {
static registerDomEvents(
el: HTMLElement,
handlerInstance: unknown,
cb: (el: HTMLElement) => unknown
): void;
}
interface WorkspaceLeaf {
openLinkText(linkText: string, path: string, state?: unknown): Promise<void>;
interface WorkspaceLeaf {
openLinkText(
linkText: string,
path: string,
state?: unknown
): Promise<void>;
updateHeader(): void;
updateHeader(): void;
containerEl: HTMLDivElement;
working: boolean;
parentSplit: WorkspaceParent;
activeTime: number;
}
containerEl: HTMLDivElement;
working: boolean;
parentSplit: WorkspaceParent;
activeTime: number;
}
interface Workspace {
recordHistory(leaf: WorkspaceLeaf, pushHistory: boolean): void;
interface Workspace {
recordHistory(leaf: WorkspaceLeaf, pushHistory: boolean): void;
iterateLeaves(callback: (item: WorkspaceLeaf) => boolean | void, item: WorkspaceItem | WorkspaceItem[]): boolean;
iterateLeaves(
callback: (item: WorkspaceLeaf) => boolean | void,
item: WorkspaceItem | WorkspaceItem[]
): boolean;
iterateLeaves(item: WorkspaceItem | WorkspaceItem[], callback: (item: WorkspaceLeaf) => boolean | void): boolean;
iterateLeaves(
item: WorkspaceItem | WorkspaceItem[],
callback: (item: WorkspaceLeaf) => boolean | void
): boolean;
getDropLocation(event: MouseEvent): {
target: WorkspaceItem;
sidedock: boolean;
};
getDropLocation(event: MouseEvent): {
target: WorkspaceItem;
sidedock: boolean;
};
recursiveGetTarget(event: MouseEvent, parent: WorkspaceParent): WorkspaceItem;
recursiveGetTarget(
event: MouseEvent,
parent: WorkspaceParent
): WorkspaceItem;
recordMostRecentOpenedFile(file: TFile): void;
recordMostRecentOpenedFile(file: TFile): void;
onDragLeaf(event: MouseEvent, leaf: WorkspaceLeaf): void;
onDragLeaf(event: MouseEvent, leaf: WorkspaceLeaf): void;
onLayoutChange(): void; // tell Obsidian leaves have been added/removed/etc.
activeLeafEvents(): void;
onLayoutChange(): void; // tell Obsidian leaves have been added/removed/etc.
activeLeafEvents(): void;
floatingSplit: any;
floatingSplit: any;
pushUndoHistory(leaf: WorkspaceLeaf, id: string, e: any): void;
}
pushUndoHistory(leaf: WorkspaceLeaf, id: string, e: any): void;
}
interface Editor {
getClickableTokenAt(pos: EditorPosition): {
text: string;
type: string;
start: EditorPosition;
end: EditorPosition;
};
}
interface Editor {
getClickableTokenAt(pos: EditorPosition): {
text: string;
type: string;
start: EditorPosition;
end: EditorPosition;
};
}
interface WorkspaceItem {
side?: "left" | "right";
}
interface WorkspaceItem {
side?: "left" | "right";
}
interface View {
iconEl: HTMLElement;
file: TFile;
interface View {
iconEl: HTMLElement;
file: TFile;
setMode(mode: MarkdownSubView): Promise<void>;
setMode(mode: MarkdownSubView): Promise<void>;
followLinkUnderCursor(newLeaf: boolean): void;
followLinkUnderCursor(newLeaf: boolean): void;
modes: Record<string, MarkdownSubView>;
modes: Record<string, MarkdownSubView>;
getMode(): string;
getMode(): string;
headerEl: HTMLElement;
contentEl: HTMLElement;
}
headerEl: HTMLElement;
contentEl: HTMLElement;
}
interface SearchView extends View {
onKeyArrowRightInFocus(e: KeyboardEvent): void;
interface SearchView extends View {
onKeyArrowRightInFocus(e: KeyboardEvent): void;
onKeyArrowLeftInFocus(e: KeyboardEvent): void;
onKeyArrowLeftInFocus(e: KeyboardEvent): void;
onKeyArrowUpInFocus(e: KeyboardEvent): void;
onKeyArrowUpInFocus(e: KeyboardEvent): void;
onKeyArrowDownInFocus(e: KeyboardEvent): void;
onKeyArrowDownInFocus(e: KeyboardEvent): void;
onKeyEnterInFocus(e: KeyboardEvent): void;
onKeyEnterInFocus(e: KeyboardEvent): void;
onKeyShowMoreBefore(e: KeyboardEvent): void;
onKeyShowMoreBefore(e: KeyboardEvent): void;
onKeyShowMoreAfter(e: KeyboardEvent): void;
onKeyShowMoreAfter(e: KeyboardEvent): void;
dom: any;
searchComponent: SearchComponent;
headerDom: any;
}
dom: any;
searchComponent: SearchComponent;
headerDom: any;
}
interface EmptyView extends View {
actionListEl: HTMLElement;
emptyTitleEl: HTMLElement;
}
interface EmptyView extends View {
actionListEl: HTMLElement;
emptyTitleEl: HTMLElement;
}
interface FileManager {
createNewMarkdownFile(folder: TFolder, fileName: string): Promise<TFile>;
}
interface FileManager {
createNewMarkdownFile(
folder: TFolder,
fileName: string
): Promise<TFile>;
}
enum PopoverState {
Showing,
Shown,
Hiding,
Hidden,
}
enum PopoverState {
Showing,
Shown,
Hiding,
Hidden,
}
interface Menu {
items: MenuItem[];
dom: HTMLElement;
hideCallback: () => unknown;
}
interface Menu {
items: MenuItem[];
dom: HTMLElement;
hideCallback: () => unknown;
}
interface MenuItem {
iconEl: HTMLElement;
dom: HTMLElement;
}
interface MenuItem {
iconEl: HTMLElement;
dom: HTMLElement;
}
interface EphemeralState {
focus?: boolean;
subpath?: string;
line?: number;
startLoc?: Loc;
endLoc?: Loc;
scroll?: number;
}
interface EphemeralState {
focus?: boolean;
subpath?: string;
line?: number;
startLoc?: Loc;
endLoc?: Loc;
scroll?: number;
}
interface HoverParent {
type?: string;
}
interface HoverParent {
type?: string;
}
interface WorkspaceContainer {
type: "window" | "split" | "tab";
}
interface WorkspaceContainer {
type: "window" | "split" | "tab";
}
interface HoverPopover {
parent: EmbeddedViewParent | null;
targetEl: HTMLElement;
hoverEl: HTMLElement;
interface HoverPopover {
parent: EmbeddedViewParent | null;
targetEl: HTMLElement;
hoverEl: HTMLElement;
position(pos?: MousePos): void;
position(pos?: MousePos): void;
hide(): void;
hide(): void;
show(): void;
show(): void;
shouldShowSelf(): boolean;
shouldShowSelf(): boolean;
timer: number;
waitTime: number;
timer: number;
waitTime: number;
shouldShow(): boolean;
shouldShow(): boolean;
transition(): void;
}
transition(): void;
}
interface MousePos {
x: number;
y: number;
}
interface MousePos {
x: number;
y: number;
}
interface Plugin {
registerGlobalCommand(command: Command): void;
}
interface Plugin {
registerGlobalCommand(command: Command): void;
}
}

View file

@ -9,15 +9,13 @@ If your plugin does not need CSS, delete this file.
.float-search-modal {
width: 700px;
padding-bottom: 0;
transition: width 0.15s ease;
}
.float-search-modal.float-search-width {
width: 1200px;
}
.float-search-modal-search-ctn,
.float-search-modal-file-ctn {
.float-search-modal-search-ctn, .float-search-modal-file-ctn {
height: 100%;
width: 100%;
}
@ -65,6 +63,7 @@ If your plugin does not need CSS, delete this file.
z-index: 30;
}
.float-search-modal-instructions {
border-top: 1px solid var(--background-secondary);
user-select: none;
@ -83,8 +82,7 @@ If your plugin does not need CSS, delete this file.
margin-right: var(--size-2-2);
}
.float-search-modal-content:has(.float-search-modal-file-ctn)
.float-search-modal-search-ctn {
.float-search-modal-content:has(.float-search-modal-file-ctn) .float-search-modal-search-ctn {
border-right: 1px solid var(--background-secondary);
}
@ -144,88 +142,3 @@ body:not(.show-file-path) .search-result-file-title .search-result-file-path {
.show-file-path .search-result-file-title .search-result-file-path:hover {
background-color: var(--background-secondary);
}
.fs-leaf-view .workspace-split {
background-color: var(--background-primary);
}
/* ── CMDK Modal ── */
.prompt.float-search-cmdk {
width: 700px;
max-width: 90vw;
transition: width 0.15s ease;
}
.prompt.float-search-cmdk.float-search-cmdk-expanded {
width: 1100px;
}
.float-search-cmdk-body {
display: flex;
flex-direction: row;
height: 50vh;
max-height: 600px;
overflow: hidden;
}
.float-search-cmdk-body .prompt-results {
max-height: none;
height: 100%;
overflow-y: auto;
flex: 1 1 auto;
}
.float-search-cmdk-expanded .float-search-cmdk-body .prompt-results {
flex: 0 0 40%;
border-right: 1px solid var(--background-modifier-border);
}
.float-search-cmdk-preview {
flex: 1;
overflow: hidden;
height: 100%;
}
.float-search-cmdk-preview .view-header {
display: none;
}
.float-search-cmdk-preview .view-content {
height: 100%;
}
.float-search-cmdk-preview .fs-block {
height: 100% !important;
}
.float-search-cmdk-preview .fs-content {
height: 100%;
}
.float-search-cmdk-preview .fs-content .workspace-split.mod-vertical {
height: 100%;
}
.float-search-cmdk-preview .workspace-leaf-resize-handle {
display: none;
}
.modal-container.float-search-cmdk-container.mod-dim {
z-index: 30;
}
/* ── Quick Create item ── */
.float-search-cmdk-create-item {
border-top: 1px solid var(--background-modifier-border);
}
.float-search-cmdk-create-item .suggestion-title {
color: var(--text-accent);
font-weight: var(--font-semibold);
}
.float-search-cmdk-create-item .suggestion-flair {
display: flex;
align-items: center;
color: var(--text-accent);
}

View file

@ -29,10 +29,5 @@
"3.4.9": "0.15.0",
"3.4.10": "0.15.0",
"3.5.0": "0.15.0",
"3.5.1": "0.15.0",
"4.0.0": "0.15.0",
"4.1.0": "0.15.0",
"4.1.1": "0.15.0",
"4.2.0": "1.2.0",
"4.3.0": "1.2.0"
"3.5.1": "0.15.0"
}