Add translations among smaller fixes

This commit is contained in:
phibr0 2022-07-05 15:10:05 +02:00
parent c655cfffd6
commit d599811d8d
46 changed files with 329 additions and 129 deletions

1
locale/ar.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/cz.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/da.json Executable file
View file

@ -0,0 +1 @@
{}

49
locale/de.json Executable file
View file

@ -0,0 +1,49 @@
{
"Open Commander Settings": "Commander Einstellungen öffnen",
"Open Macro Builder": "Makro Baukasten öffnen",
"Change Icon": "Symbol verändern",
"Rename": "Umbenennen",
"Delete": "Löschen",
"Add command": "Befehl hinzufügen",
"Add new": "Neu hinzufügen",
"This Command seems to have been removed. {{command_name}}": "Dieser Befehl wurde entfernt. {{command_name}}",
"Choose a Command to add": "Wähle einen Befehl zum hinzufügen",
"to navigate": "zum navigieren",
"to choose an icon": "um ein symbol auszuwählen",
"to cancel": "zum abbrechen",
"Use a custom name": "Nutze einen benutzerdefinierten Namen",
"Choose a custom Name for your new Command": "Wähle einen benutzerdefinierten Namen für deinen neuen Befehl",
"to save": "zum speichern",
"Choose a Icon for your new Command": "Wähle ein Symbol für deinen neuen Befehl",
"to choose a custom icon": "um ein benutzerdefiniertes Symbol auszuwählen",
"Remove Command": "Befehl entfernen",
"Double click to rename": "Zum umbenennen doppelklicken",
"This device": "Dieses Gerät",
"Added by {{plugin_name}}.": "Hinzugefügt von {{plugin_name}}.",
"Warning: This is a checked Command, meaning it might not run under every circumstance.": "Warnung: Dieser Befehl wird nur unter bestimmten Vorraussetzungen ausgeführt.",
"Move down": "Nach unten",
"Move up": "Nach oben",
"Change Mode (Currently: {{current_mode}})": "Modus verändern (Momentan: {{current_mode}})",
"Are you sure you want to delete the Command?": "Bist du dir sicher, dass du diesen Befehl entfernen möchtest?",
"Remove and don't ask again": "Entfernen und Auswahl speichern",
"Remove": "Entfernen",
"Cancel": "Abbrechen",
"Always ask before removing?": "Immer fragen, bevor ein Befehl gelöscht wird?",
"Always show a Popup to confirm deletion of a Command.": "Zeige immer ein Popup um Löschen zu bestätigen.",
"Show \"Add Command\" Button": "Zeige \"Befehl hinzufügen\" Knopf",
"Show the \"Add Command\" Button in every Menu. Requires restart.": "Zeige den \"Befehl hinzufügen\" Knopf in jedem Menü. Erfordert neustart.",
"Please restart Obsidian for these changes to take effect.": "Bitte starte Obsidian neu, damit diese Änderungen in Kraft treten.",
"Enable debugging": "Aktiviere debugging",
"Enable console output.": "Aktiviere Konsolen-Output (Für Entwickler)",
"General": "Allgemein",
"Editor Menu": "Editor-Menü",
"File Menu": "Datei-Menü",
"Left Ribbon": "Linkes Band",
"Right Ribbon": "Rechtes Band",
"Titlebar": "Titelleiste",
"Statusbar": "Statusleiste",
"Page Header": "Kopfzeile",
"Support development": "Entwicklung unterstützen",
"No commands here!": "Keine Befehle da!",
"Would you like to add one now?": "Möchtest du jetzt einen hinzufügen?"
}

1
locale/en-gb.json Executable file
View file

@ -0,0 +1 @@
{}

49
locale/en.json Executable file
View file

@ -0,0 +1,49 @@
{
"Open Commander Settings": "Open Commander Settings",
"Open Macro Builder": "Open Macro Builder",
"Change Icon": "Change Icon",
"Rename": "Rename",
"Delete": "Delete",
"Add command": "Add command",
"Add new": "Add new",
"This Command seems to have been removed. {{command_name}}": "This Command seems to have been removed. {{command_name}}",
"Choose a Command to add": "Choose a Command to add",
"to navigate": "to navigate",
"to choose an icon": "to choose an icon",
"to cancel": "to cancel",
"Use a custom name": "Use a custom name",
"Choose a custom Name for your new Command": "Choose a custom Name for your new Command",
"to save": "to save",
"Choose a Icon for your new Command": "Choose a Icon for your new Command",
"to choose a custom icon": "to choose a custom icon",
"Remove Command": "Remove Command",
"Double click to rename": "Double click to rename",
"This device": "This device",
"Added by {{plugin_name}}.": "Added by {{plugin_name}}.",
"Warning: This is a checked Command, meaning it might not run under every circumstance.": "Warning: This is a checked Command, meaning it might not run under every circumstance.",
"Move down": "Move down",
"Move up": "Move up",
"Change Mode (Currently: {{current_mode}})": "Change Mode (Currently: {{current_mode}})",
"Are you sure you want to delete the Command?": "Are you sure you want to delete the Command?",
"Remove and don't ask again": "Remove and don't ask again",
"Remove": "Remove",
"Cancel": "Cancel",
"Always ask before removing?": "Always ask before removing?",
"Always show a Popup to confirm deletion of a Command.": "Always show a Popup to confirm deletion of a Command.",
"Show \"Add Command\" Button": "Show \"Add Command\" Button",
"Show the \"Add Command\" Button in every Menu. Requires restart.": "Show the \"Add Command\" Button in every Menu. Requires restart.",
"Please restart Obsidian for these changes to take effect.": "Please restart Obsidian for these changes to take effect.",
"Enable debugging": "Enable debugging",
"Enable console output.": "Enable console output.",
"General": "General",
"Editor Menu": "Editor Menu",
"File Menu": "File Menu",
"Left Ribbon": "Left Ribbon",
"Right Ribbon": "Right Ribbon",
"Titlebar": "Titlebar",
"Statusbar": "Statusbar",
"Page Header": "Page Header",
"Support development": "Support development",
"No commands here!": "No commands here!",
"Would you like to add one now?": "Would you like to add one now?"
}

1
locale/es.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/fr.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/hi.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/id.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/it.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/ja.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/ko.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/nl.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/no.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/pl.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/pt-br.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/pt.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/ro.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/ru.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/tr.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/zh-cn.json Executable file
View file

@ -0,0 +1 @@
{}

1
locale/zh-tw.json Executable file
View file

@ -0,0 +1 @@
{}

View file

@ -1,7 +1,7 @@
{
"id": "cmdr",
"name": "Commander",
"version": "0.0.7",
"version": "0.0.8",
"minAppVersion": "0.12.0",
"description": "Customize your workspace by adding commands /everywhere/.",
"author": "jsmorabito & phibr0",

View file

@ -1,6 +1,6 @@
{
"name": "cmdr",
"version": "0.0.7",
"version": "0.0.8",
"description": "Customize your workspace by adding commands /everywhere/.",
"main": "main.js",
"scripts": {

View file

@ -3,14 +3,13 @@ import process from "process";
import builtins from 'builtin-modules';
import alias from "esbuild-plugin-alias";
import { sassPlugin } from 'esbuild-sass-plugin';
import { createRequire } from 'module';
import { renameSync } from "fs";
const require = createRequire(import.meta.url);
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
if you want to view the source, please visit the github repository of this plugin (https://github.com/phibr0/obsidian-commander)
*/
`;
@ -76,7 +75,7 @@ esbuild.build({
try {
renameSync("main.css", "styles.css")
} catch (error) {
console.log(error);
console.error(error);
}
});
},

60
src/l10n.ts Normal file
View file

@ -0,0 +1,60 @@
import { moment } from "obsidian";
import ar from "../locale/ar.json";
import cz from "../locale/cz.json";
import da from "../locale/da.json";
import de from "../locale/de.json";
import en from "../locale/en.json";
import enGB from "../locale/en-gb.json";
import es from "../locale/es.json";
import fr from "../locale/fr.json";
import hi from "../locale/hi.json";
import id from "../locale/id.json";
import it from "../locale/it.json";
import ja from "../locale/ja.json";
import ko from "../locale/ko.json";
import nl from "../locale/nl.json";
import no from "../locale/no.json";
import pl from "../locale/pl.json";
import pt from "../locale/pt.json";
import ptBR from "../locale/pt-br.json";
import ro from "../locale/ro.json";
import ru from "../locale/ru.json";
import tr from "../locale/tr.json";
import zhCN from "../locale/zh-cn.json";
import zhTW from "../locale/zh-tw.json";
const localeMap = {
ar,
cs: cz,
da,
de,
en,
"en-gb": enGB,
es,
fr,
hi,
id,
it,
ja,
ko,
nl,
nn: no,
pl,
pt,
"pt-br": ptBR,
ro,
ru,
tr,
"zh-cn": zhCN,
"zh-tw": zhTW,
};
const locale = localeMap[moment.locale() as keyof typeof localeMap];
export default function t(str: string): string {
if (!locale) {
console.error("Error: dictionary locale not found", moment.locale());
}
return (locale && locale[str as keyof typeof locale]) || en[str as keyof typeof en];
}

View file

@ -1,17 +1,18 @@
import { Plugin } from 'obsidian';
import { DEFAULT_SETTINGS } from './constants';
import CommanderSettingTab from './ui/settingTab';
import { CommanderSettings, Macro } from './types';
import t from './l10n';
import { EditorMenuCommandManager, FileMenuCommandManager } from './manager/menuManager';
import SettingTabModal from './ui/settingTabModal';
import RibbonManager from './manager/ribbonManager';
import TitleBarManager from './manager/titleBarManager';
import StatusBarManager from './manager/statusBarManager';
import PageHeaderManager from './manager/pageHeaderManager';
import RibbonManager from './manager/ribbonManager';
import StatusBarManager from './manager/statusBarManager';
import TitleBarManager from './manager/titleBarManager';
import { CommanderSettings, Macro } from './types';
import MacroModal from './ui/macroModal';
import CommanderSettingTab from './ui/settingTab';
import SettingTabModal from './ui/settingTabModal';
import "./styles.scss";
import 'beautiful-react-diagrams/styles.css';
import "./styles.scss";
export default class CommanderPlugin extends Plugin {
public settings: CommanderSettings;
@ -28,20 +29,6 @@ export default class CommanderPlugin extends Plugin {
public async onload(): Promise<void> {
await this.loadSettings();
this.addSettingTab(new CommanderSettingTab(this));
this.addCommand({
name: "Open Commander Settings",
id: "open-commander-settings",
callback: () => new SettingTabModal(this).open(),
});
this.addCommand({
name: "Open Macro Builder",
id: "open-macro-builder",
callback: () => new MacroModal(this).open(),
});
this.manager = {
editorMenu: new EditorMenuCommandManager(this, this.settings.editorMenu),
fileMenu: new FileMenuCommandManager(this, this.settings.fileMenu),
@ -52,6 +39,20 @@ export default class CommanderPlugin extends Plugin {
pageHeader: new PageHeaderManager(this, this.settings.pageHeader),
};
this.addSettingTab(new CommanderSettingTab(this));
this.addCommand({
name: t("Open Commander Settings"),
id: "open-commander-settings",
callback: () => new SettingTabModal(this).open(),
});
this.addCommand({
name: t("Open Macro Builder"),
id: "open-macro-builder",
callback: () => new MacroModal(this).open(),
});
this.registerEvent(
app.workspace.on('editor-menu', this.manager.editorMenu.applyEditorMenuCommands(this)),
);

View file

@ -16,6 +16,5 @@ export default abstract class CommandManager {
// eslint-disable-next-line no-unused-vars
public abstract removeCommand(pair: CommandIconPair): Promise<void> | void;
// eslint-disable-nextline no-unused-vars
public abstract reorder(): Promise<void> | void;
}

View file

@ -6,6 +6,7 @@ import ConfirmDeleteModal from "../ui/confirmDeleteModal";
import { chooseNewCommand, getCommandFromId, isModeActive } from "../util";
import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
import ChooseIconModal from "src/ui/chooseIconModal";
import t from "src/l10n";
abstract class Base extends CommandManager {
public async addCommand(pair: CommandIconPair): Promise<void> {
@ -39,7 +40,7 @@ abstract class Base extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle("Change Icon")
.setTitle(t("Change Icon"))
.setIcon("box")
.onClick(async () => {
const newIcon = await (new ChooseIconModal(plugin)).awaitSelection();
@ -51,7 +52,7 @@ abstract class Base extends CommandManager {
})
.addItem(item => {
item
.setTitle("Rename")
.setTitle(t("Rename"))
.setIcon("text-cursor-input")
.onClick(async () => {
const newName = await (new ChooseCustomNameModal(cmdPair.name)).awaitSelection();
@ -64,7 +65,7 @@ abstract class Base extends CommandManager {
.addItem(item => {
item.dom.addClass("is-warning");
item
.setTitle("Delete")
.setTitle(t("Delete"))
.setIcon("lucide-trash")
.onClick(async () => {
if (!plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(plugin).didChooseRemove())) {
@ -87,7 +88,7 @@ abstract class Base extends CommandManager {
};
const setRemovable = (): void => {
optionEl.style.display = "block";
item.setTitle("Delete").setIcon("trash").onClick(async (event) => {
item.setTitle(t("Delete")).setIcon("trash").onClick(async (event) => {
event.preventDefault();
event.stopImmediatePropagation();
if (!plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(plugin).didChooseRemove())) {
@ -125,7 +126,7 @@ abstract class Base extends CommandManager {
if (plugin.settings.showAddCommand) {
menu.addItem((item: MenuItem) => {
item
.setTitle("Add command")
.setTitle(t("Add command"))
.setIcon("plus-circle")
.setSection("cmdr")
.onClick(async () => {

View file

@ -1,4 +1,5 @@
import { Menu, setIcon } from "obsidian";
import t from "src/l10n";
import CommanderPlugin from "src/main";
import { CommandIconPair } from "src/types";
import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
@ -8,7 +9,7 @@ import { chooseNewCommand, isModeActive } from "src/util";
import CommandManager from "./_commandManager";
export default class PageHeaderManager extends CommandManager {
private addBtn = createDiv({ cls: "cmdr view-action cmdr-adder", attr: { "aria-label": "Add new" } });
private addBtn = createDiv({ cls: "cmdr view-action cmdr-adder", attr: { "aria-label": t("Add new") } });
public constructor(plugin: CommanderPlugin, pairArray: CommandIconPair[]) {
super(plugin, pairArray);
@ -23,12 +24,11 @@ export default class PageHeaderManager extends CommandManager {
classes: string[],
tag: 'a' | 'div' = 'a'
): HTMLElement {
const tooltip = name;
const buttonClasses = classes.concat([id]);
const buttonIcon = createEl(tag, {
cls: buttonClasses,
attr: { 'aria-label-position': 'bottom', 'aria-label': tooltip },
attr: { 'aria-label-position': 'bottom', 'aria-label': name },
});
setIcon(buttonIcon, icon, iconSize);
return buttonIcon;
@ -57,7 +57,7 @@ export default class PageHeaderManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle("Add Command")
.setTitle(t("Add Command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);
@ -67,7 +67,7 @@ export default class PageHeaderManager extends CommandManager {
.addSeparator()
.addItem(item => {
item
.setTitle("Change Icon")
.setTitle(t("Change Icon"))
.setIcon("box")
.onClick(async () => {
const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection();
@ -80,7 +80,7 @@ export default class PageHeaderManager extends CommandManager {
})
.addItem(item => {
item
.setTitle("Rename")
.setTitle(t("Rename"))
.setIcon("text-cursor-input")
.onClick(async () => {
const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection();
@ -94,7 +94,7 @@ export default class PageHeaderManager extends CommandManager {
.addItem(item => {
item.dom.addClass("is-warning");
item
.setTitle("Delete")
.setTitle(t("Delete"))
.setIcon("lucide-trash")
.onClick(async () => {
if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) {

View file

@ -7,6 +7,7 @@ import ConfirmDeleteModal from "../ui/confirmDeleteModal";
import { chooseNewCommand, getCommandFromId } from "../util";
import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
import ChooseIconModal from "src/ui/chooseIconModal";
import t from 'src/l10n';
export default class RibbonManager extends CommandManager {
private actions: {
@ -27,7 +28,7 @@ export default class RibbonManager extends CommandManager {
if (this.side === "right") {
this.addActionContainer();
}
this.addBtn = createDiv({ cls: "cmdr side-dock-ribbon-action cmdr-adder", attr: { "aria-label-position": side === "left" ? "right" : "left", "aria-label": "Add new" } });
this.addBtn = createDiv({ cls: "cmdr side-dock-ribbon-action cmdr-adder", attr: { "aria-label-position": side === "left" ? "right" : "left", "aria-label": t("Add new") } });
this.init();
});
@ -39,7 +40,7 @@ export default class RibbonManager extends CommandManager {
if (cmd) {
this.addAction(pair.name ?? cmd.name, pair.icon, pair, () => app.commands.executeCommandById(pair.id));
} else {
this.addAction(`This Command seems to have been removed. ${pair.name ? "(" + pair.name + ")" : ""}`, "trash", pair, (event: MouseEvent) => {
this.addAction(t("This Command seems to have been removed. {{command_name}}").replace("{{command_name}}", pair.name || ""), "trash", pair, (event: MouseEvent) => {
this.removeAction((event.target as HTMLElement).getAttribute("aria-label") + "trash");
});
}
@ -119,7 +120,7 @@ export default class RibbonManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle("Add Command")
.setTitle(t("Add Command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);
@ -129,7 +130,7 @@ export default class RibbonManager extends CommandManager {
.addSeparator()
.addItem(item => {
item
.setTitle("Change Icon")
.setTitle(t("Change Icon"))
.setIcon("box")
.onClick(async () => {
const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection();
@ -142,7 +143,7 @@ export default class RibbonManager extends CommandManager {
})
.addItem(item => {
item
.setTitle("Rename")
.setTitle(t("Rename"))
.setIcon("text-cursor-input")
.onClick(async () => {
const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection();
@ -156,7 +157,7 @@ export default class RibbonManager extends CommandManager {
.addItem(item => {
item.dom.addClass("is-warning");
item
.setTitle("Delete")
.setTitle(t("Delete"))
.setIcon("lucide-trash")
.onClick(async () => {
if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) {

View file

@ -1,4 +1,5 @@
import { Menu, setIcon } from "obsidian";
import t from "src/l10n";
import CommanderPlugin from "src/main";
import { CommandIconPair } from "src/types";
import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
@ -10,7 +11,7 @@ import CommandManager from "./_commandManager";
export default class StatusBarManager extends CommandManager {
private container: HTMLElement;
private readonly actions = new Map<CommandIconPair, HTMLElement>();
private addBtn = createDiv({ cls: "cmdr status-bar-item cmdr-adder", attr: { "aria-label-position": "top", "aria-label": "Add new" } });
private addBtn = createDiv({ cls: "cmdr status-bar-item cmdr-adder", attr: { "aria-label-position": "top", "aria-label": t("Add new") } });
public constructor(plugin: CommanderPlugin, pairs: CommandIconPair[]) {
super(plugin, pairs);
@ -41,7 +42,7 @@ export default class StatusBarManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle("Add Command")
.setTitle(t("Add Command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);
@ -81,7 +82,7 @@ export default class StatusBarManager extends CommandManager {
}
private addAction(pair: CommandIconPair): void {
const btn = createDiv({ cls: "cmdr status-bar-item", attr: { "aria-label-position": "top", "aria-label": pair.name } });
const btn = createDiv({ cls: "cmdr status-bar-item clickable-icon", attr: { "aria-label-position": "top", "aria-label": pair.name, "style": "margin: 0" } });
this.actions.set(pair, btn);
let isRemovable = false;
@ -118,7 +119,7 @@ export default class StatusBarManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle("Add Command")
.setTitle(t("Add Command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);
@ -128,7 +129,7 @@ export default class StatusBarManager extends CommandManager {
.addSeparator()
.addItem(item => {
item
.setTitle("Change Icon")
.setTitle(t("Change Icon"))
.setIcon("box")
.onClick(async () => {
const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection();
@ -141,7 +142,7 @@ export default class StatusBarManager extends CommandManager {
})
.addItem(item => {
item
.setTitle("Rename")
.setTitle(t("Rename"))
.setIcon("text-cursor-input")
.onClick(async () => {
const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection();
@ -155,7 +156,7 @@ export default class StatusBarManager extends CommandManager {
.addItem(item => {
item.dom.addClass("is-warning");
item
.setTitle("Delete")
.setTitle(t("Delete"))
.setIcon("lucide-trash")
.onClick(async () => {
if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) {

View file

@ -1,4 +1,5 @@
import { Menu, setIcon } from "obsidian";
import t from "src/l10n";
import CommanderPlugin from "src/main";
import { CommandIconPair } from "src/types";
import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
@ -10,7 +11,7 @@ import CommandManager from "./_commandManager";
export default class TitleBarManager extends CommandManager {
private container: HTMLElement;
private readonly actions = new Map<CommandIconPair, HTMLElement>();
private addBtn = createDiv({ cls: "cmdr titlebar-button cmdr-adder", attr: { "aria-label": "Add new" } });
private addBtn = createDiv({ cls: "cmdr titlebar-button cmdr-adder", attr: { "aria-label": t("Add new") } });
public constructor(plugin: CommanderPlugin, pairArray: CommandIconPair[]) {
super(plugin, pairArray);
@ -95,7 +96,7 @@ export default class TitleBarManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle("Add Command")
.setTitle(t("Add Command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);
@ -105,7 +106,7 @@ export default class TitleBarManager extends CommandManager {
.addSeparator()
.addItem(item => {
item
.setTitle("Change Icon")
.setTitle(t("Change Icon"))
.setIcon("box")
.onClick(async () => {
const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection();
@ -118,7 +119,7 @@ export default class TitleBarManager extends CommandManager {
})
.addItem(item => {
item
.setTitle("Rename")
.setTitle(t("Rename"))
.setIcon("text-cursor-input")
.onClick(async () => {
const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection();
@ -132,7 +133,7 @@ export default class TitleBarManager extends CommandManager {
.addItem(item => {
item.dom.addClass("is-warning");
item
.setTitle("Delete")
.setTitle(t("Delete"))
.setIcon("lucide-trash")
.onClick(async () => {
if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) {

View file

@ -74,6 +74,7 @@
.cmdr-add-new-wrapper {
width: 100%;
margin-top: 12px;
margin-bottom: 2rem;
display: flex;
justify-content: center;

View file

@ -1,33 +1,34 @@
import { Command, setIcon, FuzzySuggestModal, FuzzyMatch } from "obsidian";
import t from "src/l10n";
import CommanderPlugin from "src/main";
export default class AddCommandModal extends FuzzySuggestModal<Command> {
plugin: CommanderPlugin;
commands: Command[];
private plugin: CommanderPlugin;
private commands: Command[];
constructor(plugin: CommanderPlugin) {
public constructor(plugin: CommanderPlugin) {
super(app);
this.plugin = plugin;
this.commands = Object.values(app.commands.commands);
this.setPlaceholder("Choose a Command to add");
this.setPlaceholder(t("Choose a Command to add"));
this.setInstructions([
{
command: "↑↓",
purpose: "to navigate"
purpose: t("to navigate")
},
{
command: "↵",
purpose: "to choose an icon"
purpose: t("to choose an icon")
},
{
command: "esc",
purpose: "to cancel"
purpose: t("to cancel")
},
]);
}
async awaitSelection(): Promise<Command> {
public async awaitSelection(): Promise<Command> {
this.open();
return new Promise((resolve, reject) => {
this.onChooseItem = (item): void => resolve(item);
@ -36,7 +37,7 @@ export default class AddCommandModal extends FuzzySuggestModal<Command> {
});
}
renderSuggestion(item: FuzzyMatch<Command>, el: HTMLElement): void {
public renderSuggestion(item: FuzzyMatch<Command>, el: HTMLElement): void {
super.renderSuggestion(item, el);
//Append the icon if available
@ -45,15 +46,15 @@ export default class AddCommandModal extends FuzzySuggestModal<Command> {
}
}
getItems(): Command[] {
public getItems(): Command[] {
return this.commands;
}
getItemText(item: Command): string {
public getItemText(item: Command): string {
return item.name;
}
// This will be overriden anyway, but typescript complains if it's not declared
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-empty-function
onChooseItem(item: Command, evt: MouseEvent | KeyboardEvent): void { }
public onChooseItem(item: Command, evt: MouseEvent | KeyboardEvent): void { }
}

View file

@ -1,4 +1,5 @@
import { SuggestModal } from "obsidian";
import t from "src/l10n";
export default class ChooseCustomNameModal extends SuggestModal<string> {
@ -6,21 +7,21 @@ export default class ChooseCustomNameModal extends SuggestModal<string> {
// eslint-disable-next-line no-unused-vars
public constructor(private defaultName: string) {
super(app);
this.setPlaceholder("Use a custom name");
this.setPlaceholder(t("Use a custom name"));
this.resultContainerEl.style.display = "none";
this.setInstructions([
{
command: "",
purpose: "Choose a custom Name for your new Command"
purpose: t("Choose a custom Name for your new Command")
},
{
command: "↵",
purpose: "to save"
purpose: t("to save")
},
{
command: "esc",
purpose: "to cancel"
purpose: t("to cancel")
},
]);
}

View file

@ -1,6 +1,7 @@
import { ICON_LIST } from './../constants';
import { setIcon, FuzzySuggestModal, FuzzyMatch } from "obsidian";
import CommanderPlugin from "src/main";
import t from 'src/l10n';
export default class ChooseIconModal extends FuzzySuggestModal<string> {
private plugin: CommanderPlugin;
@ -8,20 +9,20 @@ export default class ChooseIconModal extends FuzzySuggestModal<string> {
public constructor(plugin: CommanderPlugin) {
super(app);
this.plugin = plugin;
this.setPlaceholder("Choose a Icon for your new Command");
this.setPlaceholder(t("Choose a Icon for your new Command"));
this.setInstructions([
{
command: "↑↓",
purpose: "to navigate"
purpose: t("to navigate")
},
{
command: "↵",
purpose: "to choose a custom name"
purpose: t("to choose a custom icon")
},
{
command: "esc",
purpose: "to cancel"
purpose: t("to cancel")
},
]);
}

View file

@ -1,5 +1,6 @@
import { h } from "preact";
import { useState, useRef, useEffect, Ref } from "preact/hooks";
import t from "src/l10n";
interface Props {
value: string;
@ -34,7 +35,7 @@ export default function ChangeableText({ value, handleChange }: Props): h.JSX.El
ref={el}
/>
) : (
<span onDblClick={(): void => setShowInput(true)} aria-label="Double click to rename">
<span onDblClick={(): void => setShowInput(true)} aria-label={t("Double click to rename")}>
{value}
</span>
)

View file

@ -3,6 +3,7 @@ import { CommandIconPair } from "src/types";
import { getCommandFromId } from "src/util";
import ChangeableText from "./ChangeableText";
import { ObsidianIcon } from "src/util";
import t from "src/l10n";
interface CommandViewerProps {
pair: CommandIconPair;
@ -28,25 +29,25 @@ export default function CommandComponent({ pair, handleRemove, handleDown, handl
const isChecked = cmd.hasOwnProperty("checkCallback") || cmd.hasOwnProperty("editorCheckCallback");
const modeIcon = getModeIcon(pair.mode);
const modeName = pair.mode.match(/desktop|mobile|any/) ? pair.mode[0].toUpperCase() + pair.mode.substring(1) : `This device`;
const modeName = pair.mode.match(/desktop|mobile|any/) ? pair.mode[0].toUpperCase() + pair.mode.substring(1) : t("This device");
return (
<Fragment>
<div className="setting-item">
<ObsidianIcon icon={pair.icon} size={20} aria-label="Choose new" onClick={handleNewIcon} className="cmdr-icon clickable-icon" />
<ObsidianIcon icon={pair.icon} size={20} aria-label={t("Choose new")} onClick={handleNewIcon} className="cmdr-icon clickable-icon" />
<div className="setting-item-info">
<div className="setting-item-name">
{/* @ts-ignore */}
<ChangeableText handleChange={({ target }): void => handleRename(target?.value)} value={pair.name} />
{pair.name !== cmd.name && <span style="margin-left: .8ex">({cmd.name})</span>}
</div>
<div className="setting-item-description">Added by {isInternal ? "Obsidian" : owningPlugin.name}. {isChecked ? "Warning: This is a checked Command, meaning it might not run under every circumstance." : ""}</div>
<div className="setting-item-description">{t("Added by {{plugin_name}}.".replace("{{plugin_name}}", isInternal ? "Obsidian" : owningPlugin.name))} {isChecked ? t("Warning: This is a checked Command, meaning it might not run under every circumstance.") : ""}</div>
</div>
<div className="setting-item-control">
<ObsidianIcon icon="arrow-down" className="setting-editor-extra-setting-button clickable-icon" onClick={handleDown} aria-label="Move down" />
<ObsidianIcon icon="arrow-up" className="setting-editor-extra-setting-button clickable-icon" onClick={handleUp} aria-label="Move up" />
<ObsidianIcon icon={modeIcon} className="setting-editor-extra-setting-button clickable-icon" onClick={handleModeChange} aria-label={`Change Mode (Currently: ${modeName})`} />
<button className="mod-warning" style="display: flex" onClick={handleRemove} aria-label="Delete">
<ObsidianIcon icon="arrow-down" className="setting-editor-extra-setting-button clickable-icon" onClick={handleDown} aria-label={t("Move down")} />
<ObsidianIcon icon="arrow-up" className="setting-editor-extra-setting-button clickable-icon" onClick={handleUp} aria-label={t("Move up")} />
<ObsidianIcon icon={modeIcon} className="setting-editor-extra-setting-button clickable-icon" onClick={handleModeChange} aria-label={t("Change Mode (Currently: {{current_mode}})").replace("{{current_mode}}", modeName)} />
<button className="mod-warning" style="display: flex" onClick={handleRemove} aria-label={t("Delete")}>
<ObsidianIcon icon="lucide-trash" />
</button>
</div>

View file

@ -7,7 +7,7 @@ import { chooseNewCommand, isModeActive } from "src/util";
import { arrayMoveMutable } from "array-move";
import ChooseIconModal from "../chooseIconModal";
import ConfirmDeleteModal from "../confirmDeleteModal";
import { CommandIconPair } from "src/types";
import t from "src/l10n";
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
export const ManagerContext = createContext<CommandManager>(null!);
@ -56,12 +56,12 @@ export default function CommandViewer({ manager, plugin }: CommandViewerProps):
/>;
}
})}
{!manager.pairs.some((pre) => isModeActive(pre.mode)) && <div class="cmdr-commands-empty">
{!manager.pairs.some((pre) => isModeActive(pre.mode) || pre.mode.match(/mobile|desktop/)) && <div class="cmdr-commands-empty">
{/* This isn't really dangerous,
as the svg is inserted at build time and no other data can be passed to it */}
<div class="cmdr-icon-wrapper" dangerouslySetInnerHTML={{ __html: logo }} />
<h3>No commands here!</h3>
<span>Would you like to add one now?</span>
<h3>{t("No commands here!")}</h3>
<span>{t("Would you like to add one now?")}</span>
</div>}
<div className="cmdr-add-new-wrapper">
@ -70,10 +70,11 @@ export default function CommandViewer({ manager, plugin }: CommandViewerProps):
onClick={async (): Promise<void> => {
const pair = await chooseNewCommand(plugin);
await manager.addCommand(pair);
manager.reorder();
this.forceUpdate();
}}
>
Add command
{t("Add command")}
</button>
</div>
</ManagerContext.Provider>

View file

@ -1,10 +1,11 @@
import { Fragment, h } from "preact";
import t from "src/l10n";
import ConfirmDeleteModal from "../confirmDeleteModal";
export function confirmDeleteComponent({ modal }: { modal: ConfirmDeleteModal; }): h.JSX.Element {
return (
<Fragment>
<p>Are you sure you want to delete the Command?</p>
<p>{t("Are you sure you want to delete the Command?")}</p>
<div className="modal-button-container">
<button className="mod-warning" onClick={async (): Promise<void> => {
modal.plugin.settings.confirmDeletion = false;
@ -13,19 +14,19 @@ export function confirmDeleteComponent({ modal }: { modal: ConfirmDeleteModal; }
modal.remove = true;
modal.close();
}}>
Remove and don't ask again
{t("Remove and don't ask again")}
</button>
<button className="mod-warning" onClick={(): void => {
modal.remove = true;
modal.close();
}}>
Remove
{t("Remove")}
</button>
<button onClick={(): void => {
modal.remove = false;
modal.close();
}}>
Cancel
{t("Cancel")}
</button>
</div>
</Fragment>

View file

@ -1,15 +1,15 @@
import { setIcon } from "obsidian";
import confetti from "canvas-confetti";
import { Notice } from "obsidian";
import { Fragment, h } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import { useEffect, useState } from "preact/hooks";
import t from "src/l10n";
import { ObsidianIcon } from "src/util";
import CommanderPlugin from "../../main";
import CommandViewer from "./commandViewerComponent";
import { ToggleComponent } from "./settingComponent";
import confetti from "canvas-confetti";
export default function settingTabComponent({ plugin, mobileMode }: { plugin: CommanderPlugin; mobileMode: boolean; }): h.JSX.Element {
const [activeTab, setActiveTab] = useState(0);
const coffeeIcon = useRef<HTMLDivElement>(null);
const tabToNextTab = ({ key, shiftKey }: KeyboardEvent): void => {
if (shiftKey && key === "Tab") {
@ -28,18 +28,13 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co
return () => removeEventListener("keydown", tabToNextTab);
});
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
setIcon(coffeeIcon.current!, "coffee", 24);
}, []);
const tabs = [
{
name: "General",
name: t("General"),
tab: <Fragment>
<ToggleComponent
name="Always ask before removing?"
description="Always show a Popup to confirm deletion of a Command."
name={t("Always ask before removing?")}
description={t("Always show a Popup to confirm deletion of a Command.")}
value={plugin.settings.confirmDeletion}
changeHandler={async (value): Promise<void> => {
plugin.settings.confirmDeletion = !value;
@ -47,16 +42,29 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co
}} />
<ToggleComponent
value={plugin.settings.showAddCommand}
name='Show "Add Command" Button'
description='Show the "Add Command" Button in every Menu. Requires restart.'
name={t("Show \"Add Command\" Button")}
description={t("Show the \"Add Command\" Button in every Menu. Requires restart.")}
changeHandler={async (value): Promise<void> => {
plugin.settings.showAddCommand = !value;
if (!plugin.settings.showAddCommand) {
const elements = document.getElementsByClassName("cmdr-adder");
const x: Element[] = [];
for (let i = 0; i < elements.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
x.push(elements.item(i)!);
}
x.forEach((pre) => pre.remove());
} else {
new Notice(t("Please restart Obsidian for these changes to take effect."));
}
await plugin.saveSettings();
}} />
<ToggleComponent
value={plugin.settings.debug}
name='Enable debugging'
description='Enable console output.'
name={t("Enable debugging")}
description={t("Enable console output.")}
changeHandler={async (value): Promise<void> => {
plugin.settings.debug = !value;
await plugin.saveSettings();
@ -64,31 +72,31 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co
</Fragment>
},
{
name: "Editor Menu",
name: t("Editor Menu"),
tab: <CommandViewer manager={plugin.manager.editorMenu} plugin={plugin} />
},
{
name: "File Menu",
name: t("File Menu"),
tab: <CommandViewer manager={plugin.manager.fileMenu} plugin={plugin} />
},
{
name: "Left Ribbon",
name: t("Left Ribbon"),
tab: <CommandViewer manager={plugin.manager.leftRibbon} plugin={plugin} />
},
{
name: "Right Ribbon",
name: t("Right Ribbon"),
tab: <CommandViewer manager={plugin.manager.rightRibbon} plugin={plugin} />
},
{
name: "Titlebar",
name: t("Titlebar"),
tab: <CommandViewer manager={plugin.manager.titleBar} plugin={plugin} />
},
{
name: "Statusbar",
name: t("Statusbar"),
tab: <CommandViewer manager={plugin.manager.statusBar} plugin={plugin} />
},
{
name: "Page Header",
name: t("Page Header"),
tab: <CommandViewer manager={plugin.manager.pageHeader} plugin={plugin} />
}
];
@ -97,13 +105,14 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co
<Fragment>
<div className="cmdr-setting-title">
<h1>{plugin.manifest.name}</h1>
<div
<ObsidianIcon
icon="coffee"
size={24}
className="clickable-icon"
ref={coffeeIcon}
aria-label="Support development"
aria-label={t("Support development")}
aria-label-position="left"
id="cmdr-coffee-btn"
onClick={async (): Promise<void> => {
onClick={async ({ target }): Promise<void> => {
const myCanvas = document.createElement('canvas');
document.body.appendChild(myCanvas);
myCanvas.style.position = "fixed";
@ -120,10 +129,9 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co
resize: true,
useWorker: true
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const pos = coffeeIcon.current!.getBoundingClientRect();
const pos = (target as HTMLDivElement).getBoundingClientRect();
setTimeout(() => location.replace("https://buymeacoffee.com/phibr0"), 800);
setTimeout(() => location.replace("https://buymeacoffee.com/phibr0"), Math.random() * 800 + 500);
await myConfetti({
particleCount: 150,

View file

@ -1,5 +1,6 @@
import { Modal } from "obsidian";
import { h, render, VNode } from "preact";
import t from "src/l10n";
import CommanderPlugin from "src/main";
import { confirmDeleteComponent } from "./components/confirmDeleteComponent";
@ -13,7 +14,7 @@ export default class ConfirmDeleteModal extends Modal {
}
public async onOpen(): Promise<void> {
this.titleEl.innerText = "Remove Command";
this.titleEl.innerText = t("Remove Command");
this.containerEl.style.zIndex = "99";
this.reactComponent = h(confirmDeleteComponent, { modal: this });
render(this.reactComponent, this.contentEl);

View file

@ -5,7 +5,7 @@ import ChooseIconModal from './ui/chooseIconModal';
import { Command, setIcon } from 'obsidian';
import ChooseCustomNameModal from './ui/chooseCustomNameModal';
import { ComponentProps, h } from 'preact';
import { useRef, useEffect } from 'preact/hooks';
import { useRef, useLayoutEffect } from 'preact/hooks';
/**
* It creates a modal, waits for the user to select a command, and then creates another modal to wait
@ -45,7 +45,7 @@ interface ObsidianIconProps extends ComponentProps<"div"> {
export function ObsidianIcon({ icon, size, ...props }: ObsidianIconProps): h.JSX.Element {
const iconEl = useRef<HTMLDivElement>(null);
useEffect(() => {
useLayoutEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
setIcon(iconEl.current!, icon, size);
}, [icon, size]);

View file

@ -15,7 +15,8 @@
"jsx": "preserve",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment",
"allowSyntheticDefaultImports": true
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"include": ["**/*.ts", "**/*.tsx"]
}