mirror of
https://github.com/onlyworlds/obsidian-plugin.git
synced 2026-07-22 11:00:31 +00:00
Major rebuild. Plugin now uses @onlyworlds/sdk for API calls via Obsidian's requestUrl, native PluginSettingTab for configuration, and a debounced auto-sync engine that pushes element edits to onlyworlds.com after idle. Changes - Drop handrolled API code; route all writes through @onlyworlds/sdk subclass - Native settings tab: API key, PIN, default world, sync mode, debounce - PIN handling: persist in settings or cache per session; no per-save prompts - Auto-sync toggle with configurable debounce (default 3s) - Status bar + ribbon icon reflect sync state (idle/dirty/syncing/synced/error) - Ribbon click opens menu (Sync / Settings / About) instead of firing sync - Settings API key wins over per-world World.md (legacy fallback preserved) - Add Map, Pin, Marker to element category enum (now 22) - ESLint config (eslint-plugin-obsidianmd) scoped to new code - Modernize build: TS 5.8, esbuild 0.25, stricter tsconfig - Drop dead code: GraphViewExtensions, dead command imports, handleApiError Compatibility - Existing v1 vaults work unchanged. Span-tag format preserved. - OnlyWorlds/Settings.md still readable; new settings tab takes precedence. - isDesktopOnly: true. Mobile pending verification.
191 lines
3.9 KiB
CSS
191 lines
3.9 KiB
CSS
/* styles.css */
|
|
|
|
/* Sync status bar layout */
|
|
.ow-sync-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
|
|
/* Sync status bar spinner */
|
|
.ow-sync-status .ow-spin,
|
|
.ow-ribbon.ow-spin {
|
|
display: inline-flex;
|
|
animation: ow-spin 1.5s linear infinite;
|
|
}
|
|
@keyframes ow-spin {
|
|
from { transform: rotate(0deg); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
|
|
|
|
.text-field::after, .number-field::after, .link-field::after, .multi-link-field::after {
|
|
content: attr(data-tooltip);
|
|
visibility: hidden;
|
|
background-color: black;
|
|
color: white;
|
|
text-align: center;
|
|
border-radius: 6px;
|
|
padding: 5px 10px;
|
|
position: absolute;
|
|
z-index: 1;
|
|
bottom: 100%;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: max-content;
|
|
max-width: 300px;
|
|
font-size: 0.75em;
|
|
}
|
|
|
|
.text-field:hover::after, .number-field:hover::after, .link-field:hover::after, .multi-link-field:hover::after {
|
|
visibility: visible;
|
|
}
|
|
|
|
.text-field {
|
|
color: whitesmoke;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.number-field {
|
|
font-style: italic;
|
|
color: whitesmoke;
|
|
}
|
|
|
|
.link-field {
|
|
color: whitesmoke;
|
|
border-bottom: 1px dotted rgb(114, 180, 208);
|
|
|
|
}
|
|
.multi-link-field {
|
|
color: ghostwhite;
|
|
text-decoration: none;
|
|
border-bottom: 1px dotted rgb(27, 102, 232);
|
|
}
|
|
|
|
.custom-link {
|
|
color: var(--text-link);
|
|
text-decoration: underline;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.custom-link:hover {
|
|
color: var(--text-link-hover);
|
|
text-decoration: underline;
|
|
}
|
|
.node-character {
|
|
fill: blue; /* SVG fill color for character nodes */
|
|
}
|
|
|
|
.node-location {
|
|
fill: green; /* SVG fill color for location nodes */
|
|
}
|
|
|
|
.node-event {
|
|
fill: red; /* SVG fill color for event nodes */
|
|
}
|
|
/* Styles for WorldPasteModal textarea */
|
|
.world-paste-textarea {
|
|
width: 100%;
|
|
min-height: 200px;
|
|
border: 1px solid grey;
|
|
padding: 10px;
|
|
margin-bottom: 10px; /* Spacing between textarea and button */
|
|
}
|
|
|
|
/* Specific styles for valid and invalid input */
|
|
.world-paste-textarea.valid {
|
|
border-color: lightgreen;
|
|
}
|
|
|
|
.world-paste-textarea.invalid {
|
|
border-color: salmon;
|
|
}
|
|
|
|
/* Styles for the submit button in WorldPasteModal */
|
|
.world-paste-submit-button {
|
|
width: 100%;
|
|
padding: 10px;
|
|
background-color: var(--interactive-normal);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 5px;
|
|
transition: background-color 0.3s, opacity 0.3s;
|
|
}
|
|
|
|
.world-paste-submit-button.disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.world-paste-submit-button:not(.disabled):hover {
|
|
background-color: var(--interactive-hover);
|
|
cursor: pointer;
|
|
}
|
|
/* Styles specific to the WorldRenameModal */
|
|
.rename-modal-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
|
|
.rename-dropdown {
|
|
width: 100%;
|
|
}
|
|
|
|
.rename-input {
|
|
width: 100%;
|
|
padding: 10px;
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.rename-button {
|
|
width: 100%;
|
|
padding: 10px;
|
|
background-color: var(--interactive-normal);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 5px;
|
|
opacity: 0.5; /* Start as disabled */
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.rename-button:not(.disabled) {
|
|
opacity: 1.0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.rename-button:not(.disabled):hover {
|
|
background-color: var(--interactive-hover);
|
|
}
|
|
.key-selection-modal {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.key-selection-dropdown {
|
|
width: 100%;
|
|
}
|
|
|
|
.key-selection-input {
|
|
width: 100%;
|
|
padding: 10px;
|
|
margin-top: 10px;
|
|
border: 1px solid var(--background-modifier-border);
|
|
}
|
|
|
|
.key-selection-submit-button {
|
|
width: 100%;
|
|
padding: 10px;
|
|
background-color: var(--interactive-normal);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.key-selection-submit-button:hover {
|
|
background-color: var(--interactive-hover);
|
|
}
|