feat: unify mounted workspace graph

This commit is contained in:
lucaronin
2026-05-08 00:45:21 +02:00
parent 7bda58bbf6
commit ef3aed64e3
55 changed files with 1707 additions and 189 deletions

86
src/utils/workspaces.ts Normal file
View File

@@ -0,0 +1,86 @@
import type { VaultEntry, WorkspaceIdentity } from '../types'
import type { VaultOption } from '../components/status-bar/types'
export const WORKSPACE_COLORS = ['blue', 'green', 'purple', 'orange', 'red', 'yellow'] as const
export type WorkspaceColor = typeof WORKSPACE_COLORS[number]
interface WorkspaceIdentityOptions {
defaultWorkspacePath?: string | null
}
function slugifyWorkspaceAlias(value: string): string {
const normalized = value
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
return normalized || 'workspace'
}
export function labelFromWorkspacePath(path: string): string {
return path.split(/[\\/]/).filter(Boolean).pop() || 'Workspace'
}
function shortLabelFromLabel(label: string): string {
const words = label.trim().split(/\s+/).filter(Boolean)
if (words.length === 0) return 'W'
if (words.length === 1) return words[0].slice(0, 2).toUpperCase()
return words.slice(0, 2).map((word) => word[0]?.toUpperCase() ?? '').join('')
}
export function workspaceAliasFromOption(vault: Pick<VaultOption, 'alias' | 'label' | 'path'>): string {
return slugifyWorkspaceAlias(vault.alias || vault.label || labelFromWorkspacePath(vault.path))
}
export function workspaceIdentityFromVault(
vault: VaultOption,
options: WorkspaceIdentityOptions = {},
): WorkspaceIdentity {
const label = vault.label.trim() || labelFromWorkspacePath(vault.path)
const alias = workspaceAliasFromOption({ ...vault, label })
return {
id: alias,
label,
alias,
path: vault.path,
shortLabel: shortLabelFromLabel(label),
color: vault.color ?? null,
icon: vault.icon ?? null,
mounted: vault.mounted !== false,
available: vault.available !== false,
defaultForNewNotes: options.defaultWorkspacePath === vault.path,
}
}
export function workspaceForEntry(entry: Pick<VaultEntry, 'workspace' | 'path'>): WorkspaceIdentity | null {
return entry.workspace ?? null
}
export function workspacePathForEntry(entry: Pick<VaultEntry, 'workspace'>): string | undefined {
return entry.workspace?.path
}
export function workspaceLabelForEntry(entry: Pick<VaultEntry, 'workspace'>): string | null {
return entry.workspace?.label ?? null
}
export function workspaceDisplayPrefix(entry: Pick<VaultEntry, 'workspace'>): string | null {
const workspace = workspaceForEntry(entry)
return workspace ? `${workspace.label} / ` : null
}
export function mountedWorkspacePaths(vaults: VaultOption[]): string[] {
return vaults
.filter((vault) => vault.available !== false && vault.mounted !== false)
.map((vault) => vault.path)
}
export function workspacesMountedInGraph<T extends { path: string; available?: boolean; mounted?: boolean; managedDefault?: boolean }>(
vaults: T[],
activeVaultPath: string,
): T[] {
return vaults.filter((vault) => {
if (vault.path === activeVaultPath) return true
return vault.available !== false && vault.mounted !== false && vault.managedDefault !== true
})
}