kanban和相关模版设置

This commit is contained in:
zhangkun9038@dingtalk.com 2025-04-06 18:20:39 +08:00
parent ba7466a838
commit 98187939f4
20 changed files with 6535 additions and 83 deletions

View File

@ -7,5 +7,8 @@
"dataview", "dataview",
"weather-fetcher", "weather-fetcher",
"geocoding-properties", "geocoding-properties",
"obsidian-kanban" "metaedit",
"kanban-status-updater",
"obsidian-kanban",
"templater-obsidian"
] ]

View File

@ -0,0 +1,5 @@
{
"statusPropertyName": "status",
"showNotifications": true,
"debugMode": false
}

View 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 */

View 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
}

View 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
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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;
}

View File

@ -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
}
]
} }

View 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
}

File diff suppressed because one or more lines are too long

View 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
}

View 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;
}

View File

@ -4,39 +4,44 @@
"type": "split", "type": "split",
"children": [ "children": [
{ {
"id": "d0afed41b8685973", "id": "a6f094df0e179c24",
"type": "tabs", "type": "tabs",
"children": [ "children": [
{ {
"id": "74d64848bffd2359", "id": "4694fd15b957885a",
"type": "leaf", "type": "leaf",
"state": { "state": {
"type": "markdown", "type": "markdown",
"state": { "state": {
"file": "new notes/快捷键设置.md", "file": "templates/daily_template.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "快捷键设置"
}
},
{
"id": "3985a6d657d77461",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "new notes/快捷键设置.md",
"mode": "source", "mode": "source",
"source": true "source": true
}, },
"icon": "lucide-file", "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" "direction": "vertical"
@ -157,13 +162,13 @@
"state": { "state": {
"type": "outline", "type": "outline",
"state": { "state": {
"file": "new notes/快捷键设置.md", "file": "templates/daily_template.md",
"followCursor": false, "followCursor": false,
"showSearch": false, "showSearch": false,
"searchQuery": "" "searchQuery": ""
}, },
"icon": "lucide-list", "icon": "lucide-list",
"title": "Outline of 快捷键设置" "title": "Outline of daily_template"
} }
}, },
{ {
@ -181,7 +186,8 @@
} }
], ],
"direction": "horizontal", "direction": "horizontal",
"width": 409.5 "width": 337.5,
"collapsed": true
}, },
"left-ribbon": { "left-ribbon": {
"hiddenItems": { "hiddenItems": {
@ -196,30 +202,35 @@
"terminal:Open terminal": false, "terminal:Open terminal": false,
"table-editor-obsidian:Advanced Tables Toolbar": false, "table-editor-obsidian:Advanced Tables Toolbar": false,
"weather-fetcher:Insert Weather": 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": [ "lastOpenFiles": [
"new notes/快捷键设置.md",
"templates/base_template.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", "templates/daily_template.md",
"new notes/2025-04-06.md", "kanban/mainboard.md",
"new notes/pdf 插件的学习.md", "new notes/学习看板和其他 1.md",
"new notes/2025-04-05.md", "templates/kanban_template.md",
"new notes/2025-04-04.md", "new notes/学习看板和其他.md",
"new notes/设置 nodeTest这个项目目录作为练手的项目.md", "new notes/设置 nodeTest这个项目目录作为练手的项目.md",
"new notes/chat history.md",
"new notes/找到了如何入门obsidian的途径.md",
"copilot-conversations/ubuntu lvm bindfs.md", "copilot-conversations/ubuntu lvm bindfs.md",
"copilot-conversations/dataview ob q&a.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", "Chats/New Chat.md",
"new notes/Untitled.md", "new notes/Untitled.md",
"Task.md",
"欢迎.md", "欢迎.md",
"Welcome.md", "Welcome.md",
"templates/daily.md", "templates/daily.md",

32
kanban/mainboard.md Normal file
View 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}]}
```
%%

View File

@ -0,0 +1,19 @@
---
date: 2025-04-06
tags:
- kanban
- project
title: 看板 -
project_name: 练手
status: may be do
privority: 低
---
## 学习看板和其他 1
### 备注
-

View File

@ -1,7 +1,18 @@
--- ---
date: 2025-04-06
tags: tags:
- test - kanban
- job - project
links: obsidian://open?vault=notesTest&file=new%20notes%2F2025-04-04 title: 看板 -
project_name:
status: will be do
--- ---
并以此充实起
## 设置 nodeTest这个项目目录作为练手的项目
### 备注
-

View File

@ -8,13 +8,6 @@ mood:
# {{title}} # {{title}}
## 今日目标
-
## 完成事项
-
## 学到的新东西 ## 学到的新东西
@ -22,11 +15,7 @@ mood:
## 遇到的问题及解决方案 ## 遇到的问题及解决方案
-
## 明日计划
-
## 其他备注 ## 其他备注

View File

@ -1,36 +1,18 @@
--- ---
date: {{date:YYYY-MM-DD}} date: 2025-04-06
tags: [kanban, project] tags:
title: 看板 - {{date:YYYY-MM-DD}} - kanban
project_name: - project
status: 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)
- [ ]
## 备注
- -