kanban和相关模版设置
This commit is contained in:
parent
ba7466a838
commit
98187939f4
5
.obsidian/community-plugins.json
vendored
5
.obsidian/community-plugins.json
vendored
@ -7,5 +7,8 @@
|
||||
"dataview",
|
||||
"weather-fetcher",
|
||||
"geocoding-properties",
|
||||
"obsidian-kanban"
|
||||
"metaedit",
|
||||
"kanban-status-updater",
|
||||
"obsidian-kanban",
|
||||
"templater-obsidian"
|
||||
]
|
5
.obsidian/plugins/kanban-status-updater/data.json
vendored
Normal file
5
.obsidian/plugins/kanban-status-updater/data.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"statusPropertyName": "status",
|
||||
"showNotifications": true,
|
||||
"debugMode": false
|
||||
}
|
480
.obsidian/plugins/kanban-status-updater/main.js
vendored
Normal file
480
.obsidian/plugins/kanban-status-updater/main.js
vendored
Normal file
@ -0,0 +1,480 @@
|
||||
'use strict';
|
||||
|
||||
var obsidian = require('obsidian');
|
||||
|
||||
/******************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
|
||||
function __awaiter(thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
}
|
||||
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
};
|
||||
|
||||
const DEFAULT_SETTINGS = {
|
||||
statusPropertyName: 'status',
|
||||
showNotifications: false,
|
||||
debugMode: false // Default to false for better performance
|
||||
};
|
||||
class KanbanStatusUpdaterPlugin extends obsidian.Plugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
// Track active observers to disconnect them when not needed
|
||||
this.currentObserver = null;
|
||||
this.isProcessing = false;
|
||||
this.activeKanbanBoard = null;
|
||||
}
|
||||
onload() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log('Loading Kanban Status Updater plugin');
|
||||
// Load settings
|
||||
yield this.loadSettings();
|
||||
// Display startup notification
|
||||
if (this.settings.showNotifications) {
|
||||
new obsidian.Notice('Kanban Status Updater activated');
|
||||
}
|
||||
this.log('Plugin loaded');
|
||||
// Register DOM event listener for drag events - but only process if active leaf is Kanban
|
||||
this.registerDomEvent(document, 'dragend', this.onDragEnd.bind(this));
|
||||
this.log('Registered drag event listener');
|
||||
// Watch for active leaf changes to only observe the current Kanban board
|
||||
this.registerEvent(this.app.workspace.on('active-leaf-change', this.onActiveLeafChange.bind(this)));
|
||||
// Initial check for active Kanban board
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.checkForActiveKanbanBoard();
|
||||
});
|
||||
// Add settings tab
|
||||
this.addSettingTab(new KanbanStatusUpdaterSettingTab(this.app, this));
|
||||
});
|
||||
}
|
||||
onunload() {
|
||||
// Disconnect any active observers to prevent memory leaks
|
||||
this.disconnectObservers();
|
||||
this.log('Plugin unloaded');
|
||||
}
|
||||
loadSettings() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
|
||||
});
|
||||
}
|
||||
saveSettings() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.saveData(this.settings);
|
||||
});
|
||||
}
|
||||
// Log helper with debug mode check
|
||||
log(message) {
|
||||
if (this.settings.debugMode) {
|
||||
console.log(`[KSU] ${message}`);
|
||||
}
|
||||
}
|
||||
// Clean up observers when switching away from a Kanban board
|
||||
disconnectObservers() {
|
||||
if (this.currentObserver) {
|
||||
this.log('Disconnecting observer for performance');
|
||||
this.currentObserver.disconnect();
|
||||
this.currentObserver = null;
|
||||
}
|
||||
this.activeKanbanBoard = null;
|
||||
}
|
||||
// Check if the active leaf is a Kanban board
|
||||
onActiveLeafChange(leaf) {
|
||||
this.checkForActiveKanbanBoard();
|
||||
}
|
||||
checkForActiveKanbanBoard() {
|
||||
var _a;
|
||||
// First disconnect any existing observers
|
||||
this.disconnectObservers();
|
||||
// Get the active leaf using the non-deprecated API
|
||||
const activeLeaf = this.app.workspace.getLeaf(false);
|
||||
if (!activeLeaf)
|
||||
return;
|
||||
try {
|
||||
// Find the content element safely
|
||||
let contentEl = null;
|
||||
// Use type assertions to avoid TypeScript errors
|
||||
if (activeLeaf.view) {
|
||||
// Try to access the contentEl property using type assertion
|
||||
contentEl = activeLeaf.view.contentEl || null;
|
||||
}
|
||||
// If that didn't work, try another approach
|
||||
if (!contentEl) {
|
||||
// Try to get the Kanban board directly from the DOM
|
||||
// Leaf containers have 'view-content' elements that contain the actual view
|
||||
const viewContent = (_a = activeLeaf.containerEl) === null || _a === void 0 ? void 0 : _a.querySelector('.view-content');
|
||||
if (viewContent) {
|
||||
contentEl = viewContent;
|
||||
}
|
||||
else {
|
||||
// Last resort - look for Kanban boards anywhere in the workspace
|
||||
contentEl = document.querySelector('.workspace-leaf.mod-active .view-content');
|
||||
}
|
||||
}
|
||||
if (!contentEl) {
|
||||
this.log('Could not access content element for active leaf');
|
||||
return;
|
||||
}
|
||||
// Check if this is a Kanban board
|
||||
const kanbanBoard = contentEl.querySelector('.kanban-plugin__board');
|
||||
if (kanbanBoard) {
|
||||
this.log('Found active Kanban board, setting up observer');
|
||||
// Store reference to active board
|
||||
this.activeKanbanBoard = kanbanBoard;
|
||||
// Set up observer only for this board
|
||||
this.setupObserverForBoard(kanbanBoard);
|
||||
}
|
||||
else {
|
||||
this.log('Active leaf is not a Kanban board');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.log(`Error detecting Kanban board: ${error.message}`);
|
||||
}
|
||||
}
|
||||
setupObserverForBoard(boardElement) {
|
||||
// Create a new observer for this specific board
|
||||
this.currentObserver = new MutationObserver((mutations) => {
|
||||
if (this.isProcessing)
|
||||
return;
|
||||
// Simple debounce to prevent rapid-fire processing
|
||||
this.isProcessing = true;
|
||||
setTimeout(() => {
|
||||
this.handleMutations(mutations);
|
||||
this.isProcessing = false;
|
||||
}, 300);
|
||||
});
|
||||
// Observe only this board with minimal options needed
|
||||
this.currentObserver.observe(boardElement, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: false // Don't need attribute changes for performance
|
||||
});
|
||||
this.log('Observer set up for active Kanban board');
|
||||
}
|
||||
handleMutations(mutations) {
|
||||
if (!this.activeKanbanBoard)
|
||||
return;
|
||||
try {
|
||||
const max_mutations = 10;
|
||||
// Only process a sample of mutations for performance
|
||||
const mutationsToProcess = mutations.length > max_mutations ?
|
||||
mutations.slice(0, max_mutations) : mutations;
|
||||
this.log(`Got ${mutationsToProcess.length} mutations of ${mutations.length}`);
|
||||
// Look for Kanban items in mutation
|
||||
let i = 0;
|
||||
for (const mutation of mutationsToProcess) {
|
||||
this.log(`Mutation #${++i} - Type: ${mutation.type}`);
|
||||
if (mutation.type === 'childList') {
|
||||
// Check added nodes for Kanban items
|
||||
for (const node of Array.from(mutation.addedNodes)) {
|
||||
try {
|
||||
// Check if node is any kind of Element (HTML or SVG)
|
||||
if (node instanceof Element) {
|
||||
this.log(`Processing Element of type: ${node.tagName}`);
|
||||
// Handle the node according to its type
|
||||
if (node instanceof HTMLElement || node instanceof HTMLDivElement) {
|
||||
// Direct processing for HTML elements
|
||||
this.log(`Found HTML element of type ${node.className}`);
|
||||
this.processElement(node);
|
||||
}
|
||||
else if (node instanceof SVGElement) {
|
||||
// For SVG elements, look for parent HTML element
|
||||
const parentElement = node.closest('.kanban-plugin__item');
|
||||
if (parentElement) {
|
||||
this.log('Found Kanban item parent of SVG element');
|
||||
this.processElement(parentElement);
|
||||
}
|
||||
else {
|
||||
// Look for any kanban items in the document that might have changed
|
||||
// This is for cases where the SVG update is related to a card movement
|
||||
const items = this.activeKanbanBoard.querySelectorAll('.kanban-plugin__item');
|
||||
if (items.length > 0) {
|
||||
// Process only the most recently modified item
|
||||
const recentItems = Array.from(items).slice(-1);
|
||||
for (const item of recentItems) {
|
||||
this.log('Processing recent item after SVG change');
|
||||
this.processElement(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node.nodeType === Node.TEXT_NODE) {
|
||||
// For text nodes, check the parent element
|
||||
const parentElement = node.parentElement;
|
||||
if (parentElement && (parentElement.classList.contains('kanban-plugin__item-title') ||
|
||||
parentElement.closest('.kanban-plugin__item'))) {
|
||||
this.log('Found text change in Kanban item');
|
||||
const itemElement = parentElement.closest('.kanban-plugin__item');
|
||||
if (itemElement) {
|
||||
this.processElement(itemElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.log(`Skipping node type: ${node.nodeType}`);
|
||||
}
|
||||
}
|
||||
catch (nodeError) {
|
||||
this.log(`Error processing node: ${nodeError.message}`);
|
||||
// Continue with next node even if this one fails
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.log('Ignoring mutation type: ' + mutation.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.log(`Error in handleMutations: ${error.message}`);
|
||||
}
|
||||
}
|
||||
onDragEnd(event) {
|
||||
// Only process if we have an active Kanban board
|
||||
if (!this.activeKanbanBoard || this.isProcessing) {
|
||||
this.log('Drag end detected but no active Kanban board or already processing');
|
||||
this.log('activeKanbanBoard: ' + (this.activeKanbanBoard ? 'Yes' : 'No'));
|
||||
this.log('isProcessing: ' + (this.isProcessing ? 'Yes' : 'No'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.log('Drag end detected');
|
||||
// Set processing flag to prevent multiple processing
|
||||
this.isProcessing = true;
|
||||
const target = event.target;
|
||||
if (!target)
|
||||
return;
|
||||
this.processElement(target);
|
||||
}
|
||||
catch (error) {
|
||||
this.log(`Error in onDragEnd: ${error.message}`);
|
||||
}
|
||||
finally {
|
||||
// Reset processing flag after a delay to debounce
|
||||
setTimeout(() => {
|
||||
this.isProcessing = false;
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
processElement(element) {
|
||||
try {
|
||||
// Only process if inside our active Kanban board
|
||||
if (!this.activeKanbanBoard || !element.closest('.kanban-plugin__board')) {
|
||||
this.log('Element NOT in active Kanban board. Skipping.');
|
||||
return;
|
||||
}
|
||||
// Use different strategies to find the Kanban item
|
||||
this.log("👀 Looking for Kanban item element");
|
||||
// Check if element is a Kanban item or contains one
|
||||
const kanbanItem = element.classList.contains('kanban-plugin__item')
|
||||
? element
|
||||
: element.querySelector('.kanban-plugin__item');
|
||||
if (kanbanItem) {
|
||||
this.log(`✅ Found Kanban item: ${kanbanItem}`);
|
||||
this.log('classList of kanbanItem: ' + kanbanItem.classList);
|
||||
this.processKanbanItem(kanbanItem);
|
||||
return;
|
||||
}
|
||||
this.log('Not a Kanban item, checking for parent');
|
||||
// If element is inside a Kanban item, find the parent
|
||||
const parentItem = element.closest('.kanban-plugin__item');
|
||||
this.log(`Parent item: ${parentItem ? parentItem : 'Not found'}`);
|
||||
if (parentItem) {
|
||||
this.processKanbanItem(parentItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.log(`Error in processElement: ${error.message}`);
|
||||
}
|
||||
}
|
||||
processKanbanItem(itemElement) {
|
||||
try {
|
||||
// TODO: Select the title
|
||||
const internalLink = itemElement.querySelector('.kanban-plugin__item-title .kanban-plugin__item-markdown a.internal-link');
|
||||
if (!internalLink) {
|
||||
this.log('🚫 No internal link found in item');
|
||||
return;
|
||||
}
|
||||
this.log(`Found internal link: ${internalLink.textContent}`);
|
||||
// Get the link path from data-href or href attribute
|
||||
const linkPath = internalLink.getAttribute('data-href') ||
|
||||
internalLink.getAttribute('href');
|
||||
if (!linkPath)
|
||||
return;
|
||||
this.log(`🔗 Link path: ${linkPath}`);
|
||||
// Find the lane (column) this item is in
|
||||
const lane = itemElement.closest('.kanban-plugin__lane');
|
||||
if (!lane) {
|
||||
this.log('🚫 No lane found for item');
|
||||
return;
|
||||
}
|
||||
// Get column name from the lane header
|
||||
const laneHeader = lane.querySelector('.kanban-plugin__lane-header-wrapper .kanban-plugin__lane-title');
|
||||
if (!laneHeader) {
|
||||
this.log('🚫 No laneHeader found for item');
|
||||
return;
|
||||
}
|
||||
const columnName = laneHeader.textContent.trim();
|
||||
this.log(`✅ Got lane name: ${columnName}`);
|
||||
this.log(`Processing card with link to "${linkPath}" in column "${columnName}"`);
|
||||
// Update the linked note's status
|
||||
this.updateNoteStatus(linkPath, columnName);
|
||||
}
|
||||
catch (error) {
|
||||
this.log(`Error in processKanbanItem: ${error.message}`);
|
||||
}
|
||||
}
|
||||
updateNoteStatus(notePath, status) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
// Find the linked file
|
||||
const file = this.app.metadataCache.getFirstLinkpathDest(notePath, '');
|
||||
if (!file) {
|
||||
if (this.settings.showNotifications) {
|
||||
new obsidian.Notice(`⚠️ Note "${notePath}" not found`, 3000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Get current status if it exists
|
||||
const metadata = this.app.metadataCache.getFileCache(file);
|
||||
let oldStatus = null;
|
||||
if ((metadata === null || metadata === void 0 ? void 0 : metadata.frontmatter) && metadata.frontmatter[this.settings.statusPropertyName]) {
|
||||
oldStatus = metadata.frontmatter[this.settings.statusPropertyName];
|
||||
}
|
||||
// Only update if status has changed
|
||||
if (oldStatus !== status) {
|
||||
// Use the processFrontMatter API to update the frontmatter
|
||||
yield this.app.fileManager.processFrontMatter(file, (frontmatter) => {
|
||||
// Set the status property
|
||||
frontmatter[this.settings.statusPropertyName] = status;
|
||||
});
|
||||
// Show notification if enabled
|
||||
if (this.settings.showNotifications) {
|
||||
if (oldStatus) {
|
||||
new obsidian.Notice(`Updated ${this.settings.statusPropertyName}: "${oldStatus}" → "${status}" for ${file.basename}`, 3000);
|
||||
}
|
||||
else {
|
||||
new obsidian.Notice(`Set ${this.settings.statusPropertyName}: "${status}" for ${file.basename}`, 3000);
|
||||
}
|
||||
}
|
||||
this.log(`Updated status for ${file.basename} to "${status}"`);
|
||||
}
|
||||
else {
|
||||
this.log(`Status already set to "${status}" for ${file.basename}, skipping update`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.log(`Error updating note status: ${error.message}`);
|
||||
if (this.settings.showNotifications) {
|
||||
new obsidian.Notice(`⚠️ Error updating status: ${error.message}`, 3000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Method for the test button to use
|
||||
runTest() {
|
||||
this.log('Running test...');
|
||||
// Make sure we're using the current active board
|
||||
this.checkForActiveKanbanBoard();
|
||||
if (!this.activeKanbanBoard) {
|
||||
new obsidian.Notice('⚠️ No active Kanban board found - open a Kanban board first', 5000);
|
||||
return;
|
||||
}
|
||||
// Find items in the active board
|
||||
const items = this.activeKanbanBoard.querySelectorAll('.kanban-plugin__item');
|
||||
const count = items.length;
|
||||
new obsidian.Notice(`Found ${count} cards in active Kanban board`, 3000);
|
||||
if (count > 0) {
|
||||
// Process the first item with a link
|
||||
for (let i = 0; i < count; i++) {
|
||||
const item = items[i];
|
||||
if (item.querySelector('a.internal-link')) {
|
||||
new obsidian.Notice(`Testing with card: "${item.textContent.substring(0, 20)}..."`, 3000);
|
||||
this.processKanbanItem(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class KanbanStatusUpdaterSettingTab extends obsidian.PluginSettingTab {
|
||||
constructor(app, plugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
display() {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
new obsidian.Setting(containerEl)
|
||||
.setName('Status property name')
|
||||
.setDesc('The name of the property to update when a card is moved')
|
||||
.addText(text => text
|
||||
.setPlaceholder('status')
|
||||
.setValue(this.plugin.settings.statusPropertyName)
|
||||
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
||||
this.plugin.settings.statusPropertyName = value;
|
||||
yield this.plugin.saveSettings();
|
||||
})));
|
||||
new obsidian.Setting(containerEl)
|
||||
.setName('Show notifications')
|
||||
.setDesc('Show a notification when a status is updated')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.showNotifications)
|
||||
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
||||
this.plugin.settings.showNotifications = value;
|
||||
yield this.plugin.saveSettings();
|
||||
})));
|
||||
new obsidian.Setting(containerEl)
|
||||
.setName('Debug mode')
|
||||
.setDesc('Enable detailed logging (reduces performance)')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.debugMode)
|
||||
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
||||
this.plugin.settings.debugMode = value;
|
||||
yield this.plugin.saveSettings();
|
||||
if (value) {
|
||||
new obsidian.Notice('Debug mode enabled - check console for logs', 3000);
|
||||
}
|
||||
else {
|
||||
new obsidian.Notice('Debug mode disabled', 3000);
|
||||
}
|
||||
})));
|
||||
// Add a test button
|
||||
new obsidian.Setting(containerEl)
|
||||
.setName('Test plugin')
|
||||
.setDesc('Test with current Kanban board')
|
||||
.addButton(button => button
|
||||
.setButtonText('Run Test')
|
||||
.onClick(() => {
|
||||
this.plugin.runTest();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = KanbanStatusUpdaterPlugin;
|
||||
|
||||
|
||||
/* nosourcemap */
|
10
.obsidian/plugins/kanban-status-updater/manifest.json
vendored
Normal file
10
.obsidian/plugins/kanban-status-updater/manifest.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "kanban-status-updater",
|
||||
"name": "Kanban Status Updater",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "1.1.0",
|
||||
"description": "Automatically updates a 'status' property in a note when its card is moved on a Kanban board",
|
||||
"author": "Ankit Kapur",
|
||||
"authorUrl": "https://github.com/ankit-kapur",
|
||||
"isDesktopOnly": false
|
||||
}
|
13
.obsidian/plugins/kanban-status-updater/styles.css
vendored
Normal file
13
.obsidian/plugins/kanban-status-updater/styles.css
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/* styles.css for Kanban Status Updater */
|
||||
|
||||
/* Status bar styling - minimal to ensure good performance */
|
||||
.kanban-status-updater-statusbar {
|
||||
color: var(--text-accent);
|
||||
font-size: 0.8em;
|
||||
padding: 0 8px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.kanban-status-updater-statusbar:hover {
|
||||
opacity: 1;
|
||||
}
|
25
.obsidian/plugins/metaedit/data.json
vendored
Normal file
25
.obsidian/plugins/metaedit/data.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"ProgressProperties": {
|
||||
"enabled": true,
|
||||
"properties": []
|
||||
},
|
||||
"IgnoredProperties": {
|
||||
"enabled": false,
|
||||
"properties": []
|
||||
},
|
||||
"AutoProperties": {
|
||||
"enabled": true,
|
||||
"properties": []
|
||||
},
|
||||
"EditMode": {
|
||||
"mode": "All Single",
|
||||
"properties": []
|
||||
},
|
||||
"KanbanHelper": {
|
||||
"enabled": true,
|
||||
"boards": []
|
||||
},
|
||||
"UIElements": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
5540
.obsidian/plugins/metaedit/main.js
vendored
Normal file
5540
.obsidian/plugins/metaedit/main.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
.obsidian/plugins/metaedit/manifest.json
vendored
Normal file
10
.obsidian/plugins/metaedit/manifest.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "metaedit",
|
||||
"name": "MetaEdit",
|
||||
"version": "1.8.2",
|
||||
"minAppVersion": "1.4.1",
|
||||
"description": "MetaEdit helps you manage your metadata.",
|
||||
"author": "Christian B. B. Houmann",
|
||||
"authorUrl": "https://bagerbach.com",
|
||||
"isDesktopOnly": false
|
||||
}
|
15
.obsidian/plugins/metaedit/styles.css
vendored
Normal file
15
.obsidian/plugins/metaedit/styles.css
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
.centerSettingContent {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.not-a-button {
|
||||
background: none;
|
||||
color: inherit;
|
||||
border: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
}
|
13
.obsidian/plugins/obsidian-kanban/data.json
vendored
13
.obsidian/plugins/obsidian-kanban/data.json
vendored
@ -1,3 +1,14 @@
|
||||
{
|
||||
"new-note-template": "templates/kanban_template.md"
|
||||
"new-note-template": "templates/kanban_template.md",
|
||||
"show-checkboxes": false,
|
||||
"hide-card-count": true,
|
||||
"link-date-to-daily-note": true,
|
||||
"metadata-keys": [
|
||||
{
|
||||
"metadataKey": "status",
|
||||
"label": "status",
|
||||
"shouldHideLabel": false,
|
||||
"containsMarkdown": false
|
||||
}
|
||||
]
|
||||
}
|
36
.obsidian/plugins/templater-obsidian/data.json
vendored
Normal file
36
.obsidian/plugins/templater-obsidian/data.json
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"command_timeout": 5,
|
||||
"templates_folder": "templates",
|
||||
"templates_pairs": [
|
||||
[
|
||||
"",
|
||||
""
|
||||
]
|
||||
],
|
||||
"trigger_on_file_creation": false,
|
||||
"auto_jump_to_cursor": false,
|
||||
"enable_system_commands": false,
|
||||
"shell_path": "",
|
||||
"user_scripts_folder": "",
|
||||
"enable_folder_templates": true,
|
||||
"folder_templates": [
|
||||
{
|
||||
"folder": "",
|
||||
"template": ""
|
||||
}
|
||||
],
|
||||
"enable_file_templates": false,
|
||||
"file_templates": [
|
||||
{
|
||||
"regex": ".*",
|
||||
"template": ""
|
||||
}
|
||||
],
|
||||
"syntax_highlighting": true,
|
||||
"syntax_highlighting_mobile": false,
|
||||
"enabled_templates_hotkeys": [
|
||||
""
|
||||
],
|
||||
"startup_templates": [],
|
||||
"intellisense_render": 1
|
||||
}
|
29
.obsidian/plugins/templater-obsidian/main.js
vendored
Normal file
29
.obsidian/plugins/templater-obsidian/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
11
.obsidian/plugins/templater-obsidian/manifest.json
vendored
Normal file
11
.obsidian/plugins/templater-obsidian/manifest.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"id": "templater-obsidian",
|
||||
"name": "Templater",
|
||||
"version": "2.11.1",
|
||||
"description": "Create and use templates",
|
||||
"minAppVersion": "1.5.0",
|
||||
"author": "SilentVoid",
|
||||
"authorUrl": "https://github.com/SilentVoid13",
|
||||
"helpUrl": "https://silentvoid13.github.io/Templater/",
|
||||
"isDesktopOnly": false
|
||||
}
|
220
.obsidian/plugins/templater-obsidian/styles.css
vendored
Normal file
220
.obsidian/plugins/templater-obsidian/styles.css
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
.templater_search {
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.templater_div {
|
||||
border-top: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.templater_div > .setting-item {
|
||||
border-top: none !important;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.templater_div > .setting-item > .setting-item-control {
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.templater_div
|
||||
> .setting-item
|
||||
> .setting-item-control
|
||||
> .setting-editor-extra-setting-button {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.templater_donating {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.templater_title {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.templater_template {
|
||||
align-self: center;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.templater_cmd {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.templater_div2 > .setting-item {
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.templater-prompt-div {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.templater-prompt-form {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.templater-prompt-input {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.templater-button-div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
textarea.templater-prompt-input {
|
||||
height: 10rem;
|
||||
}
|
||||
|
||||
textarea.templater-prompt-input:focus {
|
||||
border-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .templater-command-bg {
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
background-color: var(--background-primary-alt);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command {
|
||||
font-size: 0.85em;
|
||||
font-family: var(--font-monospace);
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.cm-s-obsidian .templater-inline .cm-templater-command {
|
||||
background-color: var(--background-primary-alt);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-templater-opening-tag {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-templater-closing-tag {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-templater-interpolation-tag {
|
||||
color: var(--code-property, #008bff);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-templater-execution-tag {
|
||||
color: var(--code-function, #c0d700);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-keyword {
|
||||
color: var(--code-keyword, #00a7aa);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-atom {
|
||||
color: var(--code-normal, #f39b35);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-value,
|
||||
.cm-s-obsidian .cm-templater-command.cm-number,
|
||||
.cm-s-obsidian .cm-templater-command.cm-type {
|
||||
color: var(--code-value, #a06fca);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-def,
|
||||
.cm-s-obsidian .cm-templater-command.cm-type.cm-def {
|
||||
color: var(--code-normal, var(--text-normal));
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-property,
|
||||
.cm-s-obsidian .cm-templater-command.cm-property.cm-def,
|
||||
.cm-s-obsidian .cm-templater-command.cm-attribute {
|
||||
color: var(--code-function, #98e342);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-variable,
|
||||
.cm-s-obsidian .cm-templater-command.cm-variable-2,
|
||||
.cm-s-obsidian .cm-templater-command.cm-variable-3,
|
||||
.cm-s-obsidian .cm-templater-command.cm-meta {
|
||||
color: var(--code-property, #d4d4d4);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-callee,
|
||||
.cm-s-obsidian .cm-templater-command.cm-operator,
|
||||
.cm-s-obsidian .cm-templater-command.cm-qualifier,
|
||||
.cm-s-obsidian .cm-templater-command.cm-builtin {
|
||||
color: var(--code-operator, #fc4384);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-tag {
|
||||
color: var(--code-tag, #fc4384);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-comment,
|
||||
.cm-s-obsidian .cm-templater-command.cm-comment.cm-tag,
|
||||
.cm-s-obsidian .cm-templater-command.cm-comment.cm-attribute {
|
||||
color: var(--code-comment, #696d70);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-string,
|
||||
.cm-s-obsidian .cm-templater-command.cm-string-2 {
|
||||
color: var(--code-string, #e6db74);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-header,
|
||||
.cm-s-obsidian .cm-templater-command.cm-hr {
|
||||
color: var(--code-keyword, #da7dae);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-link {
|
||||
color: var(--code-normal, #696d70);
|
||||
}
|
||||
|
||||
.cm-s-obsidian .cm-templater-command.cm-error {
|
||||
border-bottom: 1px solid #c42412;
|
||||
}
|
||||
|
||||
.CodeMirror-hints {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
|
||||
-webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
||||
-moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
border: 1px solid silver;
|
||||
|
||||
background: white;
|
||||
font-size: 90%;
|
||||
font-family: monospace;
|
||||
|
||||
max-height: 20em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-hint {
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
white-space: pre;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
li.CodeMirror-hint-active {
|
||||
background: #08f;
|
||||
color: white;
|
||||
}
|
85
.obsidian/workspace.json
vendored
85
.obsidian/workspace.json
vendored
@ -4,39 +4,44 @@
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "d0afed41b8685973",
|
||||
"id": "a6f094df0e179c24",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "74d64848bffd2359",
|
||||
"id": "4694fd15b957885a",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "new notes/快捷键设置.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "快捷键设置"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3985a6d657d77461",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "new notes/快捷键设置.md",
|
||||
"file": "templates/daily_template.md",
|
||||
"mode": "source",
|
||||
"source": true
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "快捷键设置"
|
||||
"title": "daily_template"
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "aa1061ad0c81038b",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "f18a369645815ad1",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "new notes/学习看板和其他 1.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "学习看板和其他 1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
@ -157,13 +162,13 @@
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"file": "new notes/快捷键设置.md",
|
||||
"file": "templates/daily_template.md",
|
||||
"followCursor": false,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-list",
|
||||
"title": "Outline of 快捷键设置"
|
||||
"title": "Outline of daily_template"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -181,7 +186,8 @@
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 409.5
|
||||
"width": 337.5,
|
||||
"collapsed": true
|
||||
},
|
||||
"left-ribbon": {
|
||||
"hiddenItems": {
|
||||
@ -196,30 +202,35 @@
|
||||
"terminal:Open terminal": false,
|
||||
"table-editor-obsidian:Advanced Tables Toolbar": false,
|
||||
"weather-fetcher:Insert Weather": false,
|
||||
"obsidian-kanban:Create new board": false
|
||||
"obsidian-kanban:Create new board": false,
|
||||
"card-board:CardBoard": false,
|
||||
"templater-obsidian:Templater": false
|
||||
}
|
||||
},
|
||||
"active": "3985a6d657d77461",
|
||||
"active": "4694fd15b957885a",
|
||||
"lastOpenFiles": [
|
||||
"new notes/快捷键设置.md",
|
||||
"templates/base_template.md",
|
||||
"new notes/Untitled Kanban 1.md",
|
||||
"new notes/Untitled Kanban.md",
|
||||
"templates/kanban_template.md",
|
||||
"kanban",
|
||||
"templates/daily_template.md",
|
||||
"new notes/2025-04-06.md",
|
||||
"new notes/pdf 插件的学习.md",
|
||||
"new notes/2025-04-05.md",
|
||||
"new notes/2025-04-04.md",
|
||||
"kanban/mainboard.md",
|
||||
"new notes/学习看板和其他 1.md",
|
||||
"templates/kanban_template.md",
|
||||
"new notes/学习看板和其他.md",
|
||||
"new notes/设置 nodeTest这个项目目录作为练手的项目.md",
|
||||
"new notes/chat history.md",
|
||||
"new notes/找到了如何入门obsidian的途径.md",
|
||||
"copilot-conversations/ubuntu lvm bindfs.md",
|
||||
"copilot-conversations/dataview ob q&a.md",
|
||||
"new notes/2025-04-06.md",
|
||||
"new notes/快捷键设置.md",
|
||||
"Task.md",
|
||||
"new notes/找到了如何入门obsidian的途径.md",
|
||||
"new notes/2025-04-04.md",
|
||||
"new notes/2025-04-05.md",
|
||||
"new notes/Untitled Kanban 1.md",
|
||||
"new notes/Untitled Kanban.md",
|
||||
"kanban",
|
||||
"new notes/pdf 插件的学习.md",
|
||||
"new notes/chat history.md",
|
||||
"Chats/New Chat.md",
|
||||
"new notes/Untitled.md",
|
||||
"Task.md",
|
||||
"欢迎.md",
|
||||
"Welcome.md",
|
||||
"templates/daily.md",
|
||||
|
32
kanban/mainboard.md
Normal file
32
kanban/mainboard.md
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
|
||||
kanban-plugin: board
|
||||
|
||||
---
|
||||
|
||||
## may be do
|
||||
|
||||
- [ ] [[学习看板和其他 1]]
|
||||
|
||||
|
||||
## will be do
|
||||
|
||||
- [ ] [[设置 nodeTest这个项目目录作为练手的项目]]
|
||||
|
||||
|
||||
## doing
|
||||
|
||||
|
||||
|
||||
## done
|
||||
|
||||
**Complete**
|
||||
|
||||
|
||||
|
||||
|
||||
%% kanban:settings
|
||||
```
|
||||
{"kanban-plugin":"board","list-collapse":[false,false,false,false],"metadata-keys":[{"metadataKey":"status","label":"","shouldHideLabel":false,"containsMarkdown":false}]}
|
||||
```
|
||||
%%
|
19
new notes/学习看板和其他 1.md
Normal file
19
new notes/学习看板和其他 1.md
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
date: 2025-04-06
|
||||
tags:
|
||||
- kanban
|
||||
- project
|
||||
title: 看板 -
|
||||
project_name: 练手
|
||||
status: may be do
|
||||
privority: 低
|
||||
---
|
||||
|
||||
## 学习看板和其他 1
|
||||
|
||||
|
||||
### 备注
|
||||
|
||||
-
|
||||
|
||||
|
@ -1,7 +1,18 @@
|
||||
---
|
||||
date: 2025-04-06
|
||||
tags:
|
||||
- test
|
||||
- job
|
||||
links: obsidian://open?vault=notesTest&file=new%20notes%2F2025-04-04
|
||||
- kanban
|
||||
- project
|
||||
title: 看板 -
|
||||
project_name:
|
||||
status: will be do
|
||||
---
|
||||
并以此充实起
|
||||
|
||||
## 设置 nodeTest这个项目目录作为练手的项目
|
||||
|
||||
|
||||
### 备注
|
||||
|
||||
-
|
||||
|
||||
|
||||
|
@ -8,13 +8,6 @@ mood:
|
||||
|
||||
# {{title}}
|
||||
|
||||
## 今日目标
|
||||
|
||||
-
|
||||
|
||||
## 完成事项
|
||||
|
||||
-
|
||||
|
||||
## 学到的新东西
|
||||
|
||||
@ -22,11 +15,7 @@ mood:
|
||||
|
||||
## 遇到的问题及解决方案
|
||||
|
||||
-
|
||||
|
||||
## 明日计划
|
||||
|
||||
-
|
||||
|
||||
## 其他备注
|
||||
|
||||
|
@ -1,36 +1,18 @@
|
||||
---
|
||||
date: {{date:YYYY-MM-DD}}
|
||||
tags: [kanban, project]
|
||||
title: 看板 - {{date:YYYY-MM-DD}}
|
||||
project_name:
|
||||
status:
|
||||
date: 2025-04-06
|
||||
tags:
|
||||
- kanban
|
||||
- project
|
||||
title: 看板 -
|
||||
project_name: <% tp.system.suggester(["练手", "量化", "云服务", "其他"], ["练手", "量化", "云服务", "其他"]) %>
|
||||
status: may be do
|
||||
privority: <% tp.system.suggester(["高", "中", "低"], ["高", "中", "低"]) %>
|
||||
---
|
||||
|
||||
# {{title}}
|
||||
## <% tp.file.title %>
|
||||
|
||||
## 项目描述
|
||||
|
||||
-
|
||||
|
||||
## 看板状态
|
||||
|
||||
```dataview
|
||||
TASK FROM "看板名称"
|
||||
```
|
||||
|
||||
## 待办事项 (To Do)
|
||||
|
||||
- [ ]
|
||||
|
||||
## 进行中 (In Progress)
|
||||
|
||||
- [ ]
|
||||
|
||||
## 已完成 (Done)
|
||||
|
||||
- [ ]
|
||||
|
||||
## 备注
|
||||
### 备注
|
||||
|
||||
-
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user