saberzero1_quartz-syncer/styles.css
Emile Bangma d522b479fb
Obsidian settings rework (#126)
* refactor: flatten nested git settings to top-level keys

Replace the nested `git: GitRemoteSettings` object in QuartzSyncerSettings
with flat top-level keys (gitRemoteUrl, gitBranch, gitCorsProxyUrl,
gitAuthType, gitAuthUsername, gitProviderHint) for compatibility with the
Obsidian 1.13 declarative settings API.

- Add settingsSchemaVersion field for migration gating
- Add migrateNestedGitSettings() for schema v1 → v2 migration
- Update getGitSettingsWithSecret() to construct the GitRemoteSettings
  DTO from flat keys + SecretStorageService
- Remove git.auth.secret from persisted settings (SecretStorageService only)
- Update SecretStorageService.migrateFromSettings() for new data shape
- Update all source and test references from settings.git.* to flat keys
- Preserve GitRemoteSettings and GitAuth as data transfer types used by
  RepositoryConnection and related services

* feat: adopt Obsidian 1.13 declarative settings API

Migrate the settings UI from imperative display() to the new
getSettingDefinitions() API introduced in Obsidian 1.13.

QuartzSyncerSettingTab now extends PluginSettingTab<QuartzSyncerSettings>
and returns six pages from getSettingDefinitions():

- Git and Quartz pages use imperative SettingPage subclasses for complex
  dynamic UI (connection status, remote config editor, plugin management)
- Frontmatter, Integration, Performance, and UI pages use declarative
  setting definitions with render callbacks for conditional visibility

Other changes:
- Update obsidian dependency to obsidianmd/obsidian-api#4c5889aa
- Bump minAppVersion to 1.13.0
- Remove custom tab orchestration (SettingView.ts, SyncerTab.ts)
- Replace inline style.display with CSS class for lint compliance

* feat: leverage visible, disabled, action and hide from latest API

Update obsidian dependency to obsidianmd/obsidian-api#8e116bf5 which
adds visible, disabled, validate, SettingPage.hide(), and removes the
PluginSettingTab generic parameter.

- Replace all render+addClass hidden workarounds with declarative
  visible callbacks (Frontmatter, Performance pages are now fully
  declarative with zero render callbacks)
- Add disabled flag to integration toggles for unavailable plugins
- Convert Clear cache from render button to SettingDefinitionAction
- Add hide() to GitSettingsPage (cancels debounced connection checks)
  and QuartzV5Page (resets async operation flags)
- Remove PluginSettingTab generic parameter and SettingsKey type aliases
- Replace deprecated setWarning() with setDestructive()

* fix: settings migration overwrites nested git values unconditionally

The migration from nested git settings to flat keys was guarded by
!gitRemoteUrl, which skipped the migration when both old and new keys
coexisted with conflicting values (e.g. gitBranch defaulting to "v4"
while git.branch was "v5"). Remove the guard so the nested object
always takes precedence until it is deleted.

Also persist settings immediately after migrations to prevent the
same migration from running on every plugin load.

* feat: add settings overview page with async status indicators

Add a landing page to the settings tab showing plugin version,
documentation links, configured repository/branch, connection status,
and detected Quartz version.

Static info renders immediately. Connection and version checks run
in the background and update in place once resolved.

Also remove ~200 lines of dead CSS from the old custom tab system,
integration enabled/disabled styles, and unused class references.

* fix: popup settings work-in-progress

* feat: updated to latest API changes

* fix: removed unused CSS

* docs: updated changelog

* chore: touch ups for release
2026-05-29 02:08:14 +02:00

642 lines
13 KiB
CSS

/* Quartz Syncer Publication Center */
.quartz-syncer-publisher-title-separator {
margin-top: 0;
margin-bottom: 15px;
}
.quartz-syncer-publisher-footer-separator {
margin-top: 15px;
margin-bottom: 15px;
}
.quartz-syncer-publisher-footer {
display: flex;
justify-content: flex-end;
position: sticky;
bottom: 0;
}
.quartz-syncer-publisher-loading-msg {
font-size: var(--font-ui-larger);
display: flex;
flex-grow: 0; /* Prevnets the loading message from stretching the container */
align-items: center;
flex-direction: column;
}
.quartz-syncer-progress-bar-text {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
button.quartz-syncer-publisher-button {
background-color: var(--interactive-accent);
color: var(--text-on-accent);
cursor: var(--cursor);
font-weight: var(--font-bold);
}
.quartz-syncer-publisher-loading-container {
width: 100%;
height: 5px;
margin-top: 10px;
}
.quartz-syncer-publisher-loading-bar {
background-color: var(--interactive-accent);
height: 100%;
transition: all 0.5s ease-in-out;
}
.quartz-syncer-publisher-published {
color: var(--text-success, var(--color-green));
}
.quartz-syncer-publisher-deleted {
color: var(--text-error, var(--color-red));
}
/* Quartz Syncer Diff View */
.quartz-syncer-diff-modal {
max-width: var(--modal-max-width, 100%);
width: var(--modal-width, 100%);
}
body.is-mobile .quartz-syncer-diff-modal {
width: 100%;
}
body.is-mobile .quartz-syncer-diff-view-container {
overflow-x: auto;
}
pre.quartz-syncer-diff-view {
display: block;
white-space: pre;
overflow-wrap: break-word;
width: fit-content;
}
pre.quartz-syncer-diff-view.quartz-syncer-diff-added {
background-color: rgb(
var(--background-modifier-success-rgb, var(--color-green-rgb)),
0.5
);
color: var(--text-on-accent);
}
pre.quartz-syncer-diff-view.quartz-syncer-diff-removed {
background-color: rgb(
var(--background-modifier-error-rgb, var(--color-red-rgb)),
0.5
);
color: var(--text-on-accent);
}
.quartz-syncer-diff-line {
white-space: pre;
overflow-wrap: break-word;
}
.quartz-syncer-diff-line-added {
background-color: var(--text-success, var(--color-green));
color: var(--text-on-accent);
text-decoration: overline;
}
.quartz-syncer-diff-line-removed {
background-color: var(--text-error, var(--color-red));
color: var(--text-on-accent);
text-decoration: line-through;
}
/* Quartz Syncer Tree Selectors */
.quartz-syncer-modal-content ul {
margin: 0;
list-style: none;
padding-left: 1.2rem;
user-select: none;
}
.quartz-syncer-modal-content li {
margin: 0.2rem 0;
}
.quartz-syncer-modal-content .no-arrow {
padding-left: calc(var(--icon-size) + 2px);
}
.quartz-syncer-modal-content .arrow {
cursor: var(--cursor);
display: inline-block;
transition: transform 200ms;
}
/* arrowDown svelte variable */
.quartz-syncer-modal-content .arrowDown {
transform: rotate(90deg);
}
/* isRoot svelte variable */
.quartz-syncer-modal-content ul.isRoot {
padding-left: 0;
}
.quartz-syncer-modal-content .root-header {
font-weight: var(--font-bold);
font-size: var(--font-ui-larger);
}
input:indeterminate {
background-color: var(--checkbox-color);
border-color: var(--checkbox-color);
}
input[type="checkbox"]:indeterminate::after {
content: "";
top: -1px;
left: -1px;
position: absolute;
width: var(--checkbox-size);
height: var(--checkbox-size);
display: block;
background-color: var(--checkbox-marker-color);
mask-position: 52% 52%;
mask-size: 65%;
mask-repeat: no-repeat;
mask-image: url('data:image/svg+xml; utf8,<svg fill="none" width="12px" height="12px" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><rect fill="%23000000" x="4" y="4" width="24" height="24"/></svg>');
}
.quartz-syncer-icon-diff {
cursor: var(--cursor);
display: inline-block;
margin-left: 4px;
}
/* File type badges */
.quartz-syncer-file-badge {
font-size: 9px;
font-weight: var(--font-bold);
padding: 1px 4px;
border-radius: var(--radius-s);
margin-left: 6px;
text-transform: uppercase;
vertical-align: middle;
}
.quartz-syncer-badge-base {
background-color: rgb(var(--color-purple-rgb, 147, 51, 234), 0.2);
color: var(--text-accent, var(--color-purple, #9333ea));
border: 1px solid rgb(var(--color-purple-rgb, 147, 51, 234), 0.3);
}
.quartz-syncer-badge-canvas {
background-color: rgb(var(--color-cyan-rgb, 6, 182, 212), 0.2);
color: var(--text-accent, var(--color-cyan, #06b6d4));
border: 1px solid rgb(var(--color-cyan-rgb, 6, 182, 212), 0.3);
}
/* Quartz Syncer Settings */
/* Quartz V5 Settings - Collapsible Sections */
.quartz-syncer-v5-section-heading {
cursor: var(--cursor);
user-select: none;
}
.quartz-syncer-v5-section-heading:hover {
background-color: var(--background-modifier-hover);
border-radius: var(--radius-s);
}
.quartz-syncer-v5-section-chevron {
display: inline-flex;
align-items: center;
margin-right: 4px;
transition: transform 200ms ease;
}
.quartz-syncer-v5-section-chevron-open {
transform: rotate(90deg);
}
.quartz-syncer-v5-section-content {
/* Optional subtle left border to show section grouping */
border-left: 2px solid var(--background-modifier-border);
margin-left: 8px;
padding-left: 12px;
}
.quartz-syncer-publish-status-view button:disabled {
pointer-events: none;
opacity: 0.4;
}
.quartz-syncer-publish-status-view ul {
list-style-type: none;
position: relative;
margin-left: 5px;
margin-top: 0;
max-height: 250px;
overflow: auto;
}
.quartz-syncer-publish-status-view h2 {
margin-top: 0;
margin-bottom: 5px;
}
.quartz-syncer-publish-status-view .collapsable {
cursor: var(--cursor);
margin-left: 10px;
}
.quartz-syncer-svg-icon {
margin-right: 4px;
}
/* GitHub connection status */
.quartz-syncer-connection-status {
font-weight: var(--font-bold);
}
.quartz-syncer-connection-status-failed {
color: var(--text-error, var(--color-red));
}
.quartz-syncer-connection-status-success {
color: var(--text-success, var(--color-green));
}
.quartz-syncer-connection-status-pending {
color: var(--text-warning, var(--color-orange));
}
/* Cog animation */
@keyframes quartz-syncer-rotate-animation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.quartz-syncer-rotate {
animation: quartz-syncer-rotate-animation 4s linear infinite;
}
.quartz-syncer-cog {
margin-left: 3px;
}
.quartz-syncer-cog-big {
width: 40px;
height: 40px;
}
/* Progress bar */
.quartz-syncer-progress-bar-container {
width: 100%;
height: 40px;
margin-top: 10px;
}
/* Publication center */
.quartz-syncer-modal-content:first-child {
width: 100%;
}
/* Token/Secret Storage UI */
.quartz-syncer-token-container {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.quartz-syncer-token-status {
font-size: var(--font-ui-smaller);
padding: 4px 8px;
border-radius: var(--radius-s);
display: inline-flex;
align-items: center;
gap: 4px;
}
.quartz-syncer-token-status::before {
content: "";
width: 8px;
height: 8px;
border-radius: 50%;
display: inline-block;
}
.quartz-syncer-token-status-set {
background-color: rgb(var(--color-green-rgb), 0.15);
color: var(--text-success, var(--color-green));
}
.quartz-syncer-token-status-set::before {
background-color: var(--text-success, var(--color-green));
}
.quartz-syncer-token-status-unset {
background-color: rgb(var(--color-orange-rgb), 0.15);
color: var(--text-warning, var(--color-orange));
}
.quartz-syncer-token-status-unset::before {
background-color: var(--text-warning, var(--color-orange));
}
.quartz-syncer-token-input-container {
display: flex;
gap: 4px;
align-items: center;
}
.quartz-syncer-token-input {
flex: 1;
padding: 6px 10px;
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-s);
background-color: var(--background-primary);
color: var(--text-normal);
font-family: var(--font-monospace);
}
.quartz-syncer-token-input:focus {
border-color: var(--interactive-accent);
outline: none;
}
.quartz-syncer-token-toggle {
padding: 6px;
border: none;
background: transparent;
cursor: var(--cursor);
color: var(--text-muted);
border-radius: var(--radius-s);
}
.quartz-syncer-token-toggle:hover {
color: var(--text-normal);
background-color: var(--background-modifier-hover);
}
.quartz-syncer-token-buttons {
display: flex;
gap: 8px;
}
.quartz-syncer-token-buttons button {
padding: 6px 12px;
border-radius: var(--radius-s);
cursor: var(--cursor);
font-size: var(--font-ui-small);
}
/* Plugin Browser Modal */
.quartz-syncer-plugin-browser {
width: 700px;
max-width: 90vw;
}
.quartz-syncer-plugin-browser .modal-content {
max-height: 70vh;
overflow-y: auto;
padding: 0 16px 16px;
}
.quartz-syncer-plugin-browser-loading {
text-align: center;
color: var(--text-muted);
padding: 24px 0;
}
.quartz-syncer-plugin-browser-controls {
display: flex;
gap: 8px;
margin-bottom: 12px;
position: sticky;
top: 0;
background: var(--modal-background);
padding: 8px 0;
z-index: 1;
}
.quartz-syncer-plugin-browser-search {
flex: 1;
padding: 6px 10px;
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-s);
background: var(--background-primary);
color: var(--text-normal);
font-size: var(--font-ui-small);
}
.quartz-syncer-plugin-browser-tag-filter {
padding: 6px 10px;
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-s);
background: var(--background-primary);
color: var(--text-normal);
font-size: var(--font-ui-small);
}
.quartz-syncer-plugin-browser-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.quartz-syncer-plugin-browser-empty {
text-align: center;
color: var(--text-muted);
padding: 16px 0;
}
.quartz-syncer-plugin-browser-card {
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-m);
padding: 12px;
}
.quartz-syncer-plugin-browser-card-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 4px;
}
.quartz-syncer-plugin-browser-card-name {
font-weight: var(--font-bold);
font-size: var(--font-ui-medium);
}
.quartz-syncer-plugin-browser-badge-official {
font-size: var(--font-ui-smaller);
color: var(--text-on-accent);
background: var(--interactive-accent);
padding: 1px 6px;
border-radius: var(--radius-s);
}
.quartz-syncer-plugin-browser-card-desc {
color: var(--text-muted);
font-size: var(--font-ui-small);
margin: 0 0 8px;
}
.quartz-syncer-plugin-browser-card-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.quartz-syncer-plugin-browser-card-tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.quartz-syncer-plugin-browser-tag {
font-size: var(--font-ui-smaller);
color: var(--text-muted);
background: var(--background-secondary);
padding: 1px 6px;
border-radius: var(--radius-s);
}
.quartz-syncer-plugin-browser-installed {
font-size: var(--font-ui-small);
color: var(--text-success);
font-weight: var(--font-bold);
}
.quartz-syncer-plugin-browser-install-btn {
padding: 4px 12px;
border-radius: var(--radius-s);
background: var(--interactive-accent);
color: var(--text-on-accent);
cursor: var(--cursor);
font-size: var(--font-ui-small);
font-weight: var(--font-bold);
border: none;
white-space: nowrap;
}
.quartz-syncer-plugin-browser-install-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Quartz V5 Settings - Search */
.quartz-syncer-v5-search-bar {
position: sticky;
top: 0;
z-index: 1;
background: var(--background-primary);
padding: 8px 0;
border-bottom: 1px solid var(--background-modifier-border);
}
.quartz-syncer-v5-search-results {
font-size: var(--font-ui-smaller);
color: var(--text-muted);
margin-left: 8px;
}
.quartz-syncer-v5-no-results {
text-align: center;
color: var(--text-muted);
padding: 24px 0;
font-size: var(--font-ui-medium);
}
/* Quartz V5 Settings - Sticky Action Bar */
.quartz-syncer-v5-action-bar {
position: sticky;
bottom: 0;
z-index: 1;
background: var(--background-primary);
padding: 8px 0;
border-top: 1px solid var(--background-modifier-border);
margin-top: 16px;
}
.quartz-syncer-v5-action-bar .setting-item {
border-top: none;
padding-top: 8px;
}
/* Git Settings - Status Pills */
.quartz-syncer-git-status-container {
display: inline-flex;
gap: 6px;
margin-left: 8px;
vertical-align: middle;
}
.quartz-syncer-git-status-pill {
font-size: var(--font-ui-smaller);
padding: 2px 8px;
border-radius: var(--radius-s);
display: inline-flex;
align-items: center;
gap: 4px;
font-weight: var(--font-bold);
}
.quartz-syncer-git-status-pill::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
display: inline-block;
}
.quartz-syncer-git-status-success {
background-color: rgb(var(--color-green-rgb), 0.15);
color: var(--text-success, var(--color-green));
}
.quartz-syncer-git-status-success::before {
background-color: var(--text-success, var(--color-green));
}
.quartz-syncer-git-status-failed {
background-color: rgb(var(--color-red-rgb), 0.15);
color: var(--text-error, var(--color-red));
}
.quartz-syncer-git-status-failed::before {
background-color: var(--text-error, var(--color-red));
}
.quartz-syncer-git-status-pending {
background-color: rgb(var(--color-orange-rgb), 0.15);
color: var(--text-warning, var(--color-orange));
}
.quartz-syncer-git-status-pending::before {
background-color: var(--text-warning, var(--color-orange));
}
/* Plugin Options Modal */
.quartz-syncer-plugin-options-modal {
width: 600px;
max-width: 90vw;
}
.quartz-syncer-plugin-options-modal .modal-content {
max-height: 70vh;
overflow-y: auto;
padding: 0 16px 16px;
}