mirror of
https://github.com/anshuman-ecc-eth/hm-obsidian.git
synced 2026-07-22 14:00:28 +00:00
fix: address Obsidian plugin guidelines violations
- Remove console.log from onload/onunload (Rule 21) - Fix settings headings to use sentence case (Rule 15) - Update LICENSE to proper MIT with Hyvmind copyright - Add comprehensive CSS with accessibility features - Use registerDomEvent for automatic cleanup - Add ARIA attributes for screen reader support - Add XSS sanitization helper for Notices
This commit is contained in:
parent
445e290fe3
commit
00a8e5a31c
5 changed files with 146 additions and 40 deletions
22
LICENSE
22
LICENSE
|
|
@ -1,5 +1,21 @@
|
|||
Copyright (C) 2020-2025 by Dynalist Inc.
|
||||
MIT License
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
Copyright (c) 2025 Hyvmind
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
|
|||
51
src/main.ts
51
src/main.ts
|
|
@ -101,11 +101,11 @@ export default class HyvmindPlugin extends Plugin {
|
|||
})
|
||||
);
|
||||
|
||||
console.log("Hyvmind Uploader plugin loaded");
|
||||
// Plugin loaded - no console logging in production (per Obsidian guidelines)
|
||||
}
|
||||
|
||||
onunload() {
|
||||
console.log("Hyvmind Uploader plugin unloaded");
|
||||
// Plugin unloaded - cleanup handled by register* methods
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
|
|
@ -150,7 +150,7 @@ export default class HyvmindPlugin extends Plugin {
|
|||
new Notice("Connected to ICP successfully!");
|
||||
} catch (error) {
|
||||
console.error("Connection failed:", error);
|
||||
new Notice(`Connection failed: ${error instanceof Error ? error.message : String(error)}`);
|
||||
new Notice(`Connection failed: ${this.sanitizeForNotice(error instanceof Error ? error.message : String(error))}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ export default class HyvmindPlugin extends Plugin {
|
|||
} catch (error) {
|
||||
progressModal.close();
|
||||
console.error("Upload failed:", error);
|
||||
new Notice(`Upload failed: ${error instanceof Error ? error.message : String(error)}`);
|
||||
new Notice(`Upload failed: ${this.sanitizeForNotice(error instanceof Error ? error.message : String(error))}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -210,6 +210,16 @@ export default class HyvmindPlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize text for display in Notices to prevent XSS
|
||||
*/
|
||||
private sanitizeForNotice(text: string): string {
|
||||
// Remove HTML tags and limit length
|
||||
return text
|
||||
.replace(/<[^>]*>/g, "") // Remove HTML tags
|
||||
.slice(0, 200); // Limit length
|
||||
}
|
||||
|
||||
/**
|
||||
* Show connect or upload menu
|
||||
*/
|
||||
|
|
@ -276,25 +286,23 @@ class UploadProgressModal extends Modal {
|
|||
text: "Initializing...",
|
||||
cls: "hyvmind-upload-status",
|
||||
});
|
||||
// Accessibility: Live region for screen readers
|
||||
this.statusEl.setAttribute("aria-live", "polite");
|
||||
this.statusEl.setAttribute("aria-atomic", "true");
|
||||
|
||||
this.progressEl = contentEl.createEl("div", {
|
||||
cls: "hyvmind-progress-bar",
|
||||
});
|
||||
|
||||
// Add some basic styling
|
||||
this.progressEl.style.width = "100%";
|
||||
this.progressEl.style.height = "20px";
|
||||
this.progressEl.style.backgroundColor = "var(--background-modifier-border)";
|
||||
this.progressEl.style.borderRadius = "4px";
|
||||
this.progressEl.style.overflow = "hidden";
|
||||
this.progressEl.style.marginTop = "1rem";
|
||||
|
||||
const progressFill = this.progressEl.createEl("div");
|
||||
progressFill.style.width = "0%";
|
||||
progressFill.style.height = "100%";
|
||||
progressFill.style.backgroundColor = "var(--interactive-accent)";
|
||||
progressFill.style.transition = "width 0.3s ease";
|
||||
progressFill.id = "hyvmind-progress-fill";
|
||||
// Accessibility: Progress bar with ARIA attributes
|
||||
const progressFill = this.progressEl.createEl("div", {
|
||||
cls: "hyvmind-progress-fill",
|
||||
});
|
||||
progressFill.setAttribute("role", "progressbar");
|
||||
progressFill.setAttribute("aria-valuenow", "0");
|
||||
progressFill.setAttribute("aria-valuemin", "0");
|
||||
progressFill.setAttribute("aria-valuemax", "100");
|
||||
progressFill.setAttribute("aria-label", "Upload progress");
|
||||
}
|
||||
|
||||
updateProgress(progress: {
|
||||
|
|
@ -305,10 +313,13 @@ class UploadProgressModal extends Modal {
|
|||
}): void {
|
||||
this.statusEl.setText(`${progress.stage}: ${progress.currentFile}`);
|
||||
|
||||
const fill = document.getElementById("hyvmind-progress-fill");
|
||||
// Use scoped querySelector instead of global getElementById
|
||||
const fill = this.progressEl.querySelector(".hyvmind-progress-fill");
|
||||
if (fill && progress.totalFiles > 0) {
|
||||
const percentage = (progress.processedFiles / progress.totalFiles) * 100;
|
||||
fill.style.width = `${percentage}%`;
|
||||
(fill as HTMLElement).style.width = `${percentage}%`;
|
||||
// Update ARIA value for accessibility
|
||||
fill.setAttribute("aria-valuenow", Math.round(percentage).toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export class HyvmindSettingTab extends PluginSettingTab {
|
|||
|
||||
containerEl.empty();
|
||||
|
||||
containerEl.createEl("h2", { text: "Hyvmind Uploader Settings" });
|
||||
containerEl.createEl("h2", { text: "Settings" });
|
||||
|
||||
// Canister ID setting
|
||||
new Setting(containerEl)
|
||||
|
|
@ -91,22 +91,26 @@ export class HyvmindSettingTab extends PluginSettingTab {
|
|||
);
|
||||
|
||||
// Info section
|
||||
containerEl.createEl("h3", { text: "Environment Presets" });
|
||||
|
||||
const presetContainer = containerEl.createDiv();
|
||||
presetContainer.style.marginTop = "1rem";
|
||||
|
||||
const mainnetBtn = presetContainer.createEl("button", { text: "Use Mainnet" });
|
||||
mainnetBtn.style.marginRight = "0.5rem";
|
||||
mainnetBtn.addEventListener("click", async () => {
|
||||
containerEl.createEl("h3", { text: "Environment presets" });
|
||||
|
||||
const presetContainer = containerEl.createDiv({ cls: "hyvmind-preset-container" });
|
||||
|
||||
const mainnetBtn = presetContainer.createEl("button", {
|
||||
text: "Use Mainnet",
|
||||
cls: "hyvmind-preset-btn",
|
||||
});
|
||||
this.plugin.registerDomEvent(mainnetBtn, "click", async () => {
|
||||
this.plugin.settings.identityProviderUrl = "https://id.ai";
|
||||
this.plugin.settings.host = "https://icp-api.io";
|
||||
await this.plugin.saveSettings();
|
||||
this.display(); // Refresh UI
|
||||
});
|
||||
|
||||
const localBtn = presetContainer.createEl("button", { text: "Use Local" });
|
||||
localBtn.addEventListener("click", async () => {
|
||||
const localBtn = presetContainer.createEl("button", {
|
||||
text: "Use Local",
|
||||
cls: "hyvmind-preset-btn",
|
||||
});
|
||||
this.plugin.registerDomEvent(localBtn, "click", async () => {
|
||||
this.plugin.settings.identityProviderUrl = "http://id.ai.localhost:8000";
|
||||
this.plugin.settings.host = "http://localhost:8000";
|
||||
await this.plugin.saveSettings();
|
||||
|
|
|
|||
|
|
@ -43,12 +43,14 @@ export class ConnectionStatusBar {
|
|||
const shortPrincipal = `${this.principal.slice(0, 8)}...${this.principal.slice(-4)}`;
|
||||
this.element.setText(`🟢 Hyvmind: ${shortPrincipal}`);
|
||||
this.element.title = `Connected as ${this.principal}`;
|
||||
this.element.style.color = "var(--text-success)";
|
||||
this.element.addClass("hyvmind-status-connected");
|
||||
this.element.removeClass("hyvmind-status-disconnected");
|
||||
} else {
|
||||
// Show disconnected status
|
||||
this.element.setText("⚪ Hyvmind: Not connected");
|
||||
this.element.title = "Click 'Connect to ICP' command to authenticate";
|
||||
this.element.style.color = "var(--text-muted)";
|
||||
this.element.addClass("hyvmind-status-disconnected");
|
||||
this.element.removeClass("hyvmind-status-connected");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
81
styles.css
81
styles.css
|
|
@ -1,8 +1,81 @@
|
|||
/*
|
||||
* Hyvmind Uploader Plugin Styles
|
||||
* These styles are available when the plugin is enabled
|
||||
*/
|
||||
|
||||
This CSS file will be included with your plugin, and
|
||||
available in the app when your plugin is enabled.
|
||||
/* ========================================
|
||||
Progress Modal Styles
|
||||
======================================== */
|
||||
|
||||
If your plugin does not need CSS, delete this file.
|
||||
.hyvmind-upload-status {
|
||||
font-size: var(--font-ui-small);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
*/
|
||||
.hyvmind-progress-bar {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background-color: var(--background-modifier-border);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.hyvmind-progress-bar .hyvmind-progress-fill {
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
background-color: var(--interactive-accent);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Status Bar Styles
|
||||
======================================== */
|
||||
|
||||
.hyvmind-status-bar {
|
||||
font-size: var(--font-ui-smaller);
|
||||
}
|
||||
|
||||
.hyvmind-status-connected {
|
||||
color: var(--text-success);
|
||||
}
|
||||
|
||||
.hyvmind-status-disconnected {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Settings Tab Styles
|
||||
======================================== */
|
||||
|
||||
.hyvmind-preset-container {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.hyvmind-preset-btn {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
/* Focus styles for accessibility */
|
||||
.hyvmind-preset-btn:focus-visible {
|
||||
outline: 2px solid var(--interactive-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* High contrast mode support */
|
||||
@media (prefers-contrast: high) {
|
||||
.hyvmind-progress-bar {
|
||||
border: 1px solid var(--text-normal);
|
||||
}
|
||||
|
||||
.hyvmind-progress-bar .hyvmind-progress-fill {
|
||||
border-right: 1px solid var(--text-normal);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduced motion support for accessibility */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.hyvmind-progress-bar .hyvmind-progress-fill {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue