3 Commits
Author SHA1 Message Date
oqyude 4cf5e9da4a fix with paragraphs 2026-07-11 03:43:26 +03:00
oqyude d546947e61 some automation
Release / release (push) Has been cancelled
2026-07-11 03:26:31 +03:00
oqyude 801fdec71e workflow and fixes
Release / release (push) Has been cancelled
2026-07-11 03:22:18 +03:00
8 changed files with 123 additions and 79 deletions
+42
View File
@@ -0,0 +1,42 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Verify version
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
MANIFEST_VERSION=$(node -p "require('./manifest.json').version")
if [ "$TAG_VERSION" != "$MANIFEST_VERSION" ]; then
echo "❌ Tag ($TAG_VERSION) != manifest ($MANIFEST_VERSION)"
exit 1
fi
- name: Create Release
uses: softprops/action-gh-release@v2
with:
name: ${{ github.ref_name }}
files: |
main.js
manifest.json
styles.css
+6
View File
@@ -1,5 +1,6 @@
import esbuild from 'esbuild'; import esbuild from 'esbuild';
import process from 'process'; import process from 'process';
import fs from 'fs';
import builtins from 'builtin-modules'; import builtins from 'builtin-modules';
const banner = `/* const banner = `/*
@@ -9,6 +10,11 @@ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
const prod = process.argv[2] === 'production'; const prod = process.argv[2] === 'production';
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
const manifest = JSON.parse(fs.readFileSync('./manifest.json', 'utf8'));
manifest.version = pkg.version;
fs.writeFileSync('./manifest.json', JSON.stringify(manifest, null, '\t') + '\n');
esbuild esbuild
.build({ .build({
banner: { js: banner }, banner: { js: banner },
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "zeroq-qol-modules", "id": "zeroq-qol-modules",
"name": "ZeroQ QoL Modules", "name": "ZeroQ QoL Modules",
"version": "1.0.3", "version": "1.1.1",
"minAppVersion": "0.15.0", "minAppVersion": "0.15.0",
"description": "QoL Modules", "description": "QoL Modules",
"author": "oqyude", "author": "oqyude",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "zeroq-qol-modules", "name": "zeroq-qol-modules",
"version": "1.0.0", "version": "1.1.1",
"description": "Modular Obsidian plugin with toggleable QoL modules", "description": "Modular Obsidian plugin with toggleable QoL modules",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
+52 -75
View File
@@ -4,7 +4,6 @@ import {
MarkdownFileInfo, MarkdownFileInfo,
MarkdownView, MarkdownView,
Notice, Notice,
PluginSettingTab,
Setting, Setting,
normalizePath, normalizePath,
} from 'obsidian'; } from 'obsidian';
@@ -33,25 +32,65 @@ export class AttachmentCleanPasteModule extends BaseModule {
onload(plugin: ZeroQoLModulesPlugin, moduleSettings: Record<string, unknown>): void { onload(plugin: ZeroQoLModulesPlugin, moduleSettings: Record<string, unknown>): void {
this.app = plugin.app; this.app = plugin.app;
const settings = moduleSettings as unknown as AttachmentCleanPasteSettings; const rawSettings = moduleSettings as AttachmentCleanPasteSettings;
plugin.addSettingTab(
new AttachmentCleanPasteSettingTab(plugin.app, plugin, MODULE_ID),
);
const pasteRef = plugin.app.workspace.on( const pasteRef = plugin.app.workspace.on(
'editor-paste', 'editor-paste',
this.createPasteHandler(settings), this.createPasteHandler(rawSettings),
); );
this.registerCleanup(() => plugin.app.workspace.offref(pasteRef)); this.registerCleanup(() => plugin.app.workspace.offref(pasteRef));
const dropRef = plugin.app.workspace.on( const dropRef = plugin.app.workspace.on(
'editor-drop', 'editor-drop',
this.createDropHandler(settings), this.createDropHandler(rawSettings),
); );
this.registerCleanup(() => plugin.app.workspace.offref(dropRef)); this.registerCleanup(() => plugin.app.workspace.offref(dropRef));
} }
renderInlineSettings(
containerEl: HTMLElement,
settings: Record<string, unknown>,
saveSettings: () => Promise<void>,
): void {
const loc = locale.modules['attachment-clean-paste'];
const extSettings = settings as unknown as AttachmentCleanPasteSettings;
new Setting(containerEl)
.setName(loc.extensionsLabel)
.setDesc(loc.extensionsDesc)
.addTextArea((textarea) => {
textarea
.setPlaceholder(loc.extensionsPlaceholder)
.setValue(extSettings?.extensions ?? '')
.onChange(async (value) => {
settings.extensions = value;
await saveSettings();
});
textarea.inputEl.rows = 4;
textarea.inputEl.style.width = '100%';
});
}
private async processAll(
files: FileList,
editor: Editor,
settings: AttachmentCleanPasteSettings,
): Promise<void> {
const matchingFiles = Array.from(files).filter((f) =>
this.shouldProcess(f.name, settings),
);
if (matchingFiles.length === 0) return;
const links: string[] = [];
for (const file of matchingFiles) {
const link = await this.processFile(file, settings);
if (link) links.push(link);
}
if (links.length === 0) return;
editor.replaceSelection(links.join('\n\n'));
}
private createPasteHandler(settings: AttachmentCleanPasteSettings) { private createPasteHandler(settings: AttachmentCleanPasteSettings) {
return async ( return async (
evt: ClipboardEvent, evt: ClipboardEvent,
@@ -61,17 +100,10 @@ export class AttachmentCleanPasteModule extends BaseModule {
const files = evt.clipboardData?.files; const files = evt.clipboardData?.files;
if (!files || files.length === 0) return; if (!files || files.length === 0) return;
const matchingFiles = Array.from(files).filter((f) =>
this.shouldProcess(f.name, settings),
);
if (matchingFiles.length === 0) return;
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
for (const file of matchingFiles) { await this.processAll(files, editor, settings);
await this.processFile(file, editor, settings);
}
}; };
} }
@@ -84,17 +116,10 @@ export class AttachmentCleanPasteModule extends BaseModule {
const files = evt.dataTransfer?.files; const files = evt.dataTransfer?.files;
if (!files || files.length === 0) return; if (!files || files.length === 0) return;
const matchingFiles = Array.from(files).filter((f) =>
this.shouldProcess(f.name, settings),
);
if (matchingFiles.length === 0) return;
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
for (const file of matchingFiles) { await this.processAll(files, editor, settings);
await this.processFile(file, editor, settings);
}
}; };
} }
@@ -119,9 +144,8 @@ export class AttachmentCleanPasteModule extends BaseModule {
private async processFile( private async processFile(
file: File, file: File,
editor: Editor,
_settings: AttachmentCleanPasteSettings, _settings: AttachmentCleanPasteSettings,
): Promise<void> { ): Promise<string | null> {
try { try {
const arrayBuffer = await file.arrayBuffer(); const arrayBuffer = await file.arrayBuffer();
const filename = file.name; const filename = file.name;
@@ -147,58 +171,11 @@ export class AttachmentCleanPasteModule extends BaseModule {
await this.app.vault.createBinary(availablePath, arrayBuffer); await this.app.vault.createBinary(availablePath, arrayBuffer);
const link = `[[${availablePath}|${nameWithoutExt}]]`; return `[[${availablePath}|${nameWithoutExt}]]`;
editor.replaceSelection(link);
} catch (e) { } catch (e) {
new Notice(`Clean Paste error: ${e.message}`); new Notice(`Clean Paste error: ${e.message}`);
console.error('Attachment Clean Paste:', e); console.error('Attachment Clean Paste:', e);
} }
} return null;
}
class AttachmentCleanPasteSettingTab extends PluginSettingTab {
private plugin: ZeroQoLModulesPlugin;
private moduleId: string;
constructor(app: App, plugin: ZeroQoLModulesPlugin, moduleId: string) {
super(app, plugin);
this.plugin = plugin;
this.moduleId = moduleId;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
const loc = locale.modules['attachment-clean-paste'];
containerEl.createEl('h2', { text: loc.name });
containerEl.createEl('p', {
text: loc.descriptionShort,
attr: { style: 'color: var(--text-muted); margin-bottom: 20px;' },
});
const rawSettings = this.plugin.settings.modules[this.moduleId]?.settings as
| AttachmentCleanPasteSettings
| undefined;
new Setting(containerEl)
.setName(loc.extensionsLabel)
.setDesc(loc.extensionsDesc)
.addTextArea((textarea) => {
textarea
.setPlaceholder(loc.extensionsPlaceholder)
.setValue(rawSettings?.extensions ?? '')
.onChange(async (value) => {
if (this.plugin.settings.modules[this.moduleId]) {
this.plugin.settings.modules[this.moduleId].settings = {
extensions: value,
};
}
await this.plugin.saveSettings();
});
textarea.inputEl.rows = 4;
textarea.inputEl.style.width = '100%';
});
} }
} }
+6
View File
@@ -21,6 +21,12 @@ export abstract class BaseModule implements QoLModule {
this.cleanupFns = []; this.cleanupFns = [];
} }
renderInlineSettings(
_containerEl: HTMLElement,
_settings: Record<string, unknown>,
_saveSettings: () => Promise<void>,
): void {}
protected registerCleanup(fn: () => void): void { protected registerCleanup(fn: () => void): void {
this.cleanupFns.push(fn); this.cleanupFns.push(fn);
} }
+10 -2
View File
@@ -45,14 +45,14 @@ export class ZeroQSettingTab extends PluginSettingTab {
}); });
for (const module of MODULES) { for (const module of MODULES) {
const moduleSettings = this.plugin.settings.modules[module.id]; const moduleCfg = this.plugin.settings.modules[module.id];
new Setting(containerEl) new Setting(containerEl)
.setName(module.name) .setName(module.name)
.setDesc(module.description) .setDesc(module.description)
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle
.setValue(moduleSettings?.enabled ?? true) .setValue(moduleCfg?.enabled ?? true)
.onChange(async (value) => { .onChange(async (value) => {
if (!this.plugin.settings.modules[module.id]) { if (!this.plugin.settings.modules[module.id]) {
this.plugin.settings.modules[module.id] = { this.plugin.settings.modules[module.id] = {
@@ -70,6 +70,14 @@ export class ZeroQSettingTab extends PluginSettingTab {
} }
}), }),
); );
if (moduleCfg) {
module.renderInlineSettings(
containerEl,
moduleCfg.settings,
() => this.plugin.saveSettings(),
);
}
} }
} }
} }
+5
View File
@@ -16,4 +16,9 @@ export interface QoLModule {
defaultSettings: Record<string, unknown>; defaultSettings: Record<string, unknown>;
onload(plugin: Plugin, moduleSettings: Record<string, unknown>): void; onload(plugin: Plugin, moduleSettings: Record<string, unknown>): void;
onunload(plugin: Plugin): void; onunload(plugin: Plugin): void;
renderInlineSettings(
containerEl: HTMLElement,
settings: Record<string, unknown>,
saveSettings: () => Promise<void>,
): void;
} }