allow user to pick image

This commit is contained in:
froehlichA 2023-03-18 18:29:24 +01:00
parent 5417009647
commit be39eb09d4
3 changed files with 111 additions and 5 deletions

View file

@ -1,9 +1,10 @@
<script lang="ts">
import {App, MarkdownPostProcessorContext, MarkdownView} from "obsidian";
import {App, MarkdownPostProcessorContext, MarkdownView, TFile} from "obsidian";
import {AvatarPlugin} from "../plugin";
import Fab from "./Fab.svelte";
import ObsidianIcon from "./ObsidianIcon.svelte";
import type {SetState, State} from "../core/stateProviders";
import {SelectImageModal} from "./SelectImageModal";
interface AvatarViewState {
image: string;
@ -11,7 +12,6 @@
}
export let app: App;
export let plugin: AvatarPlugin;
export let ctx: MarkdownPostProcessorContext;
export let state: State<AvatarViewState>;
export let setState: SetState<AvatarViewState>;
@ -34,18 +34,33 @@
});
}
function selectImage() {
function updateImage() {
if(inSourceMode) {
new SelectImageModal(app, (path) => {
setState((fm) => {
fm.image = path;
});
}).open();
}
}
function normalizeImgPath(src: string): string {
const file = app.vault.getAbstractFileByPath(src);
if(file && file instanceof TFile) {
return app.vault.getResourcePath(file);
}
return src;
}
</script>
<div class="flex">
<div
class="avatar relative"
on:click={selectImage}
on:click={updateImage}
on:mouseenter={() => hoverOnImage = true}
on:mouseleave={() => hoverOnImage = false}
>
<img class="avatar" alt="Avatar" src={state?.image ?? fallbackImage} />
<img class="avatar" alt="Avatar" src={normalizeImgPath(state?.image) ?? fallbackImage} />
{#if inSourceMode && hoverOnImage}
<Fab>
<ObsidianIcon id="edit"></ObsidianIcon>

View file

@ -0,0 +1,87 @@
import {App, SuggestModal, normalizePath, prepareFuzzySearch} from "obsidian";
import type {SearchMatchPart} from "obsidian";
export interface Image {
title: DocumentFragment;
desc?: string;
path: string;
}
export class SelectImageModal extends SuggestModal<Image> {
constructor(
app: App,
private readonly onSelect: (path: string) => void
) {
super(app);
this.setPlaceholder("Select image / Paste URL...");
this.setInstructions([
{ command: "↑↓", purpose: "to navigate" },
{ command: "↵", purpose: "to select" }
]);
}
override getSuggestions(query: string): Image[] {
const search = prepareFuzzySearch(query);
const files = this.app.vault.getFiles()
.filter(f => ["jpg", "jpeg", "png", "gif", "svg", "webp"].includes(f.extension))
.map(f => ({ title: f.basename, desc: f.extension, path: f.path }));
const searchResults = files
.map<Image & { score: number }>(f => {
const result = search(f.title);
return {
title: result?.matches ? fuzzyStrToFragment(f.title, result?.matches) : strToFragment(f.title),
desc: f.desc,
path: f.path,
score: result?.score ?? 1
}
})
.filter(f => f.score < 1)
.sort((a, b) => Math.abs(a.score) - Math.abs(b.score));
if (query.startsWith("http://") || query.startsWith("https://")) {
const shortenedQuery = query.substring(0, 30) + (query.length >= 30 ? "..." : "");
return [
...searchResults,
{ title: strToFragment(shortenedQuery), desc: "Use URL", path: query }
];
} else {
return searchResults;
}
}
override renderSuggestion(item: Image, el: HTMLElement) {
el.createEl("span", { text: item.title });
el.createEl("small", { text: item.desc, cls: "float-right" });
}
override onChooseSuggestion(item: Image, evt: MouseEvent | KeyboardEvent): any {
this.onSelect(normalizePath(item.path));
}
}
function strToFragment(str: string): DocumentFragment {
const fragment = new DocumentFragment();
fragment.createEl("span", { text: str });
return fragment;
}
function fuzzyStrToFragment(str: string, matches: SearchMatchPart[]) : DocumentFragment {
const fragment = new DocumentFragment();
const highlightedIndices: number[] = [];
for(const match of matches) {
for(let i = match[0]; i < match[1]; i++) {
highlightedIndices.push(i);
}
}
for(let i = 0; i < str.length; i++) {
const char = str[i];
if(highlightedIndices.includes(i)) {
fragment.createEl("span", { text: char, cls: "suggestion-highlight" });
} else {
fragment.createEl("span", { text: char });
}
}
return fragment;
}

View file

@ -13,3 +13,7 @@
.markdown-reading-view > .show-in-reading-view {
display: initial;
}
.float-right {
float: right;
}