mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
feat(settings): add dedicated Interface settings tab with Fluent/Legacy mode selection
- Create new InterfaceSettingsTab with visual mode selection using SelectableCard component - Move Fluent interface settings from Beta tab to new Interface tab - Remove deprecated ribbon icon setting - Conditionally show Fluent-specific settings based on selected mode - Add Interface tab to Core Settings category in main settings
This commit is contained in:
parent
75162619d6
commit
af31b39f30
4 changed files with 264 additions and 140 deletions
|
|
@ -2,6 +2,7 @@ export { renderAboutSettingsTab } from "./tabs/AboutSettingsTab";
|
|||
export { renderBetaTestSettingsTab } from "./tabs/BetaTestSettingsTab";
|
||||
export { renderHabitSettingsTab } from "./tabs/HabitSettingsTab";
|
||||
export { IcsSettingsComponent } from "./tabs/IcsSettingsTab";
|
||||
export { renderInterfaceSettingsTab } from "./tabs/InterfaceSettingsTab";
|
||||
export { renderProgressSettingsTab } from "./tabs/ProgressSettingsTab";
|
||||
export { renderQuickCaptureSettingsTab } from "./tabs/QuickCaptureSettingsTab";
|
||||
export { renderRewardSettingsTab } from "./tabs/RewardSettingsTab";
|
||||
|
|
|
|||
|
|
@ -41,146 +41,6 @@ export function renderBetaTestSettingsTab(
|
|||
),
|
||||
});
|
||||
|
||||
// Base View Settings
|
||||
|
||||
// V2 View Settings
|
||||
new Setting(containerEl)
|
||||
.setName(t("Task Genius Fluent Interface"))
|
||||
.setDesc(
|
||||
t(
|
||||
"Enable the experimental V2 interface with improved layout and workspace support"
|
||||
)
|
||||
)
|
||||
.addToggle((toggle) => {
|
||||
toggle
|
||||
.setValue(
|
||||
settingTab.plugin.settings.fluentView?.enableFluent ?? false
|
||||
)
|
||||
.onChange(async (value) => {
|
||||
if (!settingTab.plugin.settings.fluentView) {
|
||||
settingTab.plugin.settings.fluentView = {
|
||||
enableFluent: false,
|
||||
showFluentRibbon: false,
|
||||
};
|
||||
}
|
||||
settingTab.plugin.settings.fluentView!.enableFluent = value;
|
||||
await settingTab.plugin.saveSettings();
|
||||
|
||||
// Notify user
|
||||
new Notice(
|
||||
value
|
||||
? t(
|
||||
"Fluent interface enabled. Use the command 'Open Task View V2' to launch."
|
||||
)
|
||||
: t("Fluent interface disabled.")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("Show Fluent(beta) View Ribbon Icon"))
|
||||
.setDesc(t("Show a ribbon icon for quick access to Fluent interface"))
|
||||
.addToggle((toggle) => {
|
||||
toggle
|
||||
.setValue(
|
||||
settingTab.plugin.settings.fluentView?.showFluentRibbon ??
|
||||
false
|
||||
)
|
||||
.onChange(async (value) => {
|
||||
if (!settingTab.plugin.settings.fluentView) {
|
||||
settingTab.plugin.settings.fluentView = {
|
||||
enableFluent: false,
|
||||
showFluentRibbon: false,
|
||||
};
|
||||
}
|
||||
settingTab.plugin.settings.fluentView!.showFluentRibbon =
|
||||
value;
|
||||
await settingTab.plugin.saveSettings();
|
||||
|
||||
new Notice(
|
||||
t(
|
||||
"Please reload the plugin for ribbon icon changes to take effect."
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// V2: Use workspace side leaves for Sidebar & Details
|
||||
new Setting(containerEl)
|
||||
.setName(t("Fluent: Use Workspace Side Leaves"))
|
||||
.setDesc(
|
||||
t(
|
||||
"Use left/right workspace side leaves for Sidebar and Details. When enabled, the main V2 view won't render in-view sidebar or details."
|
||||
)
|
||||
)
|
||||
.addToggle((toggle) => {
|
||||
const current = ((settingTab.plugin.settings.fluentView)?.useWorkspaceSideLeaves ?? true);
|
||||
toggle
|
||||
.setValue(current)
|
||||
.onChange(async (value) => {
|
||||
if (!settingTab.plugin.settings.fluentView) {
|
||||
settingTab.plugin.settings.fluentView = {
|
||||
enableFluent: false,
|
||||
showFluentRibbon: false,
|
||||
};
|
||||
}
|
||||
if (!settingTab.plugin.settings.fluentView.fluentConfig) {
|
||||
settingTab.plugin.settings.fluentView.fluentConfig = {
|
||||
enableWorkspaces: true,
|
||||
defaultWorkspace: "default",
|
||||
showTopNavigation: true,
|
||||
showNewSidebar: true,
|
||||
allowViewSwitching: true,
|
||||
persistViewMode: true,
|
||||
};
|
||||
}
|
||||
// Store via 'any' to avoid typing constraints for experimental backfill
|
||||
((settingTab.plugin.settings.fluentView)).useWorkspaceSideLeaves = value;
|
||||
await settingTab.plugin.saveSettings();
|
||||
new Notice(t("Saved. Reopen the view to apply."));
|
||||
});
|
||||
});
|
||||
|
||||
// V2 Sidebar Other Views overflow threshold
|
||||
new Setting(containerEl)
|
||||
.setName(t("Fluent: Max Other Views before overflow"))
|
||||
.setDesc(
|
||||
t(
|
||||
"Number of 'Other Views' to show before grouping the rest into an overflow menu (ellipsis)"
|
||||
)
|
||||
)
|
||||
.addText((text) => {
|
||||
const current =
|
||||
settingTab.plugin.settings.fluentView?.fluentConfig
|
||||
?.maxOtherViewsBeforeOverflow ?? 5;
|
||||
text.setPlaceholder("5")
|
||||
.setValue(String(current))
|
||||
.onChange(async (value) => {
|
||||
const n = parseInt(value, 10);
|
||||
if (!isNaN(n) && n >= 1 && n <= 50) {
|
||||
if (!settingTab.plugin.settings.fluentView) {
|
||||
settingTab.plugin.settings.fluentView = {
|
||||
enableFluent: false,
|
||||
showFluentRibbon: false,
|
||||
};
|
||||
}
|
||||
if (!settingTab.plugin.settings.fluentView.fluentConfig) {
|
||||
settingTab.plugin.settings.fluentView.fluentConfig = {
|
||||
enableWorkspaces: true,
|
||||
defaultWorkspace: "default",
|
||||
showTopNavigation: true,
|
||||
showNewSidebar: true,
|
||||
allowViewSwitching: true,
|
||||
persistViewMode: true,
|
||||
};
|
||||
}
|
||||
settingTab.plugin.settings.fluentView.fluentConfig.maxOtherViewsBeforeOverflow =
|
||||
n;
|
||||
await settingTab.plugin.saveSettings();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Feedback section
|
||||
new Setting(containerEl)
|
||||
.setName(t("Beta Feedback"))
|
||||
|
|
|
|||
246
src/components/features/settings/tabs/InterfaceSettingsTab.ts
Normal file
246
src/components/features/settings/tabs/InterfaceSettingsTab.ts
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
import { Setting, Notice } from "obsidian";
|
||||
import { TaskProgressBarSettingTab } from "@/setting";
|
||||
import { t } from "@/translations/helper";
|
||||
import {
|
||||
SelectableCard,
|
||||
SelectableCardConfig,
|
||||
} from "@/components/features/onboarding/ui/SelectableCard";
|
||||
|
||||
export function renderInterfaceSettingsTab(
|
||||
settingTab: TaskProgressBarSettingTab,
|
||||
containerEl: HTMLElement
|
||||
) {
|
||||
// Header
|
||||
new Setting(containerEl)
|
||||
.setName(t("User Interface"))
|
||||
.setDesc(
|
||||
t(
|
||||
"Choose your preferred interface style and configure how Task Genius displays in your workspace."
|
||||
)
|
||||
)
|
||||
.setHeading();
|
||||
|
||||
// Mode Selection Section
|
||||
new Setting(containerEl)
|
||||
.setName(t("Interface Mode"))
|
||||
.setDesc(
|
||||
t(
|
||||
"Select between the modern Fluent interface or the classic Legacy interface."
|
||||
)
|
||||
)
|
||||
.setHeading();
|
||||
|
||||
// Create mode selection container
|
||||
const modeSelectionContainer = containerEl.createDiv({
|
||||
cls: "interface-mode-selection",
|
||||
});
|
||||
|
||||
// Get current mode
|
||||
const currentMode = settingTab.plugin.settings.fluentView?.enableFluent
|
||||
? "fluent"
|
||||
: "legacy";
|
||||
|
||||
// Create cards configuration
|
||||
const cardConfigs: SelectableCardConfig<string>[] = [
|
||||
{
|
||||
id: "fluent",
|
||||
title: t("Fluent"),
|
||||
subtitle: t("Modern & Sleek"),
|
||||
description: t(
|
||||
"New visual design with elegant animations and modern interactions"
|
||||
),
|
||||
preview: createFluentPreview(),
|
||||
},
|
||||
{
|
||||
id: "legacy",
|
||||
title: t("Legacy"),
|
||||
subtitle: t("Classic & Familiar"),
|
||||
description: t(
|
||||
"Keep the familiar interface and interaction style you know"
|
||||
),
|
||||
preview: createLegacyPreview(),
|
||||
},
|
||||
];
|
||||
|
||||
// Create selectable cards
|
||||
const card = new SelectableCard<string>(
|
||||
modeSelectionContainer,
|
||||
cardConfigs,
|
||||
{
|
||||
containerClass: "selectable-cards-container",
|
||||
cardClass: "selectable-card",
|
||||
showPreview: true,
|
||||
},
|
||||
async (mode) => {
|
||||
// Update settings
|
||||
if (!settingTab.plugin.settings.fluentView) {
|
||||
settingTab.plugin.settings.fluentView = {
|
||||
enableFluent: false,
|
||||
showFluentRibbon: false,
|
||||
};
|
||||
}
|
||||
settingTab.plugin.settings.fluentView.enableFluent = mode === "fluent";
|
||||
await settingTab.plugin.saveSettings();
|
||||
|
||||
// Re-render the settings to show/hide Fluent-specific options
|
||||
renderFluentSpecificSettings();
|
||||
}
|
||||
);
|
||||
|
||||
// Set initial selection
|
||||
card.setSelected(currentMode);
|
||||
|
||||
// Container for Fluent-specific settings
|
||||
const fluentSettingsContainer = containerEl.createDiv({
|
||||
cls: "fluent-specific-settings",
|
||||
});
|
||||
|
||||
// Function to render Fluent-specific settings
|
||||
const renderFluentSpecificSettings = () => {
|
||||
// Clear the container
|
||||
fluentSettingsContainer.empty();
|
||||
|
||||
// Only show if Fluent is enabled
|
||||
if (!settingTab.plugin.settings.fluentView?.enableFluent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fluent Settings Header
|
||||
new Setting(fluentSettingsContainer)
|
||||
.setName(t("Fluent Interface Settings"))
|
||||
.setDesc(t("Configure options specific to the Fluent interface."))
|
||||
.setHeading();
|
||||
|
||||
// Use workspace side leaves for Sidebar & Details
|
||||
new Setting(fluentSettingsContainer)
|
||||
.setName(t("Use Workspace Side Leaves"))
|
||||
.setDesc(
|
||||
t(
|
||||
"Use left/right workspace side leaves for Sidebar and Details. When enabled, the main V2 view won't render in-view sidebar or details."
|
||||
)
|
||||
)
|
||||
.addToggle((toggle) => {
|
||||
const current = settingTab.plugin.settings.fluentView?.useWorkspaceSideLeaves ?? true;
|
||||
toggle
|
||||
.setValue(current)
|
||||
.onChange(async (value) => {
|
||||
if (!settingTab.plugin.settings.fluentView) {
|
||||
settingTab.plugin.settings.fluentView = {
|
||||
enableFluent: false,
|
||||
showFluentRibbon: false,
|
||||
};
|
||||
}
|
||||
if (!settingTab.plugin.settings.fluentView.fluentConfig) {
|
||||
settingTab.plugin.settings.fluentView.fluentConfig = {
|
||||
enableWorkspaces: true,
|
||||
defaultWorkspace: "default",
|
||||
showTopNavigation: true,
|
||||
showNewSidebar: true,
|
||||
allowViewSwitching: true,
|
||||
persistViewMode: true,
|
||||
};
|
||||
}
|
||||
// Store via 'any' to avoid typing constraints for experimental backfill
|
||||
(settingTab.plugin.settings.fluentView as any).useWorkspaceSideLeaves = value;
|
||||
await settingTab.plugin.saveSettings();
|
||||
new Notice(t("Saved. Reopen the view to apply."));
|
||||
});
|
||||
});
|
||||
|
||||
// Max Other Views before overflow threshold
|
||||
new Setting(fluentSettingsContainer)
|
||||
.setName(t("Max Other Views before overflow"))
|
||||
.setDesc(
|
||||
t(
|
||||
"Number of 'Other Views' to show before grouping the rest into an overflow menu (ellipsis)"
|
||||
)
|
||||
)
|
||||
.addText((text) => {
|
||||
const current =
|
||||
settingTab.plugin.settings.fluentView?.fluentConfig
|
||||
?.maxOtherViewsBeforeOverflow ?? 5;
|
||||
text.setPlaceholder("5")
|
||||
.setValue(String(current))
|
||||
.onChange(async (value) => {
|
||||
const n = parseInt(value, 10);
|
||||
if (!isNaN(n) && n >= 1 && n <= 50) {
|
||||
if (!settingTab.plugin.settings.fluentView) {
|
||||
settingTab.plugin.settings.fluentView = {
|
||||
enableFluent: false,
|
||||
showFluentRibbon: false,
|
||||
};
|
||||
}
|
||||
if (!settingTab.plugin.settings.fluentView.fluentConfig) {
|
||||
settingTab.plugin.settings.fluentView.fluentConfig = {
|
||||
enableWorkspaces: true,
|
||||
defaultWorkspace: "default",
|
||||
showTopNavigation: true,
|
||||
showNewSidebar: true,
|
||||
allowViewSwitching: true,
|
||||
persistViewMode: true,
|
||||
};
|
||||
}
|
||||
settingTab.plugin.settings.fluentView.fluentConfig.maxOtherViewsBeforeOverflow = n;
|
||||
await settingTab.plugin.saveSettings();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Initial render of Fluent-specific settings
|
||||
renderFluentSpecificSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Fluent mode preview
|
||||
*/
|
||||
function createFluentPreview(): HTMLElement {
|
||||
const preview = createDiv({
|
||||
cls: ["mode-preview", "mode-preview-fluent"],
|
||||
});
|
||||
|
||||
// Check theme
|
||||
const isDark = document.body.classList.contains("theme-dark");
|
||||
const theme = isDark ? "" : "-light";
|
||||
const imageUrl = `https://raw.githubusercontent.com/Quorafind/Obsidian-Task-Progress-Bar/master/media/fluent${theme}.png`;
|
||||
|
||||
const img = preview.createEl("img", {
|
||||
attr: {
|
||||
src: imageUrl,
|
||||
alt: "Fluent mode preview",
|
||||
},
|
||||
});
|
||||
img.style.maxWidth = "100%";
|
||||
img.style.maxHeight = "100%";
|
||||
img.style.objectFit = "contain";
|
||||
img.style.borderRadius = "4px";
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Legacy mode preview
|
||||
*/
|
||||
function createLegacyPreview(): HTMLElement {
|
||||
const preview = createDiv({
|
||||
cls: ["mode-preview", "mode-preview-legacy"],
|
||||
});
|
||||
|
||||
// Check theme
|
||||
const isDark = document.body.classList.contains("theme-dark");
|
||||
const theme = isDark ? "" : "-light";
|
||||
const imageUrl = `https://raw.githubusercontent.com/Quorafind/Obsidian-Task-Progress-Bar/master/media/legacy${theme}.png`;
|
||||
|
||||
const img = preview.createEl("img", {
|
||||
attr: {
|
||||
src: imageUrl,
|
||||
alt: "Legacy mode preview",
|
||||
},
|
||||
});
|
||||
img.style.maxWidth = "100%";
|
||||
img.style.maxHeight = "100%";
|
||||
img.style.objectFit = "contain";
|
||||
img.style.borderRadius = "4px";
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import {
|
|||
renderAboutSettingsTab,
|
||||
renderBetaTestSettingsTab,
|
||||
renderHabitSettingsTab,
|
||||
renderInterfaceSettingsTab,
|
||||
renderProgressSettingsTab,
|
||||
renderTaskStatusSettingsTab,
|
||||
renderDatePrioritySettingsTab,
|
||||
|
|
@ -82,6 +83,12 @@ export class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
icon: "layout",
|
||||
category: "core",
|
||||
},
|
||||
{
|
||||
id: "interface",
|
||||
name: t("Interface"),
|
||||
icon: "layout-dashboard",
|
||||
category: "core",
|
||||
},
|
||||
{
|
||||
id: "file-filter",
|
||||
name: t("File Filter"),
|
||||
|
|
@ -673,6 +680,10 @@ export class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
const viewSettingsSection = this.createTabSection("view-settings");
|
||||
this.displayViewSettings(viewSettingsSection);
|
||||
|
||||
// Interface Tab
|
||||
const interfaceSection = this.createTabSection("interface");
|
||||
this.displayInterfaceSettings(interfaceSection);
|
||||
|
||||
// Reward Tab
|
||||
const rewardSection = this.createTabSection("reward");
|
||||
this.displayRewardSettings(rewardSection);
|
||||
|
|
@ -729,6 +740,8 @@ export class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
return `${base}/task-view/indexer`;
|
||||
case "view-settings":
|
||||
return `${base}/task-view`;
|
||||
case "interface":
|
||||
return `${base}/interface`;
|
||||
case "file-filter":
|
||||
return `${base}/file-filter`;
|
||||
case "progress-bar":
|
||||
|
|
@ -830,6 +843,10 @@ export class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
renderViewSettingsTab(this, containerEl);
|
||||
}
|
||||
|
||||
private displayInterfaceSettings(containerEl: HTMLElement): void {
|
||||
renderInterfaceSettingsTab(this, containerEl);
|
||||
}
|
||||
|
||||
private displayIndexSettings(containerEl: HTMLElement): void {
|
||||
renderIndexSettingsTab(this, containerEl);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue