Mise à jour rapide

This commit is contained in:
Ladebeze66 2025-03-23 20:59:56 +01:00
parent e49d034b7d
commit 5e0c1e70ca
133 changed files with 52948 additions and 49 deletions

9
.obsidian/app.json vendored
View File

@ -1,3 +1,10 @@
{
"spellcheck": true
"spellcheck": true,
"attachmentFolderPath": "./PJ",
"newFileLocation": "folder",
"newFileFolderPath": "inbox",
"userIgnoreFilters": [
"inbox/"
],
"alwaysUpdateLinks": true
}

View File

@ -1 +1,15 @@
{}
{
"enabledCssSnippets": [
"case_coche",
"citations",
"code_inline",
"lien_extern",
"lien_intern",
"listes_puces",
"multi_line_code",
"picture",
"table_dark_mode",
"tags",
"title_colors"
]
}

11
.obsidian/community-plugins.json vendored Normal file
View File

@ -0,0 +1,11 @@
[
"editing-toolbar",
"obsidian-auto-link-title",
"table-editor-obsidian",
"obsidian-table-generator",
"obsidian-tasks-plugin",
"obsidian-markdown-formatting-assistant-plugin",
"obsidian-shellcommands",
"templater-obsidian",
"buttons"
]

View File

@ -23,7 +23,7 @@
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"workspaces": true,
"file-recovery": true,
"publish": false,
"sync": true,

44
.obsidian/graph.json vendored
View File

@ -1,14 +1,50 @@
{
"collapse-filter": true,
"collapse-filter": false,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"colorGroups": [
{
"query": "path:Obsidian ",
"color": {
"a": 1,
"rgb": 14701138
}
},
{
"query": "path:Stage ",
"color": {
"a": 1,
"rgb": 14725458
}
},
{
"query": "path:ollama ",
"color": {
"a": 1,
"rgb": 11657298
}
},
{
"query": "path:\"Serveur perso\" ",
"color": {
"a": 1,
"rgb": 5399264
}
},
{
"query": "path:command_list ",
"color": {
"a": 1,
"rgb": 8091799
}
}
],
"collapse-display": true,
"showArrow": false,
"showArrow": true,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
@ -17,6 +53,6 @@
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 1,
"scale": 1.0000000000000056,
"close": true
}

65
.obsidian/hotkeys.json vendored Normal file
View File

@ -0,0 +1,65 @@
{
"editor:toggle-spellcheck": [
{
"modifiers": [
"Mod"
],
"key": "V"
}
],
"editor:unfold-all": [
{
"modifiers": [
"Mod",
"Shift"
],
"key": "D"
}
],
"editor:fold-all": [
{
"modifiers": [
"Mod",
"Shift"
],
"key": "P"
}
],
"editor:fold-less": [
{
"modifiers": [
"Mod",
"Shift"
],
"key": "+"
}
],
"editor:fold-more": [
{
"modifiers": [
"Mod",
"Shift"
],
"key": "-"
}
],
"table-editor-obsidian:table-control-bar": [],
"editor:swap-line-down": [
{
"modifiers": [
"Mod",
"Shift"
],
"key": "ArrowDown"
}
],
"editor:swap-line-up": [
{
"modifiers": [
"Mod",
"Shift"
],
"key": "ArrowUp"
}
]
}

4385
.obsidian/plugins/buttons/main.js vendored Normal file

File diff suppressed because it is too large Load Diff

10
.obsidian/plugins/buttons/manifest.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"id": "buttons",
"name": "Buttons",
"description": "Create Buttons in your Obsidian notes to run commands, open links, and insert templates",
"version": "0.5.1",
"author": "shabegom",
"authorUrl": "https://shbgm.ca",
"isDesktopOnly": false,
"minAppVersion": "0.12.8"
}

148
.obsidian/plugins/buttons/styles.css vendored Normal file
View File

@ -0,0 +1,148 @@
/* @settings
name: Buttons
id: buttons-styles
settings:
-
id: button-background
title: Background
type: variable-themed-color
format: hex
opacity: false
default-light: '#f5f6f8'
default-dark: '#1b1b1b'
-
id: button-text
title: Text
type: variable-themed-color
format: hex
opacity: false
default-light: '#1b1b1b'
default-dark: '#f5f6f8'
-
id: button-border
title: Border
type: variable-themed-color
format: hex
opacity: false
default-light: '#7a9486'
default-dark: '#84a83a'
-
id: button-box-shadow
title: Box Shadow
type: variable-themed-color
format: rgb
opacity: true
default-light: '#1b1b1b'
default-dark: '#f5f6f8'
-
id: button-border-radius
title: Border Radius
type: variable-number
format: px
default: 5
-
id: button-size
title: Font Size
type: variable-number
format: em
default: 1
*/
.block-language-button {
padding: 5px;
}
button.button-default {
border: 0.5px solid var(--button-border, #7a9486);
border-radius: var(--button-border-radius, 5px);
background-color: var(--button-background);
padding: 10px 30px;
color: var(--button-text);
text-decoration: none;
font-size: var(--button-size);
margin: 0 5px;
box-shadow: 0 1px 3px var(--button-box-shadow, rgba(0, 0, 0, 0.12)),
0 1px 2px var(--button-box-shadow, rgba(0, 0, 0, 0.24));
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
button.button-default:hover {
z-index: 100;
box-shadow: 0 4px 4px var(--button-box-shadow, rgba(0, 0, 0, 0.25)),
0 10px 10px var(--button-box-shadow, rgba(0, 0, 0, 0.22));
transform: translate3d(0px, -1.5px, 0px);
background-color: var(--button-background);
}
.theme-dark button.button-default {
border: 0.5px solid var(--button-border, #84a83a);
}
.theme-dark button.button-default:hover {
z-index: 100;
box-shadow: 0 4px 4px var(--button-box-shadow, rgba(210, 210, 210, 0.25)),
0 10px 10px var(--button-box-shadow, rgba(210, 210, 210, 0.22));
transform: translate3d(0px, -1.5px, 0px);
}
button.button-inline {
width: unset;
height: unset;
padding: 0 8px;
}
button.blue {
background: #76b3fa;
color: black;
}
button.red {
background-color: red;
}
button.green {
background: green;
}
button.yellow {
background: yellow;
color: black;
}
button.purple {
background: #725585;
}
button.blue:hover {
background: #76b3fa;
color: black;
}
button.red:hover {
background: red;
}
button.green:hover {
background: green;
}
button.yellow:hover {
background: yellow;
color: black;
}
button.purple:hover {
background: #725585;
}
.button-maker {
max-width: 35rem;
width: 35rem;
overflow-y: auto;
max-height: 30rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
overflow-x: hidden;
}

View File

@ -0,0 +1,319 @@
{
"lastVersion": "3.1.3",
"aestheticStyle": "default",
"positionStyle": "top",
"menuCommands": [
{
"id": "editing-toolbar:editor-undo",
"name": "Undo editor",
"icon": "undo-glyph"
},
{
"id": "editing-toolbar:editor-redo",
"name": "Redo editor",
"icon": "redo-glyph"
},
{
"id": "editing-toolbar:toggle-format-brush",
"name": "Format Brush",
"icon": "paintbrush"
},
{
"id": "editing-toolbar:format-eraser",
"name": "Clear text formatting",
"icon": "eraser"
},
{
"id": "editing-toolbar:header2-text",
"name": "Header 2",
"icon": "header-2"
},
{
"id": "editing-toolbar:header3-text",
"name": "Header 3",
"icon": "header-3"
},
{
"id": "SubmenuCommands-header",
"name": "submenu",
"icon": "header-n",
"SubmenuCommands": [
{
"id": "editing-toolbar:header1-text",
"name": "Header 1",
"icon": "header-1"
},
{
"id": "editing-toolbar:header4-text",
"name": "Header 4",
"icon": "header-4"
},
{
"id": "editing-toolbar:header5-text",
"name": "Header 5",
"icon": "header-5"
},
{
"id": "editing-toolbar:header6-text",
"name": "Header 6",
"icon": "header-6"
}
]
},
{
"id": "editing-toolbar:toggle-bold",
"name": "Bold",
"icon": "bold-glyph"
},
{
"id": "editing-toolbar:toggle-italics",
"name": "Italics",
"icon": "italic-glyph"
},
{
"id": "editing-toolbar:toggle-strikethrough",
"name": "Strikethrough",
"icon": "strikethrough-glyph"
},
{
"id": "editing-toolbar:underline",
"name": "Underline",
"icon": "underline-glyph"
},
{
"id": "editing-toolbar:toggle-highlight",
"name": "==Highlight==",
"icon": "highlight-glyph"
},
{
"id": "SubmenuCommands-lucdf3en5",
"name": "submenu",
"icon": "edit",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor-copy",
"name": "Copy",
"icon": "lucide-copy"
},
{
"id": "editing-toolbar:editor-cut",
"name": "Cut",
"icon": "lucide-scissors"
},
{
"id": "editing-toolbar:editor-paste",
"name": "Paste",
"icon": "lucide-clipboard-type"
},
{
"id": "editing-toolbar:editor:swap-line-down",
"name": "Swap line down",
"icon": "lucide-corner-right-down"
},
{
"id": "editing-toolbar:editor:swap-line-up",
"name": "Swap line up",
"icon": "lucide-corner-right-up"
}
]
},
{
"id": "editing-toolbar:editor:attach-file",
"name": "Attach file",
"icon": "lucide-paperclip"
},
{
"id": "editing-toolbar:editor:insert-table",
"name": "Insert Table",
"icon": "lucide-table"
},
{
"id": "editing-toolbar:editor:cycle-list-checklist",
"name": "Cycle list checklist",
"icon": "check-circle"
},
{
"id": "SubmenuCommands-luc8efull",
"name": "submenu",
"icon": "message-square",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor:toggle-blockquote",
"name": "Blockquote",
"icon": "lucide-text-quote"
},
{
"id": "editing-toolbar:insert-callout",
"name": "Insert Callout ",
"icon": "lucide-quote"
}
]
},
{
"id": "SubmenuCommands-mdcmder",
"name": "submenu",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M464 608 l0 -568 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-80 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 568 l-232 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 80 q0 3 2.5 5.5 q2.5 2.5 5.5 2.5 l560 0 q3 0 5.5 -2.5 q2.5 -2.5 2.5 -5.5 l0 -80 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-232 0 ZM864 696 q17 0 28.5 11.5 q11.5 11.5 11.5 28.5 q0 17 -11.5 28.5 q-11.5 11.5 -28.5 11.5 q-17 0 -28.5 -11.5 q-11.5 -11.5 -11.5 -28.5 q0 -17 11.5 -28.5 q11.5 -11.5 28.5 -11.5 ZM864 640 q-40 0 -68 28 q-28 28 -28 68 q0 40 28 68 q28 28 68 28 q40 0 68 -28 q28 -28 28 -68 q0 -40 -28 -68 q-28 -28 -68 -28 ZM576 322 l0 -63 q0 -3 2 -5 l89 -70 l-89 -70 q-2 -2 -2 -5 l0 -63 q0 -4 3.5 -5.5 q3.5 -1.5 6.5 0.5 l170 133 q4 3 4.5 8.5 q0.5 5.5 -2.5 9.5 l-2 2 l-170 133 q-3 2 -6.5 0.5 q-3.5 -1.5 -3.5 -5.5 ZM256 322 l0 -63 q0 -3 -2 -5 l-89 -70 l89 -70 q2 -2 2 -5 l0 -63 q0 -4 -3.5 -5.5 q-3.5 -1.5 -6.5 0.5 l-170 133 q-4 3 -4.5 8.5 q-0.5 5.5 2.5 9.5 l2 2 l170 133 q3 2 6.5 0.5 q3.5 -1.5 3.5 -5.5 Z\"></path></g></svg>",
"SubmenuCommands": [
{
"id": "editing-toolbar:superscript",
"name": "Superscript",
"icon": "superscript-glyph"
},
{
"id": "editing-toolbar:subscript",
"name": "Subscript",
"icon": "subscript-glyph"
},
{
"id": "editing-toolbar:editor:toggle-code",
"name": "Inline code",
"icon": "code-glyph"
},
{
"id": "editing-toolbar:codeblock",
"name": "Code block",
"icon": "codeblock-glyph"
},
{
"id": "editing-toolbar:editor:insert-wikilink",
"name": "Insert wikilink [[]]",
"icon": "<svg width=\"15\" height=\"15\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M306 134 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 7 q0 -8 -5 -8 l-45 0 q-5 0 -5 8 l0 784 q0 8 5 8 l45 0 q5 0 5 -8 q0 8 1 8 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 -623 q0 8 1 8 ZM139 134 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 7 q0 -8 -5 -8 l-45 0 q-5 0 -5 8 l0 784 q0 8 5 8 l45 0 q5 0 5 -8 q0 8 1 8 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 -623 q0 8 1 8 ZM711 134 q1 0 1 -8 l0 623 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 q1 0 1 -8 q0 8 4 8 l46 0 q4 0 4 -8 l0 -784 q0 -8 -4 -8 l-46 0 q-4 0 -4 8 q0 -7 -1 -7 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 ZM878 134 q1 0 1 -8 l0 623 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 q1 0 1 -8 q0 8 5 8 l45 0 q4 0 4 -8 l0 -784 q0 -8 -4 -8 l-45 0 q-5 0 -5 8 q0 -7 -1 -7 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:editor:insert-embed",
"name": "Insert embed ![[]]",
"icon": "note-glyph"
},
{
"id": "editing-toolbar:insert-link",
"name": "Insert link []()",
"icon": "link-glyph"
},
{
"id": "editing-toolbar:hrline",
"name": "Horizontal divider",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M912 424 l0 -80 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-784 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 80 q0 3 2.5 5.5 q2.5 2.5 5.5 2.5 l784 0 q3 0 5.5 -2.5 q2.5 -2.5 2.5 -5.5 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:toggle-inline-math",
"name": "Inline math",
"icon": "lucide-sigma"
},
{
"id": "editing-toolbar:editor:insert-mathblock",
"name": "MathBlock",
"icon": "lucide-sigma-square"
}
]
},
{
"id": "SubmenuCommands-list",
"name": "submenu-list",
"icon": "bullet-list-glyph",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor:toggle-checklist-status",
"name": "Checklist",
"icon": "checkbox-glyph"
},
{
"id": "editing-toolbar:toggle-numbered-list",
"name": "Numbered list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M860 424 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM860 756 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM860 92 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM264 136 l-3 -3 l-51 -57 l56 0 q14 0 24.5 -10 q10.5 -10 11.5 -25 l0 -1 q0 -15 -10.5 -25.5 q-10.5 -10.5 -24.5 -10.5 l-137 0 q-15 0 -25 10 q-10 10 -11 24.5 q-1 14.5 9 25.5 l63 70 l49 54 q7 7 7 16.5 q0 9.5 -7.5 16.5 q-7.5 7 -18.5 7 q-11 0 -18.5 -6.5 q-7.5 -6.5 -8.5 -16.5 l0 0 q0 -15 -10.5 -25.5 q-10.5 -10.5 -25.5 -10.5 q-15 0 -25.5 10.5 q-10.5 10.5 -10.5 25.5 q0 26 13.5 47.5 q13.5 21.5 36 34.5 q22.5 13 49 13 q26.5 0 49.5 -13 q23 -13 36 -34.5 q13 -21.5 13 -47.5 q0 -20 -7.5 -37.5 q-7.5 -17.5 -21.5 -30.5 l-1 -1 ZM173 794 q11 11 25 10.5 q14 -0.5 24.5 -10.5 q10.5 -10 10.5 -25 l0 -293 q0 -15 -10 -25.5 q-10 -10.5 -25 -10.5 q-15 0 -25.5 10 q-10.5 10 -11.5 25 l0 211 q-10 -8 -23.5 -7 q-13.5 1 -22.5 11 l-1 0 q-10 11 -9.5 25.5 q0.5 14.5 10.5 24.5 l58 54 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:toggle-bullet-list",
"name": "Bullet list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M860 424 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM860 756 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM860 92 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM176 716 l0 0 ZM112 716 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 ZM176 384 l0 0 ZM112 384 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 ZM176 52 l0 0 ZM112 52 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:undent-list",
"name": "Unindent-list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 302 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 542 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 784 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 62 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM244 534 l-123 -122 q-8 -7 -8 -18 q0 -11 8 -18 l123 -122 q8 -7 19 -7 q11 0 18.5 7.5 q7.5 7.5 7.5 18.5 l0 242 q0 11 -7.5 18.5 q-7.5 7.5 -18.5 7.5 q-11 0 -19 -7 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:indent-list",
"name": "Indent list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 302 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 542 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 784 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 62 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM158 534 l124 -122 q7 -7 7 -18 q0 -11 -7 -18 l-124 -122 q-7 -7 -18 -7 q-11 0 -19 7.5 q-8 7.5 -8 18.5 l0 242 q0 11 8 18.5 q8 7.5 19 7.5 q11 0 18 -7 Z\"></path></g></svg>"
}
]
},
{
"id": "SubmenuCommands-aligin",
"name": "submenu-aligin",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M724 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM724 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>",
"SubmenuCommands": [
{
"id": "editing-toolbar:justify",
"name": "<p aligin=\"justify\"></p>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M112 736 l0 0 ZM120 736 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 331 l0 0 ZM120 331 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 128 l0 0 ZM120 128 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 533 l0 0 ZM120 533 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:left",
"name": "<p aligin=\"left\"></p>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M572 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM572 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:center",
"name": "<center>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M724 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM724 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:right",
"name": "<p aligin=\"right\"></p>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
}
]
},
{
"id": "editing-toolbar:change-font-color",
"name": "Change font color[html]",
"icon": "<svg width=\"24\" height=\"24\" focusable=\"false\" fill=\"currentColor\"><g fill-rule=\"evenodd\"><path id=\"change-font-color-icon\" d=\"M3 18h18v3H3z\" style=\"fill:#2DC26B\"></path><path d=\"M8.7 16h-.8a.5.5 0 01-.5-.6l2.7-9c.1-.3.3-.4.5-.4h2.8c.2 0 .4.1.5.4l2.7 9a.5.5 0 01-.5.6h-.8a.5.5 0 01-.4-.4l-.7-2.2c0-.3-.3-.4-.5-.4h-3.4c-.2 0-.4.1-.5.4l-.7 2.2c0 .3-.2.4-.4.4zm2.6-7.6l-.6 2a.5.5 0 00.5.6h1.6a.5.5 0 00.5-.6l-.6-2c0-.3-.3-.4-.5-.4h-.4c-.2 0-.4.1-.5.4z\"></path></g></svg>"
},
{
"id": "editing-toolbar:change-background-color",
"name": "Change Backgroundcolor[html]",
"icon": "<svg width=\"18\" height=\"24\" viewBox=\"0 0 256 256\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke=\"none\" stroke-width=\"1\" fill=\"currentColor\" fill-rule=\"evenodd\"><g ><g fill=\"currentColor\"><g transform=\"translate(119.502295, 137.878331) rotate(-135.000000) translate(-119.502295, -137.878331) translate(48.002295, 31.757731)\" ><path d=\"M100.946943,60.8084699 L43.7469427,60.8084699 C37.2852111,60.8084699 32.0469427,66.0467383 32.0469427,72.5084699 L32.0469427,118.70847 C32.0469427,125.170201 37.2852111,130.40847 43.7469427,130.40847 L100.946943,130.40847 C107.408674,130.40847 112.646943,125.170201 112.646943,118.70847 L112.646943,72.5084699 C112.646943,66.0467383 107.408674,60.8084699 100.946943,60.8084699 Z M93.646,79.808 L93.646,111.408 L51.046,111.408 L51.046,79.808 L93.646,79.808 Z\" fill-rule=\"nonzero\"></path><path d=\"M87.9366521,16.90916 L87.9194966,68.2000001 C87.9183543,69.4147389 86.9334998,70.399264 85.7187607,70.4 L56.9423078,70.4 C55.7272813,70.4 54.7423078,69.4150264 54.7423078,68.2 L54.7423078,39.4621057 C54.7423078,37.2523513 55.5736632,35.1234748 57.0711706,33.4985176 L76.4832996,12.4342613 C78.9534987,9.75382857 83.1289108,9.5834005 85.8093436,12.0535996 C87.1658473,13.303709 87.9372691,15.0644715 87.9366521,16.90916 Z\" fill-rule=\"evenodd\"></path><path d=\"M131.3,111.241199 L11.7,111.241199 C5.23826843,111.241199 0,116.479467 0,122.941199 L0,200.541199 C0,207.002931 5.23826843,212.241199 11.7,212.241199 L131.3,212.241199 C137.761732,212.241199 143,207.002931 143,200.541199 L143,122.941199 C143,116.479467 137.761732,111.241199 131.3,111.241199 Z M124,130.241 L124,193.241 L19,193.241 L19,130.241 L124,130.241 Z\" fill-rule=\"nonzero\"></path></g></g><path d=\"M51,218 L205,218 C211.075132,218 216,222.924868 216,229 C216,235.075132 211.075132,240 205,240 L51,240 C44.9248678,240 40,235.075132 40,229 C40,222.924868 44.9248678,218 51,218 Z\" id=\"change-background-color-icon\" style=\"fill:#FA541C\"></path></g></g></svg>"
},
{
"id": "editing-toolbar:fullscreen-focus",
"name": "Fullscreen focus mode",
"icon": "fullscreen"
},
{
"id": "editing-toolbar:workplace-fullscreen-focus",
"name": "Workplace-Fullscreen ",
"icon": "exit-fullscreen"
}
],
"followingCommands": [],
"topCommands": [],
"fixedCommands": [],
"mobileCommands": [],
"enableMultipleConfig": false,
"appendMethod": "workspace",
"shouldShowMenuOnSelect": false,
"cMenuVisibility": true,
"cMenuBottomValue": 4.25,
"cMenuNumRows": 12,
"cMenuWidth": 610,
"cMenuFontColor": "#245bdb",
"cMenuBackgroundColor": "#d3f8b6",
"autohide": false,
"custom_bg1": "#FFB78B8C",
"custom_bg2": "#CDF4698C",
"custom_bg3": "#A0CCF68C",
"custom_bg4": "#F0A7D88C",
"custom_bg5": "#ADEFEF8C",
"custom_fc1": "#D83931",
"custom_fc2": "#DE7802",
"custom_fc3": "#245BDB",
"custom_fc4": "#6425D0",
"custom_fc5": "#646A73",
"isLoadOnMobile": false,
"horizontalPosition": 0,
"verticalPosition": 0,
"formatBrushes": {},
"customCommands": [],
"viewTypeSettings": {}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,10 @@
{
"id": "editing-toolbar",
"name": "Editing Toolbar",
"version": "3.1.3",
"minAppVersion": "0.14.0",
"description": "The Obsidian Editing Toolbar is modified from cmenu, which provides more powerful customization settings and has many built-in editing commands to be a MS Word-like toolbar editing experience.",
"author": "Cuman",
"authorUrl": "https://github.com/cumany/obsidian-editing-toolbar",
"isDesktopOnly": false
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,771 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
*/
'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 = {
regex: /^(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$/i,
lineRegex: /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi,
linkRegex: /^\[([^\[\]]*)\]\((https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})\)$/i,
linkLineRegex: /\[([^\[\]]*)\]\((https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})\)/gi,
imageRegex: /\.(gif|jpe?g|tiff?|png|webp|bmp|tga|psd|ai)$/i,
enhanceDefaultPaste: true,
shouldPreserveSelectionAsTitle: false,
enhanceDropEvents: true,
websiteBlacklist: "",
maximumTitleLength: 0,
useNewScraper: false,
linkPreviewApiKey: "",
useBetterPasteId: false,
};
class AutoLinkTitleSettingTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
let { containerEl } = this;
containerEl.empty();
new obsidian.Setting(containerEl)
.setName("Enhance Default Paste")
.setDesc("Fetch the link title when pasting a link in the editor with the default paste command")
.addToggle((val) => val
.setValue(this.plugin.settings.enhanceDefaultPaste)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.enhanceDefaultPaste = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Enhance Drop Events")
.setDesc("Fetch the link title when drag and dropping a link from another program")
.addToggle((val) => val
.setValue(this.plugin.settings.enhanceDropEvents)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.enhanceDropEvents = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Maximum title length")
.setDesc("Set the maximum length of the title. Set to 0 to disable.")
.addText((val) => val
.setValue(this.plugin.settings.maximumTitleLength.toString(10))
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
const titleLength = Number(value);
this.plugin.settings.maximumTitleLength =
isNaN(titleLength) || titleLength < 0 ? 0 : titleLength;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Preserve selection as title")
.setDesc("Whether to prefer selected text as title over fetched title when pasting")
.addToggle((val) => val
.setValue(this.plugin.settings.shouldPreserveSelectionAsTitle)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.shouldPreserveSelectionAsTitle = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Website Blacklist")
.setDesc("List of strings (comma separated) that disable autocompleting website titles. Can be URLs or arbitrary text.")
.addTextArea((val) => val
.setValue(this.plugin.settings.websiteBlacklist)
.setPlaceholder("localhost, tiktok.com")
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.websiteBlacklist = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Use New Scraper")
.setDesc("Use experimental new scraper, seems to work well on desktop but not mobile.")
.addToggle((val) => val
.setValue(this.plugin.settings.useNewScraper)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.useNewScraper = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Use Better Fetching Placeholder")
.setDesc("Use a more readable placeholder when fetching the title of a link.")
.addToggle((val) => val
.setValue(this.plugin.settings.useBetterPasteId)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.useBetterPasteId = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("LinkPreview API Key")
.setDesc("API key for the LinkPreview.net service. Get one at https://my.linkpreview.net/access_keys")
.addText((text) => text
.setValue(this.plugin.settings.linkPreviewApiKey || "")
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
const trimmedValue = value.trim();
if (trimmedValue.length > 0 && trimmedValue.length !== 32) {
new obsidian.Notice("LinkPreview API key must be 32 characters long");
this.plugin.settings.linkPreviewApiKey = "";
}
else {
this.plugin.settings.linkPreviewApiKey = trimmedValue;
}
yield this.plugin.saveSettings();
})));
}
}
class CheckIf {
static isMarkdownLinkAlready(editor) {
let cursor = editor.getCursor();
// Check if the characters before the url are ]( to indicate a markdown link
var titleEnd = editor.getRange({ ch: cursor.ch - 2, line: cursor.line }, { ch: cursor.ch, line: cursor.line });
return titleEnd == "](";
}
static isAfterQuote(editor) {
let cursor = editor.getCursor();
// Check if the characters before the url are " or ' to indicate we want the url directly
// This is common in elements like <a href="linkhere"></a>
var beforeChar = editor.getRange({ ch: cursor.ch - 1, line: cursor.line }, { ch: cursor.ch, line: cursor.line });
return beforeChar == "\"" || beforeChar == "'";
}
static isUrl(text) {
let urlRegex = new RegExp(DEFAULT_SETTINGS.regex);
return urlRegex.test(text);
}
static isImage(text) {
let imageRegex = new RegExp(DEFAULT_SETTINGS.imageRegex);
return imageRegex.test(text);
}
static isLinkedUrl(text) {
let urlRegex = new RegExp(DEFAULT_SETTINGS.linkRegex);
return urlRegex.test(text);
}
}
class EditorExtensions {
static getSelectedText(editor) {
if (!editor.somethingSelected()) {
let wordBoundaries = this.getWordBoundaries(editor);
editor.setSelection(wordBoundaries.start, wordBoundaries.end);
}
return editor.getSelection();
}
static cursorWithinBoundaries(cursor, match) {
let startIndex = match.index;
let endIndex = match.index + match[0].length;
return startIndex <= cursor.ch && cursor.ch <= endIndex;
}
static getWordBoundaries(editor) {
let cursor = editor.getCursor();
// If its a normal URL token this is not a markdown link
// In this case we can simply overwrite the link boundaries as-is
let lineText = editor.getLine(cursor.line);
// First check if we're in a link
let linksInLine = lineText.matchAll(DEFAULT_SETTINGS.linkLineRegex);
for (let match of linksInLine) {
if (this.cursorWithinBoundaries(cursor, match)) {
return {
start: { line: cursor.line, ch: match.index },
end: { line: cursor.line, ch: match.index + match[0].length },
};
}
}
// If not, check if we're in just a standard ol' URL.
let urlsInLine = lineText.matchAll(DEFAULT_SETTINGS.lineRegex);
for (let match of urlsInLine) {
if (this.cursorWithinBoundaries(cursor, match)) {
return {
start: { line: cursor.line, ch: match.index },
end: { line: cursor.line, ch: match.index + match[0].length },
};
}
}
return {
start: cursor,
end: cursor,
};
}
static getEditorPositionFromIndex(content, index) {
let substr = content.substr(0, index);
let l = 0;
let offset = -1;
let r = -1;
for (; (r = substr.indexOf("\n", r + 1)) !== -1; l++, offset = r)
;
offset += 1;
let ch = content.substr(offset, index - offset).length;
return { line: l, ch: ch };
}
}
function blank$1(text) {
return text === undefined || text === null || text === '';
}
function notBlank$1(text) {
return !blank$1(text);
}
function scrape(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield obsidian.requestUrl(url);
if (!response.headers['content-type'].includes('text/html'))
return getUrlFinalSegment$1(url);
const html = response.text;
const doc = new DOMParser().parseFromString(html, 'text/html');
const title = doc.querySelector('title');
if (blank$1(title === null || title === void 0 ? void 0 : title.innerText)) {
// If site is javascript based and has a no-title attribute when unloaded, use it.
var noTitle = title === null || title === void 0 ? void 0 : title.getAttr('no-title');
if (notBlank$1(noTitle)) {
return noTitle;
}
// Otherwise if the site has no title/requires javascript simply return Title Unknown
return url;
}
return title.innerText;
}
catch (ex) {
console.error(ex);
return '';
}
});
}
function getUrlFinalSegment$1(url) {
try {
const segments = new URL(url).pathname.split('/');
const last = segments.pop() || segments.pop(); // Handle potential trailing slash
return last;
}
catch (_) {
return 'File';
}
}
function getPageTitle$1(url) {
return __awaiter(this, void 0, void 0, function* () {
if (!(url.startsWith('http') || url.startsWith('https'))) {
url = 'https://' + url;
}
return scrape(url);
});
}
const electronPkg = require("electron");
function blank(text) {
return text === undefined || text === null || text === "";
}
function notBlank(text) {
return !blank(text);
}
// async wrapper to load a url and settle on load finish or fail
function load(window, url) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
window.webContents.on("did-finish-load", (event) => resolve(event));
window.webContents.on("did-fail-load", (event) => reject(event));
window.loadURL(url);
});
});
}
function electronGetPageTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
const { remote } = electronPkg;
const { BrowserWindow } = remote;
try {
const window = new BrowserWindow({
width: 1000,
height: 600,
webPreferences: {
webSecurity: false,
nodeIntegration: true,
images: false,
},
show: false,
});
window.webContents.setAudioMuted(true);
window.webContents.on("will-navigate", (event, newUrl) => {
event.preventDefault();
window.loadURL(newUrl);
});
yield load(window, url);
try {
const title = window.webContents.getTitle();
window.destroy();
if (notBlank(title)) {
return title;
}
else {
return url;
}
}
catch (ex) {
window.destroy();
return url;
}
}
catch (ex) {
console.error(ex);
return "";
}
});
}
function nonElectronGetPageTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
const html = yield obsidian.request({ url });
const doc = new DOMParser().parseFromString(html, "text/html");
const title = doc.querySelectorAll("title")[0];
if (title == null || blank(title === null || title === void 0 ? void 0 : title.innerText)) {
// If site is javascript based and has a no-title attribute when unloaded, use it.
var noTitle = title === null || title === void 0 ? void 0 : title.getAttr("no-title");
if (notBlank(noTitle)) {
return noTitle;
}
// Otherwise if the site has no title/requires javascript simply return Title Unknown
return url;
}
return title.innerText;
}
catch (ex) {
console.error(ex);
return "";
}
});
}
function getUrlFinalSegment(url) {
try {
const segments = new URL(url).pathname.split('/');
const last = segments.pop() || segments.pop(); // Handle potential trailing slash
return last;
}
catch (_) {
return "File";
}
}
function tryGetFileType(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield fetch(url, { method: "HEAD" });
// Ensure site returns an ok status code before scraping
if (!response.ok) {
return "Site Unreachable";
}
// Ensure site is an actual HTML page and not a pdf or 3 gigabyte video file.
let contentType = response.headers.get("content-type");
if (!contentType.includes("text/html")) {
return getUrlFinalSegment(url);
}
return null;
}
catch (err) {
return null;
}
});
}
function getPageTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
// If we're on Desktop use the Electron scraper
if (!(url.startsWith("http") || url.startsWith("https"))) {
url = "https://" + url;
}
// Try to do a HEAD request to see if the site is reachable and if it's an HTML page
// If we error out due to CORS, we'll just try to scrape the page anyway.
let fileType = yield tryGetFileType(url);
if (fileType) {
return fileType;
}
if (electronPkg != null) {
return electronGetPageTitle(url);
}
else {
return nonElectronGetPageTitle(url);
}
});
}
class AutoLinkTitle extends obsidian.Plugin {
constructor() {
super(...arguments);
this.shortTitle = (title) => {
if (this.settings.maximumTitleLength === 0) {
return title;
}
if (title.length < this.settings.maximumTitleLength + 3) {
return title;
}
const shortenedTitle = `${title.slice(0, this.settings.maximumTitleLength)}...`;
return shortenedTitle;
};
}
onload() {
return __awaiter(this, void 0, void 0, function* () {
console.log("loading obsidian-auto-link-title");
yield this.loadSettings();
this.blacklist = this.settings.websiteBlacklist
.split(",")
.map((s) => s.trim())
.filter((s) => s.length > 0);
// Listen to paste event
this.pasteFunction = this.pasteUrlWithTitle.bind(this);
// Listen to drop event
this.dropFunction = this.dropUrlWithTitle.bind(this);
this.addCommand({
id: "auto-link-title-paste",
name: "Paste URL and auto fetch title",
editorCallback: (editor) => this.manualPasteUrlWithTitle(editor),
hotkeys: [],
});
this.addCommand({
id: "auto-link-title-normal-paste",
name: "Normal paste (no fetching behavior)",
editorCallback: (editor) => this.normalPaste(editor),
hotkeys: [
{
modifiers: ["Mod", "Shift"],
key: "v",
},
],
});
this.registerEvent(this.app.workspace.on("editor-paste", this.pasteFunction));
this.registerEvent(this.app.workspace.on("editor-drop", this.dropFunction));
this.addCommand({
id: "enhance-url-with-title",
name: "Enhance existing URL with link and title",
editorCallback: (editor) => this.addTitleToLink(editor),
hotkeys: [
{
modifiers: ["Mod", "Shift"],
key: "e",
},
],
});
this.addSettingTab(new AutoLinkTitleSettingTab(this.app, this));
});
}
addTitleToLink(editor) {
// Only attempt fetch if online
if (!navigator.onLine)
return;
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
// If the cursor is on a raw html link, convert to a markdown link and fetch title
if (CheckIf.isUrl(selectedText)) {
this.convertUrlToTitledLink(editor, selectedText);
}
// If the cursor is on the URL part of a markdown link, fetch title and replace existing link title
else if (CheckIf.isLinkedUrl(selectedText)) {
const link = this.getUrlFromLink(selectedText);
this.convertUrlToTitledLink(editor, link);
}
}
normalPaste(editor) {
return __awaiter(this, void 0, void 0, function* () {
let clipboardText = yield navigator.clipboard.readText();
if (clipboardText === null || clipboardText === "")
return;
editor.replaceSelection(clipboardText);
});
}
// Simulate standard paste but using editor.replaceSelection with clipboard text since we can't seem to dispatch a paste event.
manualPasteUrlWithTitle(editor) {
return __awaiter(this, void 0, void 0, function* () {
const clipboardText = yield navigator.clipboard.readText();
// Only attempt fetch if online
if (!navigator.onLine) {
editor.replaceSelection(clipboardText);
return;
}
if (clipboardText == null || clipboardText == "")
return;
// If its not a URL, we return false to allow the default paste handler to take care of it.
// Similarly, image urls don't have a meaningful <title> attribute so downloading it
// to fetch the title is a waste of bandwidth.
if (!CheckIf.isUrl(clipboardText) || CheckIf.isImage(clipboardText)) {
editor.replaceSelection(clipboardText);
return;
}
// If it looks like we're pasting the url into a markdown link already, don't fetch title
// as the user has already probably put a meaningful title, also it would lead to the title
// being inside the link.
if (CheckIf.isMarkdownLinkAlready(editor) || CheckIf.isAfterQuote(editor)) {
editor.replaceSelection(clipboardText);
return;
}
// If url is pasted over selected text and setting is enabled, no need to fetch title,
// just insert a link
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
if (selectedText && this.settings.shouldPreserveSelectionAsTitle) {
editor.replaceSelection(`[${selectedText}](${clipboardText})`);
return;
}
// At this point we're just pasting a link in a normal fashion, fetch its title.
this.convertUrlToTitledLink(editor, clipboardText);
return;
});
}
pasteUrlWithTitle(clipboard, editor) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.settings.enhanceDefaultPaste) {
return;
}
if (clipboard.defaultPrevented)
return;
// Only attempt fetch if online
if (!navigator.onLine)
return;
let clipboardText = clipboard.clipboardData.getData("text/plain");
if (clipboardText === null || clipboardText === "")
return;
// If its not a URL, we return false to allow the default paste handler to take care of it.
// Similarly, image urls don't have a meaningful <title> attribute so downloading it
// to fetch the title is a waste of bandwidth.
if (!CheckIf.isUrl(clipboardText) || CheckIf.isImage(clipboardText)) {
return;
}
// We've decided to handle the paste, stop propagation to the default handler.
clipboard.stopPropagation();
clipboard.preventDefault();
// If it looks like we're pasting the url into a markdown link already, don't fetch title
// as the user has already probably put a meaningful title, also it would lead to the title
// being inside the link.
if (CheckIf.isMarkdownLinkAlready(editor) || CheckIf.isAfterQuote(editor)) {
editor.replaceSelection(clipboardText);
return;
}
// If url is pasted over selected text and setting is enabled, no need to fetch title,
// just insert a link
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
if (selectedText && this.settings.shouldPreserveSelectionAsTitle) {
editor.replaceSelection(`[${selectedText}](${clipboardText})`);
return;
}
// At this point we're just pasting a link in a normal fashion, fetch its title.
this.convertUrlToTitledLink(editor, clipboardText);
return;
});
}
dropUrlWithTitle(dropEvent, editor) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.settings.enhanceDropEvents) {
return;
}
if (dropEvent.defaultPrevented)
return;
// Only attempt fetch if online
if (!navigator.onLine)
return;
let dropText = dropEvent.dataTransfer.getData("text/plain");
if (dropText === null || dropText === "")
return;
// If its not a URL, we return false to allow the default paste handler to take care of it.
// Similarly, image urls don't have a meaningful <title> attribute so downloading it
// to fetch the title is a waste of bandwidth.
if (!CheckIf.isUrl(dropText) || CheckIf.isImage(dropText)) {
return;
}
// We've decided to handle the paste, stop propagation to the default handler.
dropEvent.stopPropagation();
dropEvent.preventDefault();
// If it looks like we're pasting the url into a markdown link already, don't fetch title
// as the user has already probably put a meaningful title, also it would lead to the title
// being inside the link.
if (CheckIf.isMarkdownLinkAlready(editor) || CheckIf.isAfterQuote(editor)) {
editor.replaceSelection(dropText);
return;
}
// If url is pasted over selected text and setting is enabled, no need to fetch title,
// just insert a link
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
if (selectedText && this.settings.shouldPreserveSelectionAsTitle) {
editor.replaceSelection(`[${selectedText}](${dropText})`);
return;
}
// At this point we're just pasting a link in a normal fashion, fetch its title.
this.convertUrlToTitledLink(editor, dropText);
return;
});
}
isBlacklisted(url) {
return __awaiter(this, void 0, void 0, function* () {
yield this.loadSettings();
this.blacklist = this.settings.websiteBlacklist
.split(/,|\n/)
.map((s) => s.trim())
.filter((s) => s.length > 0);
return this.blacklist.some((site) => url.includes(site));
});
}
convertUrlToTitledLink(editor, url) {
return __awaiter(this, void 0, void 0, function* () {
if (yield this.isBlacklisted(url)) {
let domain = new URL(url).hostname;
editor.replaceSelection(`[${domain}](${url})`);
return;
}
// Generate a unique id for find/replace operations for the title.
const pasteId = this.getPasteId();
// Instantly paste so you don't wonder if paste is broken
editor.replaceSelection(`[${pasteId}](${url})`);
// Fetch title from site, replace Fetching Title with actual title
const title = yield this.fetchUrlTitle(url);
const escapedTitle = this.escapeMarkdown(title);
const shortenedTitle = this.shortTitle(escapedTitle);
const text = editor.getValue();
const start = text.indexOf(pasteId);
if (start < 0) {
console.log(`Unable to find text "${pasteId}" in current editor, bailing out; link ${url}`);
}
else {
const end = start + pasteId.length;
const startPos = EditorExtensions.getEditorPositionFromIndex(text, start);
const endPos = EditorExtensions.getEditorPositionFromIndex(text, end);
editor.replaceRange(shortenedTitle, startPos, endPos);
}
});
}
escapeMarkdown(text) {
var unescaped = text.replace(/\\(\*|_|`|~|\\|\[|\])/g, "$1"); // unescape any "backslashed" character
var escaped = unescaped.replace(/(\*|_|`|<|>|~|\\|\[|\])/g, "\\$1"); // escape *, _, `, ~, \, [, ], <, and >
var escaped = unescaped.replace(/(\*|_|`|\||<|>|~|\\|\[|\])/g, "\\$1"); // escape *, _, `, ~, \, |, [, ], <, and >
return escaped;
}
fetchUrlTitleViaLinkPreview(url) {
return __awaiter(this, void 0, void 0, function* () {
if (this.settings.linkPreviewApiKey.length !== 32) {
console.error("LinkPreview API key is not 32 characters long, please check your settings");
return "";
}
try {
const apiEndpoint = `https://api.linkpreview.net/?q=${encodeURIComponent(url)}`;
const response = yield fetch(apiEndpoint, {
headers: {
"X-Linkpreview-Api-Key": this.settings.linkPreviewApiKey,
},
});
const data = yield response.json();
return data.title;
}
catch (error) {
console.error(error);
return "";
}
});
}
fetchUrlTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
let title = "";
title = yield this.fetchUrlTitleViaLinkPreview(url);
console.log(`Title via Link Preview: ${title}`);
if (title === "") {
console.log("Title via Link Preview failed, falling back to scraper");
if (this.settings.useNewScraper) {
console.log("Using new scraper");
title = yield getPageTitle$1(url);
}
else {
console.log("Using old scraper");
title = yield getPageTitle(url);
}
}
console.log(`Title: ${title}`);
title =
title.replace(/(\r\n|\n|\r)/gm, "").trim() ||
"Title Unavailable | Site Unreachable";
return title;
}
catch (error) {
console.error(error);
return "Error fetching title";
}
});
}
getUrlFromLink(link) {
let urlRegex = new RegExp(DEFAULT_SETTINGS.linkRegex);
return urlRegex.exec(link)[2];
}
getPasteId() {
var base = "Fetching Title";
if (this.settings.useBetterPasteId) {
return this.getBetterPasteId(base);
}
else {
return `${base}#${this.createBlockHash()}`;
}
}
getBetterPasteId(base) {
// After every character, add 0, 1 or 2 invisible characters
// so that to the user it looks just like the base string.
// The number of combinations is 3^14 = 4782969
let result = "";
var invisibleCharacter = "\u200B";
var maxInvisibleCharacters = 2;
for (var i = 0; i < base.length; i++) {
var count = Math.floor(Math.random() * (maxInvisibleCharacters + 1));
result += base.charAt(i) + invisibleCharacter.repeat(count);
}
return result;
}
// Custom hashid by @shabegom
createBlockHash() {
let result = "";
var characters = "abcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
for (var i = 0; i < 4; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
onunload() {
console.log("unloading obsidian-auto-link-title");
}
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);
});
}
}
module.exports = AutoLinkTitle;
/* nosourcemap */

View File

@ -0,0 +1,10 @@
{
"id": "obsidian-auto-link-title",
"name": "Auto Link Title",
"version": "1.5.5",
"minAppVersion": "0.12.17",
"description": "This plugin automatically fetches the titles of links from the web",
"author": "Matt Furden",
"authorUrl": "https://github.com/zolrath",
"isDesktopOnly": false
}

View File

@ -0,0 +1 @@
/* no styles */

View File

@ -0,0 +1,53 @@
{
"triggerChar": "\\",
"sidePaneSideLeft": false,
"savedColors": [
"#ff0000"
],
"aviabileRegions": [
"textEdit",
"tabels",
"html",
"latex",
"greekLetters",
"colors",
"callouts"
],
"regionSettings": [
{
"name": "textEdit",
"active": true,
"visible": false
},
{
"name": "tables",
"active": true,
"visible": false
},
{
"name": "html",
"active": true,
"visible": false
},
{
"name": "latex",
"active": true,
"visible": false
},
{
"name": "greekLetters",
"active": true,
"visible": false
},
{
"name": "colors",
"active": true,
"visible": false
},
{
"name": "callouts",
"active": true,
"visible": false
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
{
"id": "obsidian-markdown-formatting-assistant-plugin",
"name": "Markdown Formatting Assistant",
"version": "0.4.1",
"minAppVersion": "0.15.6",
"description": "This Plugin provides a simple Editor for Markdown, HTML and Colors and in addition a command interface. The command interface facilitate a faster workflow.",
"author": "Reocin",
"authorUrl": "https://github.com/Reocin/obsidian-markdown-formatting-assistant-plugin",
"isDesktopOnly": false
}

View File

@ -0,0 +1,62 @@
/* Sets all the text color to red! */
.nav-action-button {
color: var(--text-muted);
cursor: pointer;
padding: 0px;
margin: 5px;
border-radius: 4px;
}
.nav-action-text-button {
color: var(--text-muted);
cursor: pointer;
padding: 5px;
margin: 4px;
border-radius: 4px;
text-align: center;
border: 1px solid;
}
.nav-action-text-button.is-active {
background-color: var(--interactive-accent);
color: var(--text-on-accent);
}
.nav-action-text-button.is-active:hover {
color: var(--text-on-accent);
}
.nav-action-text-button:hover {
color: var(--text-accent);
}
.color-icon {
color: var(--text-muted);
cursor: pointer;
width: 16px;
min-width: 16px;
max-width: 16px;
height: 16px;
min-height: 16px;
max-height: 16px;
margin: 3px;
display: inline-block;
border-radius: 4px;
}
.command-list-view-row {
display: flex;
}
.command-list-view-container {
min-width: 60px;
display: flex;
}
.command-list-view-icon {
height: 24px;
max-height: 24px;
border: 1px solid gray;
margin-right: auto;
}
.command-list-view-text {
padding-left: 12px;
color: #c7254e;
}

View File

@ -0,0 +1,216 @@
{
"settings_version": "0.23.0",
"debug": false,
"obsidian_command_palette_prefix": "Execute: ",
"preview_variables_in_command_palette": true,
"show_autocomplete_menu": true,
"working_directory": "",
"default_shells": {},
"environment_variable_path_augmentations": {},
"show_installation_warnings": true,
"error_message_duration": 20,
"notification_message_duration": 10,
"execution_notification_mode": "quick",
"output_channel_clipboard_also_outputs_to_notification": true,
"output_channel_notification_decorates_output": true,
"enable_events": true,
"approve_modals_by_pressing_enter_key": true,
"command_palette": {
"re_execute_last_shell_command": {
"enabled": true,
"prefix": "Re-execute: "
}
},
"max_visible_lines_in_shell_command_fields": false,
"shell_commands": [
{
"id": "tqe6dxs5pz",
"platform_specific_commands": {
"default": "git status"
},
"shells": {},
"alias": "Git : Status",
"icon": null,
"confirm_execution": true,
"ignore_error_codes": [],
"input_contents": {
"stdin": null
},
"output_handlers": {
"stdout": {
"handler": "notification",
"convert_ansi_code": true
},
"stderr": {
"handler": "notification",
"convert_ansi_code": true
}
},
"output_wrappers": {
"stdout": null,
"stderr": null
},
"output_channel_order": "stdout-first",
"output_handling_mode": "buffered",
"execution_notification_mode": "quick",
"events": {},
"debounce": null,
"command_palette_availability": "enabled",
"preactions": [],
"variable_default_values": {}
},
{
"id": "u5z5l8o03b",
"platform_specific_commands": {
"default": "git add ."
},
"shells": {},
"alias": "Git : Add",
"icon": null,
"confirm_execution": false,
"ignore_error_codes": [],
"input_contents": {
"stdin": null
},
"output_handlers": {
"stdout": {
"handler": "notification",
"convert_ansi_code": true
},
"stderr": {
"handler": "notification",
"convert_ansi_code": true
}
},
"output_wrappers": {
"stdout": null,
"stderr": null
},
"output_channel_order": "stdout-first",
"output_handling_mode": "buffered",
"execution_notification_mode": null,
"events": {},
"debounce": null,
"command_palette_availability": "enabled",
"preactions": [],
"variable_default_values": {}
},
{
"id": "gsdvog4kwg",
"platform_specific_commands": {
"default": "git commit -m \"Mise à jour rapide\""
},
"shells": {},
"alias": "Git: Commit rapide",
"icon": null,
"confirm_execution": false,
"ignore_error_codes": [],
"input_contents": {
"stdin": null
},
"output_handlers": {
"stdout": {
"handler": "notification",
"convert_ansi_code": true
},
"stderr": {
"handler": "notification",
"convert_ansi_code": true
}
},
"output_wrappers": {
"stdout": null,
"stderr": null
},
"output_channel_order": "stdout-first",
"output_handling_mode": "buffered",
"execution_notification_mode": null,
"events": {},
"debounce": null,
"command_palette_availability": "enabled",
"preactions": [],
"variable_default_values": {}
},
{
"id": "f7zs2jf8q0",
"platform_specific_commands": {
"default": "git push"
},
"shells": {},
"alias": "Git : Push",
"icon": null,
"confirm_execution": false,
"ignore_error_codes": [],
"input_contents": {
"stdin": null
},
"output_handlers": {
"stdout": {
"handler": "notification",
"convert_ansi_code": true
},
"stderr": {
"handler": "notification",
"convert_ansi_code": true
}
},
"output_wrappers": {
"stdout": null,
"stderr": null
},
"output_channel_order": "stdout-first",
"output_handling_mode": "buffered",
"execution_notification_mode": null,
"events": {},
"debounce": null,
"command_palette_availability": "enabled",
"preactions": [],
"variable_default_values": {}
},
{
"id": "q71ju9t4ka",
"platform_specific_commands": {
"default": "git branch -a"
},
"shells": {},
"alias": "Git : Branch",
"icon": null,
"confirm_execution": false,
"ignore_error_codes": [],
"input_contents": {
"stdin": null
},
"output_handlers": {
"stdout": {
"handler": "notification",
"convert_ansi_code": true
},
"stderr": {
"handler": "notification",
"convert_ansi_code": true
}
},
"output_wrappers": {
"stdout": null,
"stderr": null
},
"output_channel_order": "stdout-first",
"output_handling_mode": "buffered",
"execution_notification_mode": null,
"events": {},
"debounce": null,
"command_palette_availability": "enabled",
"preactions": [],
"variable_default_values": {}
}
],
"prompts": [],
"builtin_variables": {},
"custom_variables": [],
"custom_variables_notify_changes_via": {
"obsidian_uri": true,
"output_assignment": true
},
"custom_shells": [],
"output_wrappers": []
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
{
"id": "obsidian-shellcommands",
"name": "Shell commands",
"version": "0.23.0",
"minAppVersion": "1.4.0",
"description": "You can predefine system commands that you want to run frequently, and assign hotkeys for them. For example open external applications. Automatic execution is also supported, and execution via URI links.",
"author": "Jarkko Linnanvirta",
"authorUrl": "https://github.com/Taitava",
"fundingUrl": "https://publish.obsidian.md/shellcommands/Donate",
"isDesktopOnly": true
}

View File

@ -0,0 +1,386 @@
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2024 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/*
* COMMON
*/
.SC-hide {
display: none;
}
.SC-scrollable {
overflow-y: auto;
}
.SC-no-margin {
margin: 0;
}
.SC-no-top-border {
border-top: none;
}
.SC-wrappable {
white-space: normal;
}
.SC-small-font {
font-size: 80%;
}
/**
* Used for indenting setting elements when they have relations to each other.
*/
.SC-indent {
margin-left: 20px;
}
.SC-text-right {
text-align: right;
}
/*
* SETTING GROUPS
* Related setting fields combined together.
*/
div.SC-setting-group div.setting-item:not(div.setting-item-heading+div.setting-item) {
/* Remove top border from all settings in the group, except settings that come AFTER a heading setting, as it looks
* good when there is a border line below a heading setting.
*/
border-top: none;
}
div.SC-setting-group div.setting-item {
padding: 5px; /* Shrink the padding. */
}
div.SC-setting-group div.setting-item:not(.setting-item-heading) div.setting-item-info, /* :not() = Don't shrink headings, they usually don't have large control elements. Heading texts themselves can be long, so don't limit them to 50% width. */
div.SC-setting-group div.setting-item:not(.setting-item-heading) div.setting-item-control {
width: 50%; /* Make sure description does not take over 50% of the space. */
}
div.SC-setting-group div.setting-item.SC-full-description div.setting-item-info {
width: 100%; /* Give description 100% width. Built-in variable list in settings uses this. */
}
div.SC-setting-group div.setting-item.SC-full-description div.setting-item-control {
width: 0; /* Make room for description. */
}
div.SC-setting-group div.setting-item.SC-wide-description div.setting-item-info {
width: max-content; /* Grow description as wide as possible, but leave some space for setting control elements. */
}
div.SC-setting-group div.setting-item.SC-wide-description div.setting-item-control {
width: min-content; /* Make room for description. */
}
div.SC-setting-group div.setting-item input[type=text],
div.SC-setting-group div.setting-item input[type=password],
div.SC-setting-group div.setting-item input[type=search],
div.SC-setting-group div.setting-item textarea,
div.SC-setting-group div.setting-item:not(.setting-item-heading) select {
width: 100%; /* Enlarge fields. */
max-width: 100%; /* Remove a maximum width limitation, at least <select> elements had one. */
}
div.SC-setting-group div.setting-item textarea {
resize: vertical; /* Allow resizing multiline text fields vertically. Don't allow horizontal resizing, because the width is already maxed out (to 50%), and horizontal resizing would just make the field accidentally narrower. */
}
div.SC-setting-group div.setting-item.SC-no-description div.setting-item-info { /* .SC-no-description is used by the 'alias' setting field. */
width: 0;
margin: 0;
}
div.SC-setting-group div.setting-item.SC-no-description div.setting-item-control { /* .SC-no-description is used by the 'alias' setting field. */
width: 100%;
}
/*
* SHELL COMMAND SETTING CONTAINERS
*/
div.SC-name-setting,
div.SC-shell-command-setting,
div.SC-preview-setting {
padding: 0;
}
div.SC-name-setting {
padding-top: 18px;
}
div.SC-shell-command-setting {
border-top: none;
padding: 5px 0; /* Padding top & bottom 5px, sides 0. */
}
div.SC-preview-setting {
border-top: none;
padding-bottom: 18px;
}
div.SC-shell-command-setting div.setting-item-info {
/* Make the left cell (=div.setting-item-info) to have no space at all: */
flex: none;
flex-grow: unset;
margin-right: 0;
}
/*
* SHELL COMMAND SETTING FIELDS
*/
div.SC-shell-command-setting textarea {
width: 100%;
}
textarea.SC-multiline {
padding: 2px 5px; /* Shrink the padding all around the textarea. */
resize: vertical;
}
div.SC-hotkey-info {
white-space: nowrap;
}
div.SC-hotkey-info svg {
vertical-align: middle; /* Not middle but close enough. */
}
small.SC-preview-shell-name {
display: inline-block;
margin-top: 7px;
border-top: 1px solid var(--text-faint);
font-weight: bold;
}
/*
* SHELL COMMAND ICONS (not button icons, just informational icons)
*/
span.SC-main-icon-container {
margin-left: 10px;
}
/*
* CUSTOM VARIABLE SETTINGS
*/
div.setting-item.SC-custom-variable-name-setting div.setting-item-control::before {
content: "{{_"; /* Wrap custom variable name field in {{_ }} */
}
div.setting-item.SC-custom-variable-name-setting div.setting-item-control::after {
content: "}}"; /* Wrap custom variable name field in {{_ }} */
}
/*
* CUSTOM VARIABLE VIEW
*/
li.SC-custom-variable-view-list-item {
margin-bottom: 1em; /* Add space between variables in list. */
}
/*
* CUSTOM SHELL SETTINGS
*/
div.SC-path-translator-setting div.setting-item-control::before {
content: "function (absolutePath) {";
white-space: nowrap;
}
div.SC-path-translator-setting div.setting-item-control::after {
content: "}";
}
/*
* MODALS (generic rules to all of the plugin's modals)
*/
div.SC-modal {
width: max-content; /* Widen the width as much as is reasonable. Obsidian 0.16.0 made modals narrower, this aims to revert it. */
}
/*
* PROMPT MODALS
*/
p.SC-prompt-dry-run-notice {
font-style: italic;
font-weight: bold;
}
/*
* Tab elements
* This CSS is copied 2021-10-21 from https://www.w3schools.com/howto/howto_js_tabs.asp
* Modifications:
* - Renamed classes
* - Added tab icons.
* - Changed colors.
* - Changed/removed borders.
* - Removed button transition.
* - Changed button border-radiuses
* - Added margin-right rule to .SC-tab-header-button .
*/
/* Style the tab */
.SC-tab-header {
border-bottom: 2px solid var(--background-modifier-border);
}
/* Style the buttons that are used to open the tab content */
button.SC-tab-header-button {
background-color: unset;
border: none;
box-shadow: none; /* Remove a "border" that came via Obsidian 0.16.0. */
outline: none;
cursor: pointer;
padding: 14px 16px;
margin-right: 6px; /* Reduced margin. Obsidian's default margin-right for button is 12px (0 for other margins). */
border-radius: 10px 10px 0 0; /* 0 0 = No border-radius at bottom */
}
/* Create an active/current tablink class */
button.SC-tab-header-button.SC-tab-active,
button.SC-tab-header-button:hover {
background-color: var(--background-modifier-border);
}
.SC-tab-header-button svg {
vertical-align: middle; /* Not middle but close enough. */
}
/* Style the tab content */
.SC-tab-content {
display: none;
padding: 6px 12px;
}
.SC-tab-content.SC-tab-active {
display: block;
}
/*
* AUTOCOMPLETE
*/
.SC-autocomplete {
background-color: var(--background-primary-alt);
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
color: var(--text-normal);
z-index: 100; /* Otherwise the element will be behind everything = invisible. */
width: auto !important; /* Otherwise the element will be as wide as the text input field. */
}
.SC-autocomplete > div {
padding: 0 5px 2px 10px;
}
.SC-autocomplete > div > span.SC-autocomplete-value {
font-weight: bold;
}
.SC-autocomplete > div > span.SC-autocomplete-help-text {
font-size: 90%;
font-style: italic;
}
.SC-autocomplete > div.selected,
.SC-autocomplete > div:hover:not(.group) {
cursor: pointer;
background-color: var(--text-selection);
color: var(--text-normal);
}
.SC-autocomplete > div.group {
background-color: var(--background-modifier-border);
padding-left: 5px;
font-size: 75%;
}
a.SC-autocomplete-link-icon {
margin-left: 3px;
}
a.SC-autocomplete-link-icon svg {
vertical-align: middle; /* Not middle but close enough. */
}
/*
* OUTPUT CHANNEL: NOTIFICATION/ERROR BALLOON.
*/
code.SC-output-channel-notification-monospace {
font-family: var(--font-monospace), monospace;
}
/*
* OUTPUT CHANNEL: ASK AFTER EXECUTION (OutputModal TypeScript class)
*/
div.SC-output-channel-modal-textarea-container textarea {
width: 100%;
min-width: 100%;
min-height: 15em;
resize: both;
}
div.SC-output-channel-modal-redirection-buttons-container div.setting-item-control {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
gap: 10px;
}
div.SC-output-channel-modal-redirection-buttons-container div.setting-item-control button {
margin: 0;
flex-grow: 1;
}
/*
* 'REQUEST TO TERMINATE THE PROCESS' ICON BUTTON
*/
a.SC-icon-terminate-process { /* Generic for all terminator icons. */
color: inherit; /* Don't use accent color. */
}
a.SC-icon-terminate-process svg {
height: 1em;
vertical-align: middle; /* Not middle but close enough. */
}
.notice a.SC-icon-terminate-process { /* For terminator icons in Notice balloons. */
margin-left: 5px; /* Add space between the icon and notification text. */
float: right; /* Position the icon to the (top) right corner. */
}
div.SC-modal-output a.SC-icon-terminate-process { /* For terminator icons in OutputChannel_Modal. */
margin-right: 5px; /* Add space between the icon and "Executing..." text.*/
}

View File

@ -0,0 +1,7 @@
{
"rowCount": 8,
"columnCount": 8,
"defaultAlignment": "left",
"defaultCardWidth": 160,
"defaultCardHeight": 160
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
{
"id": "obsidian-table-generator",
"name": "Table Generator",
"version": "1.4.1",
"minAppVersion": "1.1.0",
"description": "A plugin for generate markdown table quickly like Typora /card table in canvas .",
"author": "Boninall",
"authorUrl": "https://github.com/Quorafind",
"fundingUrl": {
"Buy Me a Coffee": "https://www.buymeacoffee.com/boninall",
"爱发电": "https://afdian.net/a/boninall",
"支付宝": "https://cdn.jsdelivr.net/gh/Quorafind/.github@main/IMAGE/%E6%94%AF%E4%BB%98%E5%AE%9D%E4%BB%98%E6%AC%BE%E7%A0%81.jpg"
},
"isDesktopOnly": false
}

View File

@ -0,0 +1,44 @@
.table-container.s-VU35bhriycJk.s-VU35bhriycJk{display:grid;border-bottom:2px dotted var(--color-base-40);border-top:2px dotted var(--color-base-40);padding-top:var(--size-2-1);padding-bottom:var(--size-2-1);width:100%;height:150px;grid-gap:1px}.table-container.s-VU35bhriycJk div.s-VU35bhriycJk{background:var(--color-base-00);border-radius:var(--radius-s);border:1px solid var(--color-base-40)}.table-container.s-VU35bhriycJk .table-generator-cell.s-VU35bhriycJk{height:var(--size-4-4);width:var(--size-4-4)}div.active.s-VU35bhriycJk.s-VU35bhriycJk{background-color:var(--active-color)}.s-VU35bhriycJk.s-VU35bhriycJk{}.table-generator.s-YxLKubgSvLDy{padding-left:5px;padding-right:5px;width:220px}.table-generator-header.s-YxLKubgSvLDy{display:flex;justify-content:space-between;align-items:center;margin-top:var(--size-4-1);margin-bottom:var(--size-4-1)}.input-table-generator.s-YxLKubgSvLDy{margin-left:var(--size-2-2);margin-right:var(--size-2-2);margin-top:var(--size-4-2);margin-bottom:var(--size-4-2);display:flex;justify-content:space-around;align-items:center}.input-table-generator-row.s-YxLKubgSvLDy,.input-table-generator-col.s-YxLKubgSvLDy{display:flex;justify-content:space-around;align-items:center}button.s-YxLKubgSvLDy{width:80px;height:20px;margin:var(--size-4-1) auto var(--size-4-2);padding:0px 10px;text-align:center;text-decoration:none;display:flex;align-items:center}input.s-YxLKubgSvLDy{width:40px;height:18px;border:1px solid var(--color-base-50);margin-left:var(--size-2-2);border-radius:var(--radius-m);text-align:center}.H1.s-YxLKubgSvLDy{margin-left:auto;margin-right:auto;text-align:center}.s-YxLKubgSvLDy{}.table-generator-align-group.s-XNB-qso0yOHJ{display:flex;align-items:center;flex-direction:row;gap:var(--size-2-2)}.table-generator-align-icon.s-XNB-qso0yOHJ{display:flex;align-items:center;justify-content:center;border-radius:var(--radius-s);padding:var(--size-2-1)}.table-generator-align-icon.s-XNB-qso0yOHJ:not(.active):hover{background-color:var(--background-modifier-hover)}.table-generator-align-icon.active.s-XNB-qso0yOHJ{background-color:var(--background-modifier-border-hover)}.s-XNB-qso0yOHJ{}.table-generator-view {
position: absolute;
border: 1px solid var(--color-base-50);
border-radius: 5px;
background-color: var(--color-base-20);
}
.table-generator-setting-text {
min-width: 2.3em;
text-align: right;
}
.theme-light .table-generator-view {
--color-base-00: #ffffff;
--color-base-05: #fcfcfc;
--color-base-10: #fafafa;
--color-base-20: #f6f6f6;
--color-base-25: #e3e3e3;
--color-base-30: #e0e0e0;
--color-base-35: #d4d4d4;
--color-base-40: #bdbdbd;
--color-base-50: #ababab;
--color-base-60: #707070;
--color-base-70: #5a5a5a;
--color-base-100: #222222;
--active-color: rgb(224 242 254);
}
.theme-dark .table-generator-view {
--color-base-00: #1e1e1e;
--color-base-10: #242424;
--color-base-20: #262626;
--color-base-25: #2a2a2a;
--color-base-30: #363636;
--color-base-35: #3F3F3F;
--color-base-40: #555;
--color-base-50: #666;
--color-base-60: #999;
--color-base-70: #bababa;
--color-base-100: #dadada;
--active-color: rgb(3 105 161);
}
.input-table-generator.s-b7dfVi8Mj3e3{margin-left:var(--size-2-2);margin-right:var(--size-2-2);margin-top:var(--size-4-2);margin-bottom:var(--size-4-2);display:flex;justify-content:space-around;align-items:center}.input-table-generator-width.s-b7dfVi8Mj3e3,.input-table-generator-height.s-b7dfVi8Mj3e3{display:flex;justify-content:space-around;align-items:center}input.s-b7dfVi8Mj3e3{width:70px;height:18px;border:1px solid var(--color-base-50);margin-left:var(--size-2-2);border-radius:var(--radius-m);text-align:center}.s-b7dfVi8Mj3e3{}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
{
"id": "obsidian-tasks-plugin",
"name": "Tasks",
"version": "7.18.3",
"minAppVersion": "1.4.0",
"description": "Track tasks across your vault. Supports due dates, recurring tasks, done dates, sub-set of checklist items, and filtering.",
"helpUrl": "https://publish.obsidian.md/tasks/",
"author": "Clare Macrae and Ilyas Landikov (created by Martin Schenck)",
"authorUrl": "https://github.com/obsidian-tasks-group",
"fundingUrl": "https://github.com/sponsors/claremacrae",
"isDesktopOnly": false
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,319 @@
{
"lastVersion": "3.1.3",
"aestheticStyle": "default",
"positionStyle": "top",
"menuCommands": [
{
"id": "editing-toolbar:editor-undo",
"name": "Undo editor",
"icon": "undo-glyph"
},
{
"id": "editing-toolbar:editor-redo",
"name": "Redo editor",
"icon": "redo-glyph"
},
{
"id": "editing-toolbar:toggle-format-brush",
"name": "Format Brush",
"icon": "paintbrush"
},
{
"id": "editing-toolbar:format-eraser",
"name": "Clear text formatting",
"icon": "eraser"
},
{
"id": "editing-toolbar:header2-text",
"name": "Header 2",
"icon": "header-2"
},
{
"id": "editing-toolbar:header3-text",
"name": "Header 3",
"icon": "header-3"
},
{
"id": "SubmenuCommands-header",
"name": "submenu",
"icon": "header-n",
"SubmenuCommands": [
{
"id": "editing-toolbar:header1-text",
"name": "Header 1",
"icon": "header-1"
},
{
"id": "editing-toolbar:header4-text",
"name": "Header 4",
"icon": "header-4"
},
{
"id": "editing-toolbar:header5-text",
"name": "Header 5",
"icon": "header-5"
},
{
"id": "editing-toolbar:header6-text",
"name": "Header 6",
"icon": "header-6"
}
]
},
{
"id": "editing-toolbar:toggle-bold",
"name": "Bold",
"icon": "bold-glyph"
},
{
"id": "editing-toolbar:toggle-italics",
"name": "Italics",
"icon": "italic-glyph"
},
{
"id": "editing-toolbar:toggle-strikethrough",
"name": "Strikethrough",
"icon": "strikethrough-glyph"
},
{
"id": "editing-toolbar:underline",
"name": "Underline",
"icon": "underline-glyph"
},
{
"id": "editing-toolbar:toggle-highlight",
"name": "==Highlight==",
"icon": "highlight-glyph"
},
{
"id": "SubmenuCommands-lucdf3en5",
"name": "submenu",
"icon": "edit",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor-copy",
"name": "Copy",
"icon": "lucide-copy"
},
{
"id": "editing-toolbar:editor-cut",
"name": "Cut",
"icon": "lucide-scissors"
},
{
"id": "editing-toolbar:editor-paste",
"name": "Paste",
"icon": "lucide-clipboard-type"
},
{
"id": "editing-toolbar:editor:swap-line-down",
"name": "Swap line down",
"icon": "lucide-corner-right-down"
},
{
"id": "editing-toolbar:editor:swap-line-up",
"name": "Swap line up",
"icon": "lucide-corner-right-up"
}
]
},
{
"id": "editing-toolbar:editor:attach-file",
"name": "Attach file",
"icon": "lucide-paperclip"
},
{
"id": "editing-toolbar:editor:insert-table",
"name": "Insert Table",
"icon": "lucide-table"
},
{
"id": "editing-toolbar:editor:cycle-list-checklist",
"name": "Cycle list checklist",
"icon": "check-circle"
},
{
"id": "SubmenuCommands-luc8efull",
"name": "submenu",
"icon": "message-square",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor:toggle-blockquote",
"name": "Blockquote",
"icon": "lucide-text-quote"
},
{
"id": "editing-toolbar:insert-callout",
"name": "Insert Callout ",
"icon": "lucide-quote"
}
]
},
{
"id": "SubmenuCommands-mdcmder",
"name": "submenu",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M464 608 l0 -568 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-80 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 568 l-232 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 80 q0 3 2.5 5.5 q2.5 2.5 5.5 2.5 l560 0 q3 0 5.5 -2.5 q2.5 -2.5 2.5 -5.5 l0 -80 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-232 0 ZM864 696 q17 0 28.5 11.5 q11.5 11.5 11.5 28.5 q0 17 -11.5 28.5 q-11.5 11.5 -28.5 11.5 q-17 0 -28.5 -11.5 q-11.5 -11.5 -11.5 -28.5 q0 -17 11.5 -28.5 q11.5 -11.5 28.5 -11.5 ZM864 640 q-40 0 -68 28 q-28 28 -28 68 q0 40 28 68 q28 28 68 28 q40 0 68 -28 q28 -28 28 -68 q0 -40 -28 -68 q-28 -28 -68 -28 ZM576 322 l0 -63 q0 -3 2 -5 l89 -70 l-89 -70 q-2 -2 -2 -5 l0 -63 q0 -4 3.5 -5.5 q3.5 -1.5 6.5 0.5 l170 133 q4 3 4.5 8.5 q0.5 5.5 -2.5 9.5 l-2 2 l-170 133 q-3 2 -6.5 0.5 q-3.5 -1.5 -3.5 -5.5 ZM256 322 l0 -63 q0 -3 -2 -5 l-89 -70 l89 -70 q2 -2 2 -5 l0 -63 q0 -4 -3.5 -5.5 q-3.5 -1.5 -6.5 0.5 l-170 133 q-4 3 -4.5 8.5 q-0.5 5.5 2.5 9.5 l2 2 l170 133 q3 2 6.5 0.5 q3.5 -1.5 3.5 -5.5 Z\"></path></g></svg>",
"SubmenuCommands": [
{
"id": "editing-toolbar:superscript",
"name": "Superscript",
"icon": "superscript-glyph"
},
{
"id": "editing-toolbar:subscript",
"name": "Subscript",
"icon": "subscript-glyph"
},
{
"id": "editing-toolbar:editor:toggle-code",
"name": "Inline code",
"icon": "code-glyph"
},
{
"id": "editing-toolbar:codeblock",
"name": "Code block",
"icon": "codeblock-glyph"
},
{
"id": "editing-toolbar:editor:insert-wikilink",
"name": "Insert wikilink [[]]",
"icon": "<svg width=\"15\" height=\"15\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M306 134 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 7 q0 -8 -5 -8 l-45 0 q-5 0 -5 8 l0 784 q0 8 5 8 l45 0 q5 0 5 -8 q0 8 1 8 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 -623 q0 8 1 8 ZM139 134 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 7 q0 -8 -5 -8 l-45 0 q-5 0 -5 8 l0 784 q0 8 5 8 l45 0 q5 0 5 -8 q0 8 1 8 l91 0 q1 0 1 -8 l0 -80 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 -623 q0 8 1 8 ZM711 134 q1 0 1 -8 l0 623 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 q1 0 1 -8 q0 8 4 8 l46 0 q4 0 4 -8 l0 -784 q0 -8 -4 -8 l-46 0 q-4 0 -4 8 q0 -7 -1 -7 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 ZM878 134 q1 0 1 -8 l0 623 q0 -8 -1 -8 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 q1 0 1 -8 q0 8 5 8 l45 0 q4 0 4 -8 l0 -784 q0 -8 -4 -8 l-45 0 q-5 0 -5 8 q0 -7 -1 -7 l-91 0 q-1 0 -1 8 l0 80 q0 8 1 8 l91 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:editor:insert-embed",
"name": "Insert embed ![[]]",
"icon": "note-glyph"
},
{
"id": "editing-toolbar:insert-link",
"name": "Insert link []()",
"icon": "link-glyph"
},
{
"id": "editing-toolbar:hrline",
"name": "Horizontal divider",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M912 424 l0 -80 q0 -3 -2.5 -5.5 q-2.5 -2.5 -5.5 -2.5 l-784 0 q-3 0 -5.5 2.5 q-2.5 2.5 -2.5 5.5 l0 80 q0 3 2.5 5.5 q2.5 2.5 5.5 2.5 l784 0 q3 0 5.5 -2.5 q2.5 -2.5 2.5 -5.5 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:toggle-inline-math",
"name": "Inline math",
"icon": "lucide-sigma"
},
{
"id": "editing-toolbar:editor:insert-mathblock",
"name": "MathBlock",
"icon": "lucide-sigma-square"
}
]
},
{
"id": "SubmenuCommands-list",
"name": "submenu-list",
"icon": "bullet-list-glyph",
"SubmenuCommands": [
{
"id": "editing-toolbar:editor:toggle-checklist-status",
"name": "Checklist",
"icon": "checkbox-glyph"
},
{
"id": "editing-toolbar:toggle-numbered-list",
"name": "Numbered list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M860 424 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM860 756 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM860 92 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-457 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l457 0 ZM264 136 l-3 -3 l-51 -57 l56 0 q14 0 24.5 -10 q10.5 -10 11.5 -25 l0 -1 q0 -15 -10.5 -25.5 q-10.5 -10.5 -24.5 -10.5 l-137 0 q-15 0 -25 10 q-10 10 -11 24.5 q-1 14.5 9 25.5 l63 70 l49 54 q7 7 7 16.5 q0 9.5 -7.5 16.5 q-7.5 7 -18.5 7 q-11 0 -18.5 -6.5 q-7.5 -6.5 -8.5 -16.5 l0 0 q0 -15 -10.5 -25.5 q-10.5 -10.5 -25.5 -10.5 q-15 0 -25.5 10.5 q-10.5 10.5 -10.5 25.5 q0 26 13.5 47.5 q13.5 21.5 36 34.5 q22.5 13 49 13 q26.5 0 49.5 -13 q23 -13 36 -34.5 q13 -21.5 13 -47.5 q0 -20 -7.5 -37.5 q-7.5 -17.5 -21.5 -30.5 l-1 -1 ZM173 794 q11 11 25 10.5 q14 -0.5 24.5 -10.5 q10.5 -10 10.5 -25 l0 -293 q0 -15 -10 -25.5 q-10 -10.5 -25 -10.5 q-15 0 -25.5 10 q-10.5 10 -11.5 25 l0 211 q-10 -8 -23.5 -7 q-13.5 1 -22.5 11 l-1 0 q-10 11 -9.5 25.5 q0.5 14.5 10.5 24.5 l58 54 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:toggle-bullet-list",
"name": "Bullet list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M860 424 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM860 756 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM860 92 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-477 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l477 0 ZM176 716 l0 0 ZM112 716 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 ZM176 384 l0 0 ZM112 384 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 ZM176 52 l0 0 ZM112 52 q0 -27 18.5 -45.5 q18.5 -18.5 45.5 -18.5 q27 0 45.5 18.5 q18.5 18.5 18.5 45.5 q0 27 -18.5 45.5 q-18.5 18.5 -45.5 18.5 q-27 0 -45.5 -18.5 q-18.5 -18.5 -18.5 -45.5 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:undent-list",
"name": "Unindent-list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 302 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 542 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 784 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 62 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM244 534 l-123 -122 q-8 -7 -8 -18 q0 -11 8 -18 l123 -122 q8 -7 19 -7 q11 0 18.5 7.5 q7.5 7.5 7.5 18.5 l0 242 q0 11 -7.5 18.5 q-7.5 7.5 -18.5 7.5 q-11 0 -19 -7 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:indent-list",
"name": "Indent list",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 302 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 542 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-429 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l429 0 ZM872 784 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 62 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM158 534 l124 -122 q7 -7 7 -18 q0 -11 -7 -18 l-124 -122 q-7 -7 -18 -7 q-11 0 -19 7.5 q-8 7.5 -8 18.5 l0 242 q0 11 8 18.5 q8 7.5 19 7.5 q11 0 18 -7 Z\"></path></g></svg>"
}
]
},
{
"id": "SubmenuCommands-aligin",
"name": "submenu-aligin",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M724 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM724 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>",
"SubmenuCommands": [
{
"id": "editing-toolbar:justify",
"name": "<p aligin=\"justify\"></p>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M112 736 l0 0 ZM120 736 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 331 l0 0 ZM120 331 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 128 l0 0 ZM120 128 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 ZM112 533 l0 0 ZM120 533 l784 0 q8 0 8 -8 l0 -80 q0 -8 -8 -8 l-784 0 q-8 0 -8 8 l0 80 q0 8 8 8 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:left",
"name": "<p aligin=\"left\"></p>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M572 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM572 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:center",
"name": "<center>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M724 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM724 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
},
{
"id": "editing-toolbar:right",
"name": "<p aligin=\"right\"></p>",
"icon": "<svg width=\"18\" height=\"18\" focusable=\"false\" fill=\"currentColor\" viewBox=\"0 0 1024 1024\"><g transform=\"scale(1, -1) translate(0, -896) scale(0.9, 0.9) \"><path class=\"path\" d=\"M872 304 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 540 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 ZM872 776 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-421 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l421 0 ZM872 68 q17 0 28.5 -11.5 q11.5 -11.5 11.5 -28 q0 -16.5 -11.5 -28.5 q-11.5 -12 -27.5 -12 l-721 0 q-17 0 -28.5 11.5 q-11.5 11.5 -11.5 28 q0 16.5 11.5 28.5 q11.5 12 27.5 12 l721 0 Z\"></path></g></svg>"
}
]
},
{
"id": "editing-toolbar:change-font-color",
"name": "Change font color[html]",
"icon": "<svg width=\"24\" height=\"24\" focusable=\"false\" fill=\"currentColor\"><g fill-rule=\"evenodd\"><path id=\"change-font-color-icon\" d=\"M3 18h18v3H3z\" style=\"fill:#2DC26B\"></path><path d=\"M8.7 16h-.8a.5.5 0 01-.5-.6l2.7-9c.1-.3.3-.4.5-.4h2.8c.2 0 .4.1.5.4l2.7 9a.5.5 0 01-.5.6h-.8a.5.5 0 01-.4-.4l-.7-2.2c0-.3-.3-.4-.5-.4h-3.4c-.2 0-.4.1-.5.4l-.7 2.2c0 .3-.2.4-.4.4zm2.6-7.6l-.6 2a.5.5 0 00.5.6h1.6a.5.5 0 00.5-.6l-.6-2c0-.3-.3-.4-.5-.4h-.4c-.2 0-.4.1-.5.4z\"></path></g></svg>"
},
{
"id": "editing-toolbar:change-background-color",
"name": "Change Backgroundcolor[html]",
"icon": "<svg width=\"18\" height=\"24\" viewBox=\"0 0 256 256\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke=\"none\" stroke-width=\"1\" fill=\"currentColor\" fill-rule=\"evenodd\"><g ><g fill=\"currentColor\"><g transform=\"translate(119.502295, 137.878331) rotate(-135.000000) translate(-119.502295, -137.878331) translate(48.002295, 31.757731)\" ><path d=\"M100.946943,60.8084699 L43.7469427,60.8084699 C37.2852111,60.8084699 32.0469427,66.0467383 32.0469427,72.5084699 L32.0469427,118.70847 C32.0469427,125.170201 37.2852111,130.40847 43.7469427,130.40847 L100.946943,130.40847 C107.408674,130.40847 112.646943,125.170201 112.646943,118.70847 L112.646943,72.5084699 C112.646943,66.0467383 107.408674,60.8084699 100.946943,60.8084699 Z M93.646,79.808 L93.646,111.408 L51.046,111.408 L51.046,79.808 L93.646,79.808 Z\" fill-rule=\"nonzero\"></path><path d=\"M87.9366521,16.90916 L87.9194966,68.2000001 C87.9183543,69.4147389 86.9334998,70.399264 85.7187607,70.4 L56.9423078,70.4 C55.7272813,70.4 54.7423078,69.4150264 54.7423078,68.2 L54.7423078,39.4621057 C54.7423078,37.2523513 55.5736632,35.1234748 57.0711706,33.4985176 L76.4832996,12.4342613 C78.9534987,9.75382857 83.1289108,9.5834005 85.8093436,12.0535996 C87.1658473,13.303709 87.9372691,15.0644715 87.9366521,16.90916 Z\" fill-rule=\"evenodd\"></path><path d=\"M131.3,111.241199 L11.7,111.241199 C5.23826843,111.241199 0,116.479467 0,122.941199 L0,200.541199 C0,207.002931 5.23826843,212.241199 11.7,212.241199 L131.3,212.241199 C137.761732,212.241199 143,207.002931 143,200.541199 L143,122.941199 C143,116.479467 137.761732,111.241199 131.3,111.241199 Z M124,130.241 L124,193.241 L19,193.241 L19,130.241 L124,130.241 Z\" fill-rule=\"nonzero\"></path></g></g><path d=\"M51,218 L205,218 C211.075132,218 216,222.924868 216,229 C216,235.075132 211.075132,240 205,240 L51,240 C44.9248678,240 40,235.075132 40,229 C40,222.924868 44.9248678,218 51,218 Z\" id=\"change-background-color-icon\" style=\"fill:#FA541C\"></path></g></g></svg>"
},
{
"id": "editing-toolbar:fullscreen-focus",
"name": "Fullscreen focus mode",
"icon": "fullscreen"
},
{
"id": "editing-toolbar:workplace-fullscreen-focus",
"name": "Workplace-Fullscreen ",
"icon": "exit-fullscreen"
}
],
"followingCommands": [],
"topCommands": [],
"fixedCommands": [],
"mobileCommands": [],
"enableMultipleConfig": false,
"appendMethod": "workspace",
"shouldShowMenuOnSelect": false,
"cMenuVisibility": true,
"cMenuBottomValue": 4.25,
"cMenuNumRows": 12,
"cMenuWidth": 610,
"cMenuFontColor": "#245bdb",
"cMenuBackgroundColor": "#d3f8b6",
"autohide": false,
"custom_bg1": "#FFB78B8C",
"custom_bg2": "#CDF4698C",
"custom_bg3": "#A0CCF68C",
"custom_bg4": "#F0A7D88C",
"custom_bg5": "#ADEFEF8C",
"custom_fc1": "#D83931",
"custom_fc2": "#DE7802",
"custom_fc3": "#245BDB",
"custom_fc4": "#6425D0",
"custom_fc5": "#646A73",
"isLoadOnMobile": false,
"horizontalPosition": 0,
"verticalPosition": 0,
"formatBrushes": {},
"customCommands": [],
"viewTypeSettings": {}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,10 @@
{
"id": "editing-toolbar",
"name": "Editing Toolbar",
"version": "3.1.3",
"minAppVersion": "0.14.0",
"description": "The Obsidian Editing Toolbar is modified from cmenu, which provides more powerful customization settings and has many built-in editing commands to be a MS Word-like toolbar editing experience.",
"author": "Cuman",
"authorUrl": "https://github.com/cumany/obsidian-editing-toolbar",
"isDesktopOnly": false
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,771 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
*/
'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 = {
regex: /^(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$/i,
lineRegex: /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi,
linkRegex: /^\[([^\[\]]*)\]\((https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})\)$/i,
linkLineRegex: /\[([^\[\]]*)\]\((https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})\)/gi,
imageRegex: /\.(gif|jpe?g|tiff?|png|webp|bmp|tga|psd|ai)$/i,
enhanceDefaultPaste: true,
shouldPreserveSelectionAsTitle: false,
enhanceDropEvents: true,
websiteBlacklist: "",
maximumTitleLength: 0,
useNewScraper: false,
linkPreviewApiKey: "",
useBetterPasteId: false,
};
class AutoLinkTitleSettingTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
let { containerEl } = this;
containerEl.empty();
new obsidian.Setting(containerEl)
.setName("Enhance Default Paste")
.setDesc("Fetch the link title when pasting a link in the editor with the default paste command")
.addToggle((val) => val
.setValue(this.plugin.settings.enhanceDefaultPaste)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.enhanceDefaultPaste = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Enhance Drop Events")
.setDesc("Fetch the link title when drag and dropping a link from another program")
.addToggle((val) => val
.setValue(this.plugin.settings.enhanceDropEvents)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.enhanceDropEvents = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Maximum title length")
.setDesc("Set the maximum length of the title. Set to 0 to disable.")
.addText((val) => val
.setValue(this.plugin.settings.maximumTitleLength.toString(10))
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
const titleLength = Number(value);
this.plugin.settings.maximumTitleLength =
isNaN(titleLength) || titleLength < 0 ? 0 : titleLength;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Preserve selection as title")
.setDesc("Whether to prefer selected text as title over fetched title when pasting")
.addToggle((val) => val
.setValue(this.plugin.settings.shouldPreserveSelectionAsTitle)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.shouldPreserveSelectionAsTitle = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Website Blacklist")
.setDesc("List of strings (comma separated) that disable autocompleting website titles. Can be URLs or arbitrary text.")
.addTextArea((val) => val
.setValue(this.plugin.settings.websiteBlacklist)
.setPlaceholder("localhost, tiktok.com")
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.websiteBlacklist = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Use New Scraper")
.setDesc("Use experimental new scraper, seems to work well on desktop but not mobile.")
.addToggle((val) => val
.setValue(this.plugin.settings.useNewScraper)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.useNewScraper = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("Use Better Fetching Placeholder")
.setDesc("Use a more readable placeholder when fetching the title of a link.")
.addToggle((val) => val
.setValue(this.plugin.settings.useBetterPasteId)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
console.log(value);
this.plugin.settings.useBetterPasteId = value;
yield this.plugin.saveSettings();
})));
new obsidian.Setting(containerEl)
.setName("LinkPreview API Key")
.setDesc("API key for the LinkPreview.net service. Get one at https://my.linkpreview.net/access_keys")
.addText((text) => text
.setValue(this.plugin.settings.linkPreviewApiKey || "")
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
const trimmedValue = value.trim();
if (trimmedValue.length > 0 && trimmedValue.length !== 32) {
new obsidian.Notice("LinkPreview API key must be 32 characters long");
this.plugin.settings.linkPreviewApiKey = "";
}
else {
this.plugin.settings.linkPreviewApiKey = trimmedValue;
}
yield this.plugin.saveSettings();
})));
}
}
class CheckIf {
static isMarkdownLinkAlready(editor) {
let cursor = editor.getCursor();
// Check if the characters before the url are ]( to indicate a markdown link
var titleEnd = editor.getRange({ ch: cursor.ch - 2, line: cursor.line }, { ch: cursor.ch, line: cursor.line });
return titleEnd == "](";
}
static isAfterQuote(editor) {
let cursor = editor.getCursor();
// Check if the characters before the url are " or ' to indicate we want the url directly
// This is common in elements like <a href="linkhere"></a>
var beforeChar = editor.getRange({ ch: cursor.ch - 1, line: cursor.line }, { ch: cursor.ch, line: cursor.line });
return beforeChar == "\"" || beforeChar == "'";
}
static isUrl(text) {
let urlRegex = new RegExp(DEFAULT_SETTINGS.regex);
return urlRegex.test(text);
}
static isImage(text) {
let imageRegex = new RegExp(DEFAULT_SETTINGS.imageRegex);
return imageRegex.test(text);
}
static isLinkedUrl(text) {
let urlRegex = new RegExp(DEFAULT_SETTINGS.linkRegex);
return urlRegex.test(text);
}
}
class EditorExtensions {
static getSelectedText(editor) {
if (!editor.somethingSelected()) {
let wordBoundaries = this.getWordBoundaries(editor);
editor.setSelection(wordBoundaries.start, wordBoundaries.end);
}
return editor.getSelection();
}
static cursorWithinBoundaries(cursor, match) {
let startIndex = match.index;
let endIndex = match.index + match[0].length;
return startIndex <= cursor.ch && cursor.ch <= endIndex;
}
static getWordBoundaries(editor) {
let cursor = editor.getCursor();
// If its a normal URL token this is not a markdown link
// In this case we can simply overwrite the link boundaries as-is
let lineText = editor.getLine(cursor.line);
// First check if we're in a link
let linksInLine = lineText.matchAll(DEFAULT_SETTINGS.linkLineRegex);
for (let match of linksInLine) {
if (this.cursorWithinBoundaries(cursor, match)) {
return {
start: { line: cursor.line, ch: match.index },
end: { line: cursor.line, ch: match.index + match[0].length },
};
}
}
// If not, check if we're in just a standard ol' URL.
let urlsInLine = lineText.matchAll(DEFAULT_SETTINGS.lineRegex);
for (let match of urlsInLine) {
if (this.cursorWithinBoundaries(cursor, match)) {
return {
start: { line: cursor.line, ch: match.index },
end: { line: cursor.line, ch: match.index + match[0].length },
};
}
}
return {
start: cursor,
end: cursor,
};
}
static getEditorPositionFromIndex(content, index) {
let substr = content.substr(0, index);
let l = 0;
let offset = -1;
let r = -1;
for (; (r = substr.indexOf("\n", r + 1)) !== -1; l++, offset = r)
;
offset += 1;
let ch = content.substr(offset, index - offset).length;
return { line: l, ch: ch };
}
}
function blank$1(text) {
return text === undefined || text === null || text === '';
}
function notBlank$1(text) {
return !blank$1(text);
}
function scrape(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield obsidian.requestUrl(url);
if (!response.headers['content-type'].includes('text/html'))
return getUrlFinalSegment$1(url);
const html = response.text;
const doc = new DOMParser().parseFromString(html, 'text/html');
const title = doc.querySelector('title');
if (blank$1(title === null || title === void 0 ? void 0 : title.innerText)) {
// If site is javascript based and has a no-title attribute when unloaded, use it.
var noTitle = title === null || title === void 0 ? void 0 : title.getAttr('no-title');
if (notBlank$1(noTitle)) {
return noTitle;
}
// Otherwise if the site has no title/requires javascript simply return Title Unknown
return url;
}
return title.innerText;
}
catch (ex) {
console.error(ex);
return '';
}
});
}
function getUrlFinalSegment$1(url) {
try {
const segments = new URL(url).pathname.split('/');
const last = segments.pop() || segments.pop(); // Handle potential trailing slash
return last;
}
catch (_) {
return 'File';
}
}
function getPageTitle$1(url) {
return __awaiter(this, void 0, void 0, function* () {
if (!(url.startsWith('http') || url.startsWith('https'))) {
url = 'https://' + url;
}
return scrape(url);
});
}
const electronPkg = require("electron");
function blank(text) {
return text === undefined || text === null || text === "";
}
function notBlank(text) {
return !blank(text);
}
// async wrapper to load a url and settle on load finish or fail
function load(window, url) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
window.webContents.on("did-finish-load", (event) => resolve(event));
window.webContents.on("did-fail-load", (event) => reject(event));
window.loadURL(url);
});
});
}
function electronGetPageTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
const { remote } = electronPkg;
const { BrowserWindow } = remote;
try {
const window = new BrowserWindow({
width: 1000,
height: 600,
webPreferences: {
webSecurity: false,
nodeIntegration: true,
images: false,
},
show: false,
});
window.webContents.setAudioMuted(true);
window.webContents.on("will-navigate", (event, newUrl) => {
event.preventDefault();
window.loadURL(newUrl);
});
yield load(window, url);
try {
const title = window.webContents.getTitle();
window.destroy();
if (notBlank(title)) {
return title;
}
else {
return url;
}
}
catch (ex) {
window.destroy();
return url;
}
}
catch (ex) {
console.error(ex);
return "";
}
});
}
function nonElectronGetPageTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
const html = yield obsidian.request({ url });
const doc = new DOMParser().parseFromString(html, "text/html");
const title = doc.querySelectorAll("title")[0];
if (title == null || blank(title === null || title === void 0 ? void 0 : title.innerText)) {
// If site is javascript based and has a no-title attribute when unloaded, use it.
var noTitle = title === null || title === void 0 ? void 0 : title.getAttr("no-title");
if (notBlank(noTitle)) {
return noTitle;
}
// Otherwise if the site has no title/requires javascript simply return Title Unknown
return url;
}
return title.innerText;
}
catch (ex) {
console.error(ex);
return "";
}
});
}
function getUrlFinalSegment(url) {
try {
const segments = new URL(url).pathname.split('/');
const last = segments.pop() || segments.pop(); // Handle potential trailing slash
return last;
}
catch (_) {
return "File";
}
}
function tryGetFileType(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield fetch(url, { method: "HEAD" });
// Ensure site returns an ok status code before scraping
if (!response.ok) {
return "Site Unreachable";
}
// Ensure site is an actual HTML page and not a pdf or 3 gigabyte video file.
let contentType = response.headers.get("content-type");
if (!contentType.includes("text/html")) {
return getUrlFinalSegment(url);
}
return null;
}
catch (err) {
return null;
}
});
}
function getPageTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
// If we're on Desktop use the Electron scraper
if (!(url.startsWith("http") || url.startsWith("https"))) {
url = "https://" + url;
}
// Try to do a HEAD request to see if the site is reachable and if it's an HTML page
// If we error out due to CORS, we'll just try to scrape the page anyway.
let fileType = yield tryGetFileType(url);
if (fileType) {
return fileType;
}
if (electronPkg != null) {
return electronGetPageTitle(url);
}
else {
return nonElectronGetPageTitle(url);
}
});
}
class AutoLinkTitle extends obsidian.Plugin {
constructor() {
super(...arguments);
this.shortTitle = (title) => {
if (this.settings.maximumTitleLength === 0) {
return title;
}
if (title.length < this.settings.maximumTitleLength + 3) {
return title;
}
const shortenedTitle = `${title.slice(0, this.settings.maximumTitleLength)}...`;
return shortenedTitle;
};
}
onload() {
return __awaiter(this, void 0, void 0, function* () {
console.log("loading obsidian-auto-link-title");
yield this.loadSettings();
this.blacklist = this.settings.websiteBlacklist
.split(",")
.map((s) => s.trim())
.filter((s) => s.length > 0);
// Listen to paste event
this.pasteFunction = this.pasteUrlWithTitle.bind(this);
// Listen to drop event
this.dropFunction = this.dropUrlWithTitle.bind(this);
this.addCommand({
id: "auto-link-title-paste",
name: "Paste URL and auto fetch title",
editorCallback: (editor) => this.manualPasteUrlWithTitle(editor),
hotkeys: [],
});
this.addCommand({
id: "auto-link-title-normal-paste",
name: "Normal paste (no fetching behavior)",
editorCallback: (editor) => this.normalPaste(editor),
hotkeys: [
{
modifiers: ["Mod", "Shift"],
key: "v",
},
],
});
this.registerEvent(this.app.workspace.on("editor-paste", this.pasteFunction));
this.registerEvent(this.app.workspace.on("editor-drop", this.dropFunction));
this.addCommand({
id: "enhance-url-with-title",
name: "Enhance existing URL with link and title",
editorCallback: (editor) => this.addTitleToLink(editor),
hotkeys: [
{
modifiers: ["Mod", "Shift"],
key: "e",
},
],
});
this.addSettingTab(new AutoLinkTitleSettingTab(this.app, this));
});
}
addTitleToLink(editor) {
// Only attempt fetch if online
if (!navigator.onLine)
return;
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
// If the cursor is on a raw html link, convert to a markdown link and fetch title
if (CheckIf.isUrl(selectedText)) {
this.convertUrlToTitledLink(editor, selectedText);
}
// If the cursor is on the URL part of a markdown link, fetch title and replace existing link title
else if (CheckIf.isLinkedUrl(selectedText)) {
const link = this.getUrlFromLink(selectedText);
this.convertUrlToTitledLink(editor, link);
}
}
normalPaste(editor) {
return __awaiter(this, void 0, void 0, function* () {
let clipboardText = yield navigator.clipboard.readText();
if (clipboardText === null || clipboardText === "")
return;
editor.replaceSelection(clipboardText);
});
}
// Simulate standard paste but using editor.replaceSelection with clipboard text since we can't seem to dispatch a paste event.
manualPasteUrlWithTitle(editor) {
return __awaiter(this, void 0, void 0, function* () {
const clipboardText = yield navigator.clipboard.readText();
// Only attempt fetch if online
if (!navigator.onLine) {
editor.replaceSelection(clipboardText);
return;
}
if (clipboardText == null || clipboardText == "")
return;
// If its not a URL, we return false to allow the default paste handler to take care of it.
// Similarly, image urls don't have a meaningful <title> attribute so downloading it
// to fetch the title is a waste of bandwidth.
if (!CheckIf.isUrl(clipboardText) || CheckIf.isImage(clipboardText)) {
editor.replaceSelection(clipboardText);
return;
}
// If it looks like we're pasting the url into a markdown link already, don't fetch title
// as the user has already probably put a meaningful title, also it would lead to the title
// being inside the link.
if (CheckIf.isMarkdownLinkAlready(editor) || CheckIf.isAfterQuote(editor)) {
editor.replaceSelection(clipboardText);
return;
}
// If url is pasted over selected text and setting is enabled, no need to fetch title,
// just insert a link
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
if (selectedText && this.settings.shouldPreserveSelectionAsTitle) {
editor.replaceSelection(`[${selectedText}](${clipboardText})`);
return;
}
// At this point we're just pasting a link in a normal fashion, fetch its title.
this.convertUrlToTitledLink(editor, clipboardText);
return;
});
}
pasteUrlWithTitle(clipboard, editor) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.settings.enhanceDefaultPaste) {
return;
}
if (clipboard.defaultPrevented)
return;
// Only attempt fetch if online
if (!navigator.onLine)
return;
let clipboardText = clipboard.clipboardData.getData("text/plain");
if (clipboardText === null || clipboardText === "")
return;
// If its not a URL, we return false to allow the default paste handler to take care of it.
// Similarly, image urls don't have a meaningful <title> attribute so downloading it
// to fetch the title is a waste of bandwidth.
if (!CheckIf.isUrl(clipboardText) || CheckIf.isImage(clipboardText)) {
return;
}
// We've decided to handle the paste, stop propagation to the default handler.
clipboard.stopPropagation();
clipboard.preventDefault();
// If it looks like we're pasting the url into a markdown link already, don't fetch title
// as the user has already probably put a meaningful title, also it would lead to the title
// being inside the link.
if (CheckIf.isMarkdownLinkAlready(editor) || CheckIf.isAfterQuote(editor)) {
editor.replaceSelection(clipboardText);
return;
}
// If url is pasted over selected text and setting is enabled, no need to fetch title,
// just insert a link
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
if (selectedText && this.settings.shouldPreserveSelectionAsTitle) {
editor.replaceSelection(`[${selectedText}](${clipboardText})`);
return;
}
// At this point we're just pasting a link in a normal fashion, fetch its title.
this.convertUrlToTitledLink(editor, clipboardText);
return;
});
}
dropUrlWithTitle(dropEvent, editor) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.settings.enhanceDropEvents) {
return;
}
if (dropEvent.defaultPrevented)
return;
// Only attempt fetch if online
if (!navigator.onLine)
return;
let dropText = dropEvent.dataTransfer.getData("text/plain");
if (dropText === null || dropText === "")
return;
// If its not a URL, we return false to allow the default paste handler to take care of it.
// Similarly, image urls don't have a meaningful <title> attribute so downloading it
// to fetch the title is a waste of bandwidth.
if (!CheckIf.isUrl(dropText) || CheckIf.isImage(dropText)) {
return;
}
// We've decided to handle the paste, stop propagation to the default handler.
dropEvent.stopPropagation();
dropEvent.preventDefault();
// If it looks like we're pasting the url into a markdown link already, don't fetch title
// as the user has already probably put a meaningful title, also it would lead to the title
// being inside the link.
if (CheckIf.isMarkdownLinkAlready(editor) || CheckIf.isAfterQuote(editor)) {
editor.replaceSelection(dropText);
return;
}
// If url is pasted over selected text and setting is enabled, no need to fetch title,
// just insert a link
let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
if (selectedText && this.settings.shouldPreserveSelectionAsTitle) {
editor.replaceSelection(`[${selectedText}](${dropText})`);
return;
}
// At this point we're just pasting a link in a normal fashion, fetch its title.
this.convertUrlToTitledLink(editor, dropText);
return;
});
}
isBlacklisted(url) {
return __awaiter(this, void 0, void 0, function* () {
yield this.loadSettings();
this.blacklist = this.settings.websiteBlacklist
.split(/,|\n/)
.map((s) => s.trim())
.filter((s) => s.length > 0);
return this.blacklist.some((site) => url.includes(site));
});
}
convertUrlToTitledLink(editor, url) {
return __awaiter(this, void 0, void 0, function* () {
if (yield this.isBlacklisted(url)) {
let domain = new URL(url).hostname;
editor.replaceSelection(`[${domain}](${url})`);
return;
}
// Generate a unique id for find/replace operations for the title.
const pasteId = this.getPasteId();
// Instantly paste so you don't wonder if paste is broken
editor.replaceSelection(`[${pasteId}](${url})`);
// Fetch title from site, replace Fetching Title with actual title
const title = yield this.fetchUrlTitle(url);
const escapedTitle = this.escapeMarkdown(title);
const shortenedTitle = this.shortTitle(escapedTitle);
const text = editor.getValue();
const start = text.indexOf(pasteId);
if (start < 0) {
console.log(`Unable to find text "${pasteId}" in current editor, bailing out; link ${url}`);
}
else {
const end = start + pasteId.length;
const startPos = EditorExtensions.getEditorPositionFromIndex(text, start);
const endPos = EditorExtensions.getEditorPositionFromIndex(text, end);
editor.replaceRange(shortenedTitle, startPos, endPos);
}
});
}
escapeMarkdown(text) {
var unescaped = text.replace(/\\(\*|_|`|~|\\|\[|\])/g, "$1"); // unescape any "backslashed" character
var escaped = unescaped.replace(/(\*|_|`|<|>|~|\\|\[|\])/g, "\\$1"); // escape *, _, `, ~, \, [, ], <, and >
var escaped = unescaped.replace(/(\*|_|`|\||<|>|~|\\|\[|\])/g, "\\$1"); // escape *, _, `, ~, \, |, [, ], <, and >
return escaped;
}
fetchUrlTitleViaLinkPreview(url) {
return __awaiter(this, void 0, void 0, function* () {
if (this.settings.linkPreviewApiKey.length !== 32) {
console.error("LinkPreview API key is not 32 characters long, please check your settings");
return "";
}
try {
const apiEndpoint = `https://api.linkpreview.net/?q=${encodeURIComponent(url)}`;
const response = yield fetch(apiEndpoint, {
headers: {
"X-Linkpreview-Api-Key": this.settings.linkPreviewApiKey,
},
});
const data = yield response.json();
return data.title;
}
catch (error) {
console.error(error);
return "";
}
});
}
fetchUrlTitle(url) {
return __awaiter(this, void 0, void 0, function* () {
try {
let title = "";
title = yield this.fetchUrlTitleViaLinkPreview(url);
console.log(`Title via Link Preview: ${title}`);
if (title === "") {
console.log("Title via Link Preview failed, falling back to scraper");
if (this.settings.useNewScraper) {
console.log("Using new scraper");
title = yield getPageTitle$1(url);
}
else {
console.log("Using old scraper");
title = yield getPageTitle(url);
}
}
console.log(`Title: ${title}`);
title =
title.replace(/(\r\n|\n|\r)/gm, "").trim() ||
"Title Unavailable | Site Unreachable";
return title;
}
catch (error) {
console.error(error);
return "Error fetching title";
}
});
}
getUrlFromLink(link) {
let urlRegex = new RegExp(DEFAULT_SETTINGS.linkRegex);
return urlRegex.exec(link)[2];
}
getPasteId() {
var base = "Fetching Title";
if (this.settings.useBetterPasteId) {
return this.getBetterPasteId(base);
}
else {
return `${base}#${this.createBlockHash()}`;
}
}
getBetterPasteId(base) {
// After every character, add 0, 1 or 2 invisible characters
// so that to the user it looks just like the base string.
// The number of combinations is 3^14 = 4782969
let result = "";
var invisibleCharacter = "\u200B";
var maxInvisibleCharacters = 2;
for (var i = 0; i < base.length; i++) {
var count = Math.floor(Math.random() * (maxInvisibleCharacters + 1));
result += base.charAt(i) + invisibleCharacter.repeat(count);
}
return result;
}
// Custom hashid by @shabegom
createBlockHash() {
let result = "";
var characters = "abcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
for (var i = 0; i < 4; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
onunload() {
console.log("unloading obsidian-auto-link-title");
}
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);
});
}
}
module.exports = AutoLinkTitle;
/* nosourcemap */

View File

@ -0,0 +1,10 @@
{
"id": "obsidian-auto-link-title",
"name": "Auto Link Title",
"version": "1.5.5",
"minAppVersion": "0.12.17",
"description": "This plugin automatically fetches the titles of links from the web",
"author": "Matt Furden",
"authorUrl": "https://github.com/zolrath",
"isDesktopOnly": false
}

View File

@ -0,0 +1 @@
/* no styles */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
{
"id": "obsidian-markdown-formatting-assistant-plugin",
"name": "Markdown Formatting Assistant",
"version": "0.4.1",
"minAppVersion": "0.15.6",
"description": "This Plugin provides a simple Editor for Markdown, HTML and Colors and in addition a command interface. The command interface facilitate a faster workflow.",
"author": "Reocin",
"authorUrl": "https://github.com/Reocin/obsidian-markdown-formatting-assistant-plugin",
"isDesktopOnly": false
}

View File

@ -0,0 +1,62 @@
/* Sets all the text color to red! */
.nav-action-button {
color: var(--text-muted);
cursor: pointer;
padding: 0px;
margin: 5px;
border-radius: 4px;
}
.nav-action-text-button {
color: var(--text-muted);
cursor: pointer;
padding: 5px;
margin: 4px;
border-radius: 4px;
text-align: center;
border: 1px solid;
}
.nav-action-text-button.is-active {
background-color: var(--interactive-accent);
color: var(--text-on-accent);
}
.nav-action-text-button.is-active:hover {
color: var(--text-on-accent);
}
.nav-action-text-button:hover {
color: var(--text-accent);
}
.color-icon {
color: var(--text-muted);
cursor: pointer;
width: 16px;
min-width: 16px;
max-width: 16px;
height: 16px;
min-height: 16px;
max-height: 16px;
margin: 3px;
display: inline-block;
border-radius: 4px;
}
.command-list-view-row {
display: flex;
}
.command-list-view-container {
min-width: 60px;
display: flex;
}
.command-list-view-icon {
height: 24px;
max-height: 24px;
border: 1px solid gray;
margin-right: auto;
}
.command-list-view-text {
padding-left: 12px;
color: #c7254e;
}

View File

@ -0,0 +1,7 @@
{
"rowCount": 8,
"columnCount": 8,
"defaultAlignment": "left",
"defaultCardWidth": 160,
"defaultCardHeight": 160
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
{
"id": "obsidian-table-generator",
"name": "Table Generator",
"version": "1.4.1",
"minAppVersion": "1.1.0",
"description": "A plugin for generate markdown table quickly like Typora /card table in canvas .",
"author": "Boninall",
"authorUrl": "https://github.com/Quorafind",
"fundingUrl": {
"Buy Me a Coffee": "https://www.buymeacoffee.com/boninall",
"爱发电": "https://afdian.net/a/boninall",
"支付宝": "https://cdn.jsdelivr.net/gh/Quorafind/.github@main/IMAGE/%E6%94%AF%E4%BB%98%E5%AE%9D%E4%BB%98%E6%AC%BE%E7%A0%81.jpg"
},
"isDesktopOnly": false
}

View File

@ -0,0 +1,44 @@
.table-container.s-VU35bhriycJk.s-VU35bhriycJk{display:grid;border-bottom:2px dotted var(--color-base-40);border-top:2px dotted var(--color-base-40);padding-top:var(--size-2-1);padding-bottom:var(--size-2-1);width:100%;height:150px;grid-gap:1px}.table-container.s-VU35bhriycJk div.s-VU35bhriycJk{background:var(--color-base-00);border-radius:var(--radius-s);border:1px solid var(--color-base-40)}.table-container.s-VU35bhriycJk .table-generator-cell.s-VU35bhriycJk{height:var(--size-4-4);width:var(--size-4-4)}div.active.s-VU35bhriycJk.s-VU35bhriycJk{background-color:var(--active-color)}.s-VU35bhriycJk.s-VU35bhriycJk{}.table-generator.s-YxLKubgSvLDy{padding-left:5px;padding-right:5px;width:220px}.table-generator-header.s-YxLKubgSvLDy{display:flex;justify-content:space-between;align-items:center;margin-top:var(--size-4-1);margin-bottom:var(--size-4-1)}.input-table-generator.s-YxLKubgSvLDy{margin-left:var(--size-2-2);margin-right:var(--size-2-2);margin-top:var(--size-4-2);margin-bottom:var(--size-4-2);display:flex;justify-content:space-around;align-items:center}.input-table-generator-row.s-YxLKubgSvLDy,.input-table-generator-col.s-YxLKubgSvLDy{display:flex;justify-content:space-around;align-items:center}button.s-YxLKubgSvLDy{width:80px;height:20px;margin:var(--size-4-1) auto var(--size-4-2);padding:0px 10px;text-align:center;text-decoration:none;display:flex;align-items:center}input.s-YxLKubgSvLDy{width:40px;height:18px;border:1px solid var(--color-base-50);margin-left:var(--size-2-2);border-radius:var(--radius-m);text-align:center}.H1.s-YxLKubgSvLDy{margin-left:auto;margin-right:auto;text-align:center}.s-YxLKubgSvLDy{}.table-generator-align-group.s-XNB-qso0yOHJ{display:flex;align-items:center;flex-direction:row;gap:var(--size-2-2)}.table-generator-align-icon.s-XNB-qso0yOHJ{display:flex;align-items:center;justify-content:center;border-radius:var(--radius-s);padding:var(--size-2-1)}.table-generator-align-icon.s-XNB-qso0yOHJ:not(.active):hover{background-color:var(--background-modifier-hover)}.table-generator-align-icon.active.s-XNB-qso0yOHJ{background-color:var(--background-modifier-border-hover)}.s-XNB-qso0yOHJ{}.table-generator-view {
position: absolute;
border: 1px solid var(--color-base-50);
border-radius: 5px;
background-color: var(--color-base-20);
}
.table-generator-setting-text {
min-width: 2.3em;
text-align: right;
}
.theme-light .table-generator-view {
--color-base-00: #ffffff;
--color-base-05: #fcfcfc;
--color-base-10: #fafafa;
--color-base-20: #f6f6f6;
--color-base-25: #e3e3e3;
--color-base-30: #e0e0e0;
--color-base-35: #d4d4d4;
--color-base-40: #bdbdbd;
--color-base-50: #ababab;
--color-base-60: #707070;
--color-base-70: #5a5a5a;
--color-base-100: #222222;
--active-color: rgb(224 242 254);
}
.theme-dark .table-generator-view {
--color-base-00: #1e1e1e;
--color-base-10: #242424;
--color-base-20: #262626;
--color-base-25: #2a2a2a;
--color-base-30: #363636;
--color-base-35: #3F3F3F;
--color-base-40: #555;
--color-base-50: #666;
--color-base-60: #999;
--color-base-70: #bababa;
--color-base-100: #dadada;
--active-color: rgb(3 105 161);
}
.input-table-generator.s-b7dfVi8Mj3e3{margin-left:var(--size-2-2);margin-right:var(--size-2-2);margin-top:var(--size-4-2);margin-bottom:var(--size-4-2);display:flex;justify-content:space-around;align-items:center}.input-table-generator-width.s-b7dfVi8Mj3e3,.input-table-generator-height.s-b7dfVi8Mj3e3{display:flex;justify-content:space-around;align-items:center}input.s-b7dfVi8Mj3e3{width:70px;height:18px;border:1px solid var(--color-base-50);margin-left:var(--size-2-2);border-radius:var(--radius-m);text-align:center}.s-b7dfVi8Mj3e3{}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
{
"id": "obsidian-tasks-plugin",
"name": "Tasks",
"version": "7.18.3",
"minAppVersion": "1.4.0",
"description": "Track tasks across your vault. Supports due dates, recurring tasks, done dates, sub-set of checklist items, and filtering.",
"helpUrl": "https://publish.obsidian.md/tasks/",
"author": "Clare Macrae and Ilyas Landikov (created by Martin Schenck)",
"authorUrl": "https://github.com/obsidian-tasks-group",
"fundingUrl": "https://github.com/sponsors/claremacrae",
"isDesktopOnly": false
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
{
"formatType": "normal",
"showRibbonIcon": true,
"bindEnter": true,
"bindTab": true
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
{
"id": "table-editor-obsidian",
"name": "Advanced Tables",
"author": "Tony Grosinger",
"authorUrl": "https://grosinger.net",
"description": "Improved table navigation, formatting, manipulation, and formulas",
"isDesktopOnly": false,
"minAppVersion": "1.0.0",
"version": "0.22.1",
"js": "main.js",
"fundingUrl": {
"Github Sponsor": "https://github.com/sponsors/tgrosinger",
"Buy me a Coffee": "https://buymeacoffee.com/tgrosinger",
"Paypal": "https://paypal.me/tgrosinger"
},
"donation": "https://buymeacoffee.com/tgrosinger"
}

View File

@ -0,0 +1,78 @@
:root {
--advanced-tables-helper-size: 28px;
}
.HyperMD-table-row span.cm-inline-code {
font-size: 100%;
padding: 0px;
}
.advanced-tables-buttons>div>.title {
font-weight: var(--font-medium);
font-size: var(--nav-item-size);
color: var(--nav-item-color);
text-decoration: underline;
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container {
column-gap: 0.2rem;
margin: 0.2rem 0 0.2rem 0;
justify-content: start;
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container::before {
min-width: 2.6rem;
line-height: var(--advanced-tables-helper-size);
font-size: var(--nav-item-size);
font-weight: var(--nav-item-weight);
color: var(--nav-item-color);
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container>* {
height: var(--advanced-tables-helper-size);
line-height: var(--advanced-tables-helper-size);
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button {
width: var(--advanced-tables-helper-size);
height: var(--advanced-tables-helper-size);
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--radius-s);
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button:hover {
background-color: var(--nav-item-background-hover);
color: var(--nav-item-color-hover);
font-weight: var(--nav-item-weight-hover);
}
.advanced-tables-row-label {
width: 50px;
}
.widget-icon {
width: 20px;
height: 20px;
fill: var(--text-muted);
}
.widget-icon:hover {
fill: var(--text-normal);
}
.advanced-tables-csv-export textarea {
height: 200px;
width: 100%;
}
.advanced-tables-donation {
width: 70%;
margin: 0 auto;
text-align: center;
}
.advanced-tables-donate-button {
margin: 10px;
}

View File

@ -0,0 +1,6 @@
{
"formatType": "normal",
"showRibbonIcon": true,
"bindEnter": true,
"bindTab": true
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
{
"id": "table-editor-obsidian",
"name": "Advanced Tables",
"author": "Tony Grosinger",
"authorUrl": "https://grosinger.net",
"description": "Improved table navigation, formatting, manipulation, and formulas",
"isDesktopOnly": false,
"minAppVersion": "1.0.0",
"version": "0.22.1",
"js": "main.js",
"fundingUrl": {
"Github Sponsor": "https://github.com/sponsors/tgrosinger",
"Buy me a Coffee": "https://buymeacoffee.com/tgrosinger",
"Paypal": "https://paypal.me/tgrosinger"
},
"donation": "https://buymeacoffee.com/tgrosinger"
}

View File

@ -0,0 +1,78 @@
:root {
--advanced-tables-helper-size: 28px;
}
.HyperMD-table-row span.cm-inline-code {
font-size: 100%;
padding: 0px;
}
.advanced-tables-buttons>div>.title {
font-weight: var(--font-medium);
font-size: var(--nav-item-size);
color: var(--nav-item-color);
text-decoration: underline;
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container {
column-gap: 0.2rem;
margin: 0.2rem 0 0.2rem 0;
justify-content: start;
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container::before {
min-width: 2.6rem;
line-height: var(--advanced-tables-helper-size);
font-size: var(--nav-item-size);
font-weight: var(--nav-item-weight);
color: var(--nav-item-color);
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container>* {
height: var(--advanced-tables-helper-size);
line-height: var(--advanced-tables-helper-size);
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button {
width: var(--advanced-tables-helper-size);
height: var(--advanced-tables-helper-size);
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--radius-s);
}
[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button:hover {
background-color: var(--nav-item-background-hover);
color: var(--nav-item-color-hover);
font-weight: var(--nav-item-weight-hover);
}
.advanced-tables-row-label {
width: 50px;
}
.widget-icon {
width: 20px;
height: 20px;
fill: var(--text-muted);
}
.widget-icon:hover {
fill: var(--text-normal);
}
.advanced-tables-csv-export textarea {
height: 200px;
width: 100%;
}
.advanced-tables-donation {
width: 70%;
margin: 0 auto;
text-align: center;
}
.advanced-tables-donate-button {
margin: 10px;
}

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

@ -0,0 +1,5 @@
<%*
const commitMsg = await tp.system.prompt("Message de commit")
const result = await tp.system.exec("git add . && git commit -m \"" + commitMsg + "\"")
tR += result
%>

View File

@ -0,0 +1,5 @@
<%*
const branch = await tp.system.prompt("Branche à utiliser")
const result = await tp.system.exec("git switch " + branch)
tR += result
%>

10
.obsidian/snippets/case_coche.css vendored Normal file
View File

@ -0,0 +1,10 @@
/* ========== CASES À COCHER ========== */
.markdown-preview-view input[type="checkbox"] {
transform: scale(1.2); /* Agrandir la checkbox */
accent-color: #98FF98; /* Couleur de coche (vert pastel) */
margin-right: 8px;
}
.task-list-item.is-checked {
text-decoration: line-through;
color: #888888; /* Tâche grisée si cochée */
}

10
.obsidian/snippets/citations.css vendored Normal file
View File

@ -0,0 +1,10 @@
/* ========== CITATIONS (>) ========== */
.markdown-preview-view blockquote {
border-left: 4px solid #98FF98; /* Vert pastel pour cohérence */
background-color: #1f1f1f; /* Fond foncé légèrement différent */
color: #f0f0f0; /* Texte clair */
font-style: italic; /* Style classique pour citations */
padding: 8px 12px;
margin: 1em 0;
border-radius: 5px;
}

8
.obsidian/snippets/code_inline.css vendored Normal file
View File

@ -0,0 +1,8 @@
/* ========== CODE INLINE (`code`) ========== */
.markdown-preview-view code {
background-color: #333;
color: #ffd700;
padding: 2px 6px;
border-radius: 4px;
font-family: "Fira Code", monospace;
}

5
.obsidian/snippets/hide-inbox.css vendored Normal file
View File

@ -0,0 +1,5 @@
/* Masquer le dossier "inbox" dans l'explorateur de fichiers */
.nav-folder-title[data-path="inbox"] {
display: none !important;
}

9
.obsidian/snippets/lien_extern.css vendored Normal file
View File

@ -0,0 +1,9 @@
/* ========== LIENS EXTERNES ========== */
a.external-link {
color: #FFD700; /* Jaune doré pour les liens externes */
text-decoration: none;
}
a.external-link:hover {
text-decoration: underline;
color: #f0c000;
}

10
.obsidian/snippets/lien_intern.css vendored Normal file
View File

@ -0,0 +1,10 @@
/* ========== LIENS INTERNES ========== */
a.internal-link {
color: #40E0D0; /* Turquoise vif pour les liens internes */
font-weight: bold;
text-decoration: none;
}
a.internal-link:hover {
text-decoration: underline;
color: #20b2aa;
}

9
.obsidian/snippets/listes_puces.css vendored Normal file
View File

@ -0,0 +1,9 @@
/* ========== LISTES À PUCES (ul) ========== */
.markdown-preview-view ul {
list-style-type: disc; /* Cercle plein */
margin-left: 1.5em;
color: #e0e0e0;
}
.markdown-preview-view ul li {
padding: 4px 0;
}

12
.obsidian/snippets/multi_line_code.css vendored Normal file
View File

@ -0,0 +1,12 @@
/* ========== BLOCS DE CODE MULTI-LIGNE ========== */
.markdown-preview-view pre code {
display: block;
background-color: #2b2b2b;
color: #f8f8f2;
padding: 12px;
border-radius: 6px;
overflow-x: auto;
font-family: "Fira Code", monospace;
font-size: 0.95em;
box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.5);
}

9
.obsidian/snippets/picture.css vendored Normal file
View File

@ -0,0 +1,9 @@
/* ========== IMAGES ========== */
.markdown-preview-view img {
max-width: 100%;
border-radius: 6px;
box-shadow: 0 2px 6px rgba(0,0,0,0.5);
margin: 1em 0;
display: block;
}

View File

@ -0,0 +1,34 @@
/* === Responsive pour écrans larges (Ultrawide 21:9) === */
@media (min-aspect-ratio: 21/9) {
.markdown-preview-view, .cm-s-obsidian {
max-width: 95% !important;
margin: 0 auto;
font-size: 1.1em;
}
.workspace-split.mod-vertical {
gap: 16px;
}
body {
--file-line-width: 1000px; /* agrandir zone de lecture */
}
}
/* === Responsive pour écrans standards (16:9 ou moins) === */
@media (max-aspect-ratio: 16/9) {
.markdown-preview-view, .cm-s-obsidian {
max-width: 700px;
margin: auto;
font-size: 1em;
}
.workspace-split.mod-vertical {
gap: 8px;
}
body {
--file-line-width: 650px;
}
}

60
.obsidian/snippets/table_dark_mode.css vendored Normal file
View File

@ -0,0 +1,60 @@
/* ======================================
Style personnalisé pour les TABLEAUX
Obsidian - Thème sombre
====================================== */
/* Style général des tableaux */
.markdown-preview-view table {
border-collapse: collapse; /* Fusionne les bordures des cellules */
width: 100%; /* Prend toute la largeur disponible */
margin: 1em 0; /* Espace au-dessus et en dessous */
background-color: #1e1e1e; /* Couleur de fond du tableau */
color: #e0e0e0; /* Couleur du texte */
border: px solid #444; /* Bordure extérieure */
font-size: 0.95em; /* Légère réduction de la taille de police */
}
/* Style des cellules générales (corps du tableau) */
.markdown-preview-view td {
padding: 10px; /* Espace intérieur dans chaque cellule */
border: 1px solid #444; /* Bordure autour des cellules */
text-align: left; /* Alignement du texte */
vertical-align: top; /* Aligne en haut par défaut */
background-color: #2a2a2a; /* Fond des cellules */
color: #dddddd; /* Couleur du texte des cellules */
}
/* En-tête de colonne */
.markdown-preview-view th {
padding: 12px; /* Espace intérieur des cellules en-tête */
border: 1px solid #555; /* Bordure */
background-color: #333; /* Fond plus contrasté pour les titres */
color: #ffffff; /* Texte plus clair */
text-transform: uppercase; /* Met en majuscules les titres */
font-weight: bold; /* Met les en-têtes en gras */
text-align: center; /* Centre les titres par défaut */
}
/* Ligne survolée */
.markdown-preview-view tr:hover {
background-color: #383838; /* Changement de fond au survol */
}
/* Style de la première colonne si elle agit comme un titre de ligne */
.markdown-preview-view td:first-child {
font-weight: 600; /* Légèrement plus gras */
color: #f1c40f; /* Couleur différente pour se démarquer */
background-color: #262626; /* Fond un peu plus sombre */
}
/* Si tu veux ajouter une bordure arrondie au tableau */
.markdown-preview-view table {
border-radius: 6px; /* Coins arrondis */
overflow: hidden; /* Empêche le débordement des coins */
}
/* Si tu veux ajuster l'espacement entre les lignes */
.markdown-preview-view tr {
line-height: 1.6; /* Hauteur de ligne agréable */
}

16
.obsidian/snippets/tags.css vendored Normal file
View File

@ -0,0 +1,16 @@
/* ========== TAGS (#monTag) ========== */
.markdown-preview-view .tag {
background-color: #333;
color: #ffd700;
padding: 4px 8px;
margin: 2px;
border-radius: 4px;
font-size: 0.85em;
font-weight: bold;
display: inline-block;
text-decoration: none;
}
.markdown-preview-view .tag:hover {
background-color: #444;
cursor: pointer;
}

76
.obsidian/snippets/title_colors.css vendored Normal file
View File

@ -0,0 +1,76 @@
/* Titre de niveau 1 */
.markdown-preview-view h1 {
color: #FF0000;
background-color: #A9A9A9;
text-transform: capitalize;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
border-left: 4px solid #98FF98;
border-right: 4px solid #98FF98;
padding: 1px 4px;
border-radius: 5px;
}
/* Titre de niveau 2 */
.markdown-preview-view h2 {
color: #40E0D0;
background-color: #000000;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
border-left: 4px solid #8B0000;
border-right: 4px solid #8B0000;
padding: 1px 4px;
border-radius: 5px;
}
/* Titre de niveau 3 */
.markdown-preview-view h3 {
color: #FF0000;
background-color: #A9A9A9;
text-transform: capitalize;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
border-left: 4px solid #98FF98;
border-right: 4px solid #98FF98;
padding: 1px 4px;
border-radius: 5px;
}
/* Titre de niveau 4 */
.markdown-preview-view h4 {
color: #27ae60;
background-color: #000000;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
border-left: 4px solid #8B0000;
border-right: 4px solid #8B0000;
padding: 1px 4px;
border-radius: 5px;
}
/* Titre de niveau 5 */
.markdown-preview-view h5 {
color: #00008B;
background-color: #A9A9A9;
text-transform: capitalize;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
border-left: 4px solid #98FF98;
border-right: 4px solid #98FF98;
padding: 1px 4px;
border-radius: 5px;
}
/* Titre de niveau 6 */
.markdown-preview-view h6 {
color: #FFD700;
background-color: #000000;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
border-left: 4px solid #8B0000;
border-right: 4px solid #8B0000;
padding: 6px 8px;
border-radius: 5px;
}

28
.obsidian/types.json vendored Normal file
View File

@ -0,0 +1,28 @@
{
"types": {
"aliases": "aliases",
"cssclasses": "multitext",
"tags": "tags",
"TQ_explain": "checkbox",
"TQ_extra_instructions": "text",
"TQ_short_mode": "checkbox",
"TQ_show_backlink": "checkbox",
"TQ_show_cancelled_date": "checkbox",
"TQ_show_created_date": "checkbox",
"TQ_show_depends_on": "checkbox",
"TQ_show_done_date": "checkbox",
"TQ_show_due_date": "checkbox",
"TQ_show_edit_button": "checkbox",
"TQ_show_id": "checkbox",
"TQ_show_on_completion": "checkbox",
"TQ_show_postpone_button": "checkbox",
"TQ_show_priority": "checkbox",
"TQ_show_recurrence_rule": "checkbox",
"TQ_show_scheduled_date": "checkbox",
"TQ_show_start_date": "checkbox",
"TQ_show_tags": "checkbox",
"TQ_show_task_count": "checkbox",
"TQ_show_tree": "checkbox",
"TQ_show_urgency": "checkbox"
}
}

View File

@ -13,36 +13,316 @@
"state": {
"type": "markdown",
"state": {
"file": "Scripts requêtes Odoo.md",
"file": "Obsidian/Ouvrir un terminal dans Obsidian.md",
"mode": "preview",
"source": false
},
"icon": "lucide-file",
"title": "Ouvrir un terminal dans Obsidian"
}
},
{
"id": "6190bc947aeac61d",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "ollama/guide_ollama_complet.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Scripts requêtes Odoo"
"title": "guide_ollama_complet"
}
},
{
"id": "4a79ae9b5cf40685",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/Infrastructure Optimisée d'IA Locale.md",
"mode": "preview",
"source": false
},
"icon": "lucide-file",
"title": "Infrastructure Optimisée d'IA Locale"
}
},
{
"id": "c732e844eb2b7094",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/Infrastructure Optimisée d'IA Locale (version 2).md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Infrastructure Optimisée d'IA Locale (version 2)"
}
},
{
"id": "c425e145aee8cd6a",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/Agent LLM Classes recherches 1.md",
"mode": "preview",
"source": false
},
"icon": "lucide-file",
"title": "Agent LLM Classes recherches 1"
}
},
{
"id": "9f01b54131d8ad11",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/Agent LLM Classes recherches 1.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Agent LLM Classes recherches 1"
}
},
{
"id": "b9670384c5347fe5",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/LLM Obsidian.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "LLM Obsidian"
}
},
{
"id": "3d7bf6b1be159bbe",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/LLM Cursor.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "LLM Cursor"
}
},
{
"id": "93feebe5d77bd0dc",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "ollama/Plan d'apprentissage détaillé sur Ollama.md",
"mode": "preview",
"source": false
},
"icon": "lucide-file",
"title": "Plan d'apprentissage détaillé sur Ollama"
}
},
{
"id": "aab7b92f101ead65",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "inbox/StramDeck config.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "StramDeck config"
}
},
{
"id": "bf4f5ca51a0e0dd8",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/Optimisation bios serveur.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Optimisation bios serveur"
}
},
{
"id": "2bc8a1b7fd6d9af5",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "inbox/wild.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "wild"
}
},
{
"id": "15f320992faf0688",
"type": "leaf",
"state": {
"type": "graph",
"state": {},
"icon": "lucide-git-fork",
"title": "Vue graphique"
"type": "markdown",
"state": {
"file": "Jour 5 notes support traitement ticket dev.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Jour 5 notes support traitement ticket dev"
}
},
{
"id": "b3459535494873e5",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Obsidian/Obsidian CSS.md",
"mode": "preview",
"source": false
},
"icon": "lucide-file",
"title": "Obsidian CSS"
}
},
{
"id": "72aa54670d29b111",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "inbox/prompt.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "prompt"
}
},
{
"id": "0e580d10b27a161e",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "inbox/prompt.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "prompt"
}
},
{
"id": "5afdc6cb3fe20644",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/Préversion IA locales personnelle.md",
"mode": "preview",
"source": false
},
"icon": "lucide-file",
"title": "Préversion IA locales personnelle"
}
},
{
"id": "4e69fedfd0d21df9",
"type": "leaf",
"state": {
"type": "graph",
"state": {},
"icon": "lucide-git-fork",
"title": "Vue graphique"
}
},
{
"id": "48842f66b7e7e365",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Obsidian/Liens dans obsidian.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Liens dans obsidian"
}
},
{
"id": "64922fb286281777",
"type": "leaf",
"state": {
"type": "graph",
"state": {},
"icon": "lucide-git-fork",
"title": "Vue graphique"
}
},
{
"id": "4102dd91ee7179ea",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "inbox/Piste d'améliorations du projet IA locale.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Piste d'améliorations du projet IA locale"
}
},
{
"id": "ff79cd1085f74b83",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Serveur perso/Création de classes agents pour LLM locaux avec Cursor et Ollama.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Création de classes agents pour LLM locaux avec Cursor et Ollama"
}
},
{
"id": "6d3c8a826a68010d",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Obsidian/Ouvrir un terminal dans Obsidian.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Ouvrir un terminal dans Obsidian"
}
}
],
"currentTab": 1
"currentTab": 11
}
],
"direction": "vertical"
@ -168,8 +448,209 @@
"icon": "lucide-list",
"title": "Plan"
}
},
{
"id": "951b140618e23a01",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "bc83bf4d646c6251",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "7159f03bd4f4713d",
"type": "leaf",
"state": {
"type": "side-panel-control-view",
"state": {},
"icon": "viewIcon",
"title": "Markdown-Autocomplete"
}
},
{
"id": "0c09db9097ae5501",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "40ecd53b5714e84a",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "9e0cb42e4e7fb2ce",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "27a6d9958d77d1c4",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "4984ab5664cbdf1e",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "044d4009eb4d9f09",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "121cd48c0f850895",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "63a2493b28c786f9",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "1b489c2d20569896",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "576a9f452ca5574a",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "924046250738ca76",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "a519ac6a83200154",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "ac6ec92bfe4e4827",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "323408a4d8b291e3",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "8c8085a704076189",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "3063cf0151358bc1",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
},
{
"id": "65cf9e1f20d79f54",
"type": "leaf",
"state": {
"type": "SC-custom-variables-view",
"state": {},
"icon": "code-glyph",
"title": "Shell commands: Custom variables"
}
}
]
],
"currentTab": 23
}
],
"direction": "horizontal",
@ -178,28 +659,66 @@
},
"left-ribbon": {
"hiddenItems": {
"workspaces:Gérer les espaces de travail": false,
"table-editor-obsidian:Advanced Tables Toolbar": false,
"obsidian-markdown-formatting-assistant-plugin:Open Markdown Formatting Assistant": false,
"switcher:Ouvrir le sélecteur rapide": false,
"graph:Ouvrir la vue graphique": false,
"canvas:Créer une nouvelle toile": false,
"daily-notes:Ouvrir la note quotidienne": false,
"templates:Insérer le modèle": false,
"command-palette:Ouvrir la palette de commandes": false
"command-palette:Ouvrir la palette de commandes": false,
"obsidian-shellcommands:Shell commands: Custom variables": false,
"templater-obsidian:Templater": false
}
},
"active": "15f320992faf0688",
"active": "2bc8a1b7fd6d9af5",
"lastOpenFiles": [
"Scripts requêtes Odoo.md",
"T11016.md",
"Réunion 13 mars.md",
"Jour 5 notes support traitement ticket dev.md",
"20 mars Questions pour Karim.md",
"exemple filtre fil de discussion.md",
"README.md",
"Serveur perso/Optimisation bios serveur.md",
"inbox/wild.md",
"Serveur perso/Infrastructure Optimisée d'IA Locale (version 2).md",
"Serveur perso/Infrastructure Optimisée d'IA Locale.md",
"inbox/StramDeck config.md",
"ollama/Plan d'apprentissage détaillé sur Ollama.md",
"Streamdeck",
"ollama/guide_ollama_complet.md",
"Obsidian/Couleurs liens Obsidian.md",
"Stage/20 mars réponses Karim.md",
"Obsidian/Notes Obsidian.md",
"Obsidian/Guide_Organisation.md",
"Obsidian/Liens dans obsidian.md",
"Serveur perso/Agent LLM Classes recherches 1.md",
"Serveur perso/Création de classes agents pour LLM locaux avec Cursor et Ollama.md",
"command_list/Ollama commands.md",
"Serveur perso/automatiser-lancement-serveur-windows.md",
"Serveur perso/LLM Obsidian.md",
"Serveur perso/Piste d'améliorations du projet IA locale.md",
"Serveur perso/Préversion IA locales personnelle.md",
"inbox/Odoo.md",
"inbox/Notes RAGFLOW.md",
"inbox/Notes projet LLM.md",
"Serveur perso/Agent LLM recherches 2.md",
"Obsidian/Ouvrir un terminal dans Obsidian.md",
"Obsidian/Obsidian CSS.md",
"Serveur perso/Recherche modèles.md",
"command_list",
"Stage",
"ollama",
"Obsidian",
"Serveur perso",
"captures/signature.png",
"inbox",
"captures/Capture d'écran 2025-03-20 150304.png",
"captures/Capture d'écran 2025-03-20 150213.png",
"captures/Capture d'écran 2025-03-20 150023.png",
"captures/Capture d'écran 2025-03-20 145754.png",
"captures/Capture d'écran 2025-03-20 145214.png",
"captures/Capture d'écran 2025-03-20 144343.png",
"captures/Capture d'écran 2025-03-20 144317.png",
"captures/Capture d'écran 2025-03-20 143039.png",
"captures/Capture d'écran 2025-03-20 112035.png",
"captures",
"data/ticket_10995_raw.json",
"data",
"Rédiger un cahier des charges pour récupération données dOdoo.md",
"ticket_10995_raw.json",
"README 1.md",
"Bienvenue.md"
"data"
]
}

View File

@ -0,0 +1,89 @@
---
## 🔧 MÉTHODE 1 : Personnaliser les couleurs par dossier ou tag (avec le core dObsidian)
### 👉 Dans la vue graphique (`Graph View > Filters > Groups`), tu peux :
1. Aller dans la **vue graphique globale**
2. En haut à droite, clique sur **licône "Filtres"**
3. Va dans longlet **"Groupes"**
4. Clique sur **"Ajouter un groupe"**
### Puis tu choisis :
- Un **critère** :
- 📁 Dossier (ex: `projets/projetA`)
- 🏷️ Tag (ex: `#projetA`)
- Une **couleur personnalisée**
- **Opacité / style** pour les liens
➡️ Cela te permet de **colorer les notes et leurs liens** selon le projet ou le contexte.
---
## 🎯 MÉTHODE 2 : Coloration des **liens eux-mêmes**, plus avancée (via CSS snippets)
Par défaut, les **liens entre les notes** n'ont pas de couleur spécifique, **mais** tu peux utiliser un **snippet CSS** pour changer la couleur des arêtes selon le contexte (avec limitation sur les liens directs uniquement).
### Exemple de snippet CSS :
```css
.graph-view.color-line .graph-link {
stroke: rgba(255, 255, 255, 0.1); /* couleur par défaut */
}
/* Pour les liens entre notes contenant "projetA" */
.graph-view.color-line .graph-link[data-source*="projetA"] {
stroke: #ff0000; /* rouge pour projet A */
}
.graph-view.color-line .graph-link[data-source*="projetB"] {
stroke: #00ff00; /* vert pour projet B */
}
```
### Étapes :
1. Crée un fichier `.css` dans `.obsidian/snippets`
2. Active-le dans `Paramètres > Apparence > Snippets CSS`
3. Recharge la vue graphique
📌 **Limite** : ça ne fonctionne que si les noms de fichiers incluent le projet, ou avec tag mapping via plugins.
---
## 🧩 MÉTHODE 3 : Plugin **Juggl** (pour graphes plus personnalisables)
- Juggl permet :
- de personnaliser **liens + arêtes** avec des styles
- davoir des **liens directionnels** colorés
- une interface de graphe plus riche
👉 [https://github.com/HEmile/juggl](https://github.com/HEmile/juggl)
---
## ✅ Astuce : organisation par tag ou dossier
|Organisation|Bénéfice dans GraphView|
|---|---|
|`projets/projetA/`|Peut être filtré et coloré|
|`#projetA`|Groupable par tag|
|Liens inter-projets|Visuellement visibles dans le graphe|
---
## 🧠 Exemple concret : différencier projets
|Projet|Tag utilisé|Couleur|
|---|---|---|
|Projet A|`#projetA`|Rouge|
|Projet B|`#projetB`|Bleu|
|Référentiel|`#meta`|Violet|
Puis dans les **groupes du graphe** :
- Groupe par tag = couleur + filtre dynamique
---

View File

@ -0,0 +1,119 @@
# 🧱 Organisation dun Dossier Isolé : `serveur/`
## 🎯 Objectif
Isoler un dossier dédié (ici `serveur/`) pour quil soit :
- Masqué de la **sidebar (explorateur de fichiers)**
- Masqué de la **vue graphique globale**
- Facilement filtrable dans les **recherches et plugins**
- Restant accessible quand je le veux
---
## 1⃣ Création du dossier
- Aller dans la **sidebar → clic droit → Nouveau dossier**
- Nom : `serveur/`
> 💡 Astuce : Tu peux aussi le nommer `_serveur/` pour quil soit trié en bas et reconnu comme dossier technique.
---
## 2⃣ Masquer le dossier de la *sidebar*
### Étapes :
1. Ouvre `Paramètres → Apparence → Snippets CSS`
2. Clique sur **"Ouvrir le dossier des extraits"**
3. Crée un fichier `hide-serveur.css`
4. Copie-colle le CSS suivant :
```css
/* Masquer le dossier 'serveur' dans l'explorateur de fichiers */
.nav-folder-title[data-path="serveur"] {
display: none !important;
}
```
5. Active le snippet dans la liste
---
## 3⃣ Masquer le dossier de la *vue graphique*
### Graphe global :
1. Ouvre la **vue Graphique** (icône réseau)
2. Clique sur ⚙️ **Paramètres du graphe**
3. Dans **"Exclure les fichiers/dossiers"**, ajoute :
```text
serveur/
```
---
### Graphe local :
1. Ouvre une note
2. Clique sur **Graphe local → ⚙️ Options**
3. Exclure aussi le dossier `serveur/`
---
## 4⃣ Filtrage dans les recherches
Dans la recherche (loupe) ou les plugins comme **Dataview**, tu peux filtrer ce dossier :
### Recherche manuelle :
```text
-path:serveur/
```
### Dataview :
```dataview
table file.name
from ""
where !contains(file.path, "serveur")
```
---
## 5⃣ Bonus : Ajouter une page daccueil pour le dossier
Crée une note nommée `_index.md` dans le dossier `serveur/` avec ce contenu :
```markdown
# 🖥️ Tableau de bord : Serveur
- [[fonctionnement_du_serveur]]
- [[commandes_utiles]]
- [[monitoring_et_logs]]
- [[maintenance_preventive]]
```
> 💡 Utilisable avec les plugins **Folder Note** ou **Canvas** pour visualiser tout le contenu lié.
---
## 📦 Résumé
| Action | Méthode |
|----------------------------|-----------------------------|
| Masquer de la sidebar | Snippet CSS personnalisé |
| Masquer du graphe | Filtres dans les options |
| Filtrer des recherches | `-path:serveur/` |
| Garder une porte dentrée | `index.md` ou `canvas` |
---
## 🧠 Astuce : Regrouper tous les dossiers "techniques"
Si tu veux aussi masquer d'autres dossiers comme `_inbox`, `_templates`, tu peux fusionner leur masquage dans un même fichier CSS :
```css
.nav-folder-title[data-path="serveur"],
.nav-folder-title[data-path="_inbox"],
.nav-folder-title[data-path="_templates"] {
display: none !important;
}
```

View File

@ -0,0 +1,73 @@
---
## 🧠 1. **Quest-ce que la vue graphique ?**
La **vue graphique** dObsidian est une représentation **interactive et dynamique** de toutes tes notes **connectées entre elles via des liens internes** (`[[nom de note]]`).
---
## 🔗 2. **Créer des liens depuis la vue graphique**
➡️ Obsidian ne permet pas encore de **créer des liens directs depuis le graphe par glisser-déposer natif**, **mais** tu peux facilement **cliquer et éditer à la volée**. Voici ce que tu peux faire 👇
### ✅ Méthodes actuelles :
#### 🖱️ **A. Cliquer sur une note dans la vue graphique → louvrir → ajouter un lien**
1. Clique sur un nœud dans le graphe (note)
2. La note souvre
3. Tape : `[[nom dune autre note]]`
4. Obsidian met à jour automatiquement le graphe 📈
#### 🧲 **B. Plugin : [Graph Analysis](https://github.com/lynchjames/obsidian-mind-map)** _(ou via Canvas)_
- Permet une navigation intelligente
- Ajoute des interactions (par exemple, **repérer les notes orphelines**)
- Tu peux voir les **liens entrants/sortants** plus visuellement
#### 🎨 **C. Utiliser le plugin [Canvas] pour relier des cartes comme un graphe personnalisé**
- Tu crées un fichier `.canvas`
- Tu ajoutes des notes dedans (drag & drop)
- Tu peux **tirer une flèche entre deux notes** (✅ lien visuel direct)
---
## 🧪 Astuce bonus : créer un lien dans une note depuis la vue
Tu peux aussi :
- Cliquer sur un nœud
- Copier son nom (`Ctrl/Cmd + Shift + L`)
- Aller dans une autre note
- Coller `[[nom]]` → le lien est créé
Le graphe se mettra à jour instantanément.
---
## 🧰 Plugins utiles pour étendre ça
|Plugin|Fonction|
|---|---|
|**Canvas**|Vue relationnelle interactive, liens par flèches|
|**Graph Analysis**|Statistiques + navigation avancée|
|**Juggl** (expérimental)|Permet la création de liens en drag & drop dans un graphe visuel|
|**Breadcrumbs**|Pour organiser des graphes hiérarchiques (ontologie)|
---
## ✅ Conclusion
|Action|Possible dans la vue graphique ?|
|---|---|
|Créer un lien en glissant une flèche|❌ (pas dans la vue principale)|
|Créer un lien depuis une note ouverte|✅ Oui, avec `[[...]]`|
|Voir les liens en temps réel|✅ Oui (automatique)|
|Créer des liens visuellement (Canvas)|✅ Oui (par glisser-flèche)|
|Étendre les fonctions avec des plugins|✅ Fortement recommandé|
---
[[Couleurs liens Obsidian]]

View File

@ -0,0 +1,75 @@
- Création note: ctrl + N
- Palette de commande: ctrl + P
- Ctrl + Alt + clic pour créer une note et diviser l'interface
- Ouvrir certaines notes shift pour ouvrir plusieurs notes dans les onglets
- On peut déplacer intuitivement les fichiers, dossiers et sous-dossiers
- On peut également gérer les fichiers depuis gestionnaire des dossiers OS
- Sauvegarde espace de travail activation plugin et "espace de travail"
- Marquage des notes, dossiers, vue graphique, recherche, titre, section spécifique
- Ctrl E changement de mode (edition, visualisation)
- ctrl + tab et ctrl+shift+tab navigation dans les onglets
#### Format Markdown
- Petit livre en haut à droite, en bas à droite stylo changement de mode
- Explorer click droit en sélectionnant un partie du texte différentes possibilités
- Math block pour faire des maths avec obsidian
- On peut utiliser le format html dans obsidian ajout d'autres possibilités
- Activation pluggin Active toolbar
- ajout couleur etc ...
- Niveaux de titre accéssibles en haut à droite
- On peut configurer (personalisation) les niveau de titre (couleur , taille)
- Mettre en forme le texte
- Italique ctrl + i ou 1 *
- gras ctrl + b 2 *
- Italique + gras 3 *
- barrer texte ~
- Surligner ==
- <u></u> souligner le texte \<u> <\u>
- Crétion d'une citation
- chevron >
- ou callout avec - (citation un peu plus travaillé on peut personnaliser un peu tout)
- liste à puce - deux fois entrée pour la quitter
- liste numéroté 1. et espace
- liste de tâches - [ ]
- \%% pour rendre un commentaire invisible
- Création tableau click droite
- ligne \---
#### Création de liens
- Permet de faire ressortir les informations où qu'elles soient
- Différences entre les tags et les liens
- Dans Obsidian les liens sont plus pertinents
- On peut retrouver toutes les occurences d'une réference taggué rapidement
- On peut aussi vue graphique visualiser directement les mots clés
- Liens permettent de créer une note index et l'éditer permet de relier les notes entre elles de manière plus interactive
- En haut à droite accès au liens
- Différents types de liens
- \[[]] vers notes ou nouvelle note
- \[[Notes Obsidian#]] choix par titre
- \[[Notes Obsidian^]] choix endroit précis
- Voici l'information important \[[Notes Obsidian#^9cdda1| ce que je veux afficher]]
- affichage le contenu d'une note dans une autre note \![[]]
- Utiliser la vue graphique et ses différentes options peut etre judicieux
- mot-clé
- pièces-jointes
- fichiers orphelins (pas rattâchés)
#### Importation de fichiers
- Paramètres/fichiers et liens : création du dossier pièces jointes
- On peut coller les liens directements
- pluggin Auto link title va permettre d'automatiser le nom du lien
- \| ordre de grandeur modifie la taille de la pièce (ex image on peut également longueur x largeur )
- image aligné automatiquement déportée sur la gauche
- lien image en ligne \! devant l'image et \| pour la taille
- Iframe
- exemple youtube partager et intégrer copie iframe et intégrable dans obsidian
- Embarsuer un résultat de recherche altgr+7 permet d'intégrer une recherche récurrente si pertinent à utiliser dans la note pour rechercher
#### Pluggins
- Auto link title permet de gérer automatiquement les titres des liens
- Editing ToolBar (html) va permettre édition plus classique (couleur, etc ...)
[[Couleurs liens Obsidian]]
[[Obsidian CSS]]
[[Liens dans obsidian]]
[[Ouvrir un terminal dans Obsidian]]
[[Guide_Organisation]]

181
Obsidian/Obsidian CSS.md Normal file
View File

@ -0,0 +1,181 @@
## Configuration des titres automatiques
Configuration personnelle dans répertoire snippets du coffre obsidian fichier : title_colors.css
| Couleur | Code HEX | Aperçu |
| ------------ | --------- | ------------------------------------------------------------------------------ |
| Rouge | `#FF0000` | <span style="background-color:#FF0000;color:#fff;padding:2px 8px;"></span> |
| Vert | `#00FF00` | <span style="background-color:#00FF00;"></span> |
| Bleu | `#0000FF` | <span style="background-color:#0000FF;color:#fff;padding:2px 8px;"></span> |
| Jaune | `#FFFF00` | <span style="background-color:#FFFF00;"></span> |
| Cyan | `#00FFFF` | <span style="background-color:#00FFFF;"></span> |
| Magenta | `#FF00FF` | <span style="background-color:#FF00FF;"></span> |
| Noir | `#000000` | <span style="background-color:#000000;color:#fff;padding:2px 8px;"></span> |
| Blanc | `#FFFFFF` | <span style="background-color:#FFFFFF;border:1px solid #ccc;"></span> |
| Gris clair | `#D3D3D3` | <span style="background-color:#D3D3D3;"></span> |
| Gris foncé | `#A9A9A9` | <span style="background-color:#A9A9A9;"></span> |
| Rouge foncé | `#8B0000` | <span style="background-color:#8B0000;color:#fff;padding:2px 8px;"></span> |
| Vert foncé | `#006400` | <span style="background-color:#006400;color:#fff;padding:2px 8px;"></span> |
| Bleu foncé | `#00008B` | <span style="background-color:#00008B;color:#fff;padding:2px 8px;"></span> |
| Orange | `#FFA500` | <span style="background-color:#FFA500;"></span> |
| Or | `#FFD700` | <span style="background-color:#FFD700;"></span> |
| Rose | `#FFC0CB` | <span style="background-color:#FFC0CB;"></span> |
| Lavande | `#E6E6FA` | <span style="background-color:#E6E6FA;"></span> |
| Turquoise | `#40E0D0` | <span style="background-color:#40E0D0;"></span> |
| Indigo | `#4B0082` | <span style="background-color:#4B0082;color:#fff;padding:2px 8px;"></span> |
| Violet | `#800080` | <span style="background-color:#800080;color:#fff;padding:2px 8px;"></span> |
| Bleu ciel | `#87CEEB` | <span style="background-color:#87CEEB;"></span> |
| Vert citron | `#ADFF2F` | <span style="background-color:#ADFF2F;"></span> |
| Rouge corail | `#FF7F50` | <span style="background-color:#FF7F50;"></span> |
| Menthe | `#98FF98` | <span style="background-color:#98FF98;"></span> |
| Bleu pétrole | `#2F4F4F` | <span style="background-color:#2F4F4F;color:#fff;padding:2px 8px;"></span> |
| Sable | `#F4A460` | <span style="background-color:#F4A460;"></span> |
| Chocolat | `#D2691E` | <span style="background-color:#D2691E;color:#fff;padding:2px 8px;"></span> |
| Bronze | `#CD7F32` | <span style="background-color:#CD7F32;"></span> |
| Vert forêt | `#228B22` | <span style="background-color:#228B22;color:#fff;padding:2px 8px;"></span> |
Exemple de code du fichier :
```markdown
.markdown-preview-view h1 {
color: #e74c3c; /* Rouge */
background-color: #ffeaea;
}
.markdown-preview-view h2 {
color: #2980b9; /* Bleu */
background-color: #eaf4ff;
}
.markdown-preview-view h3 {
color: #27ae60; /* Vert */
background-color: #eafff3;
}
.markdown-preview-view h4 {
color: #e67e22; /* Orange */
background-color: #fff3e6;
}
```
```css
/* =========================================
PERSONNALISATION DES TITRES MARKDOWN
========================================= */
.markdown-preview-view h1,
.markdown-preview-view h2,
.markdown-preview-view h3,
.markdown-preview-view h4,
.markdown-preview-view h5,
.markdown-preview-view h6 {
/* === Apparence du texte === */
/* Couleur du texte */
color: #333; /* ➤ Changer la couleur du titre — ex: #e74c3c pour rouge vif */
/* Pour désactiver : commenter ou supprimer la ligne */
/* Police en gras */
font-weight: bold; /* ➤ Force du gras — "normal", "bold", ou 100 à 900 */
/* Style de police */
font-style: normal; /* ➤ "italic" pour pencher les titres */
/* Transformation du texte */
text-transform: none; /* ➤ "uppercase", "lowercase", ou "capitalize" */
/* Soulignement, surlignement */
text-decoration: none; /* ➤ "underline", "line-through", etc. */
/* Ombre sur le texte */
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); /* ➤ Effet d'ombre douce */
/* === Fond et encadrement === */
/* Couleur de fond */
background-color: transparent; /* ➤ Changer pour mettre en valeur (ex: #f0f0f0) */
/* Bordure gauche (style bloc-notes) */
border-left: 4px solid transparent; /* ➤ Couleur & épaisseur personnalisables */
/* Bordure globale (si besoin) */
border: none;
/* Rayon des coins */
border-radius: 4px; /* ➤ Arrondi des bords */
/* === Espacement === */
/* Espace intérieur (entre le texte et le bord) */
padding: 6px 10px; /* ➤ Haut/Bas 6px, Gauche/Droite 10px */
/* Marge extérieure (espacement entre éléments) */
margin-top: 20px;
margin-bottom: 10px;
/* === Taille du texte (ajustable par niveau) === */
/* Décommenter si tu veux des tailles fixes */
/*
font-size: 2em; // h1
font-size: 1.75em; // h2
font-size: 1.5em; // h3
font-size: 1.25em; // h4
font-size: 1em; // h5
font-size: 0.875em;// h6
*/
/* === Police personnalisée === */
/* font-family: 'Fira Code', 'Arial', sans-serif; */
}
```
### 1. Structures de base dans obsidian (éléments ciblages en CSS)
| Élément Obsidian | Sélecteur CSS | Description |
| ------------------------- | ---------------------------- | ------------------------------- |
| Vue lecture (Preview) | `.markdown-preview-view` | Affiche la note en mode lecture |
| Vue édition (Editor) | `.cm-s-obsidian` | Contenu en mode édition |
| Titre de niveau 1 (`#`) | `h1` | Titre principal |
| Titre de niveau 2 (`##`) | `h2` | Sous-titre |
| Titre de niveau 3 (`###`) | `h3` | Sous-sous-titre |
| Citation (`>`) | `blockquote` | Bloc de citation |
| Liste à puces | `ul`, `li` | Liste non ordonnée |
| Liste numérotée | `ol`, `li` | Liste ordonnée |
| Case à cocher | `input[type="checkbox"]` | Checkbox dans les tâches |
| Tâche cochée | `.task-list-item.is-checked` | Tâche marquée comme faite |
| Lien interne | `a.internal-link` | Lien vers une autre note |
| Lien externe | `a.external-link` | Lien vers un site web |
| Tableau Markdown | `table`, `thead`, `td`, `th` | Tableau classique |
| Bloc de code | `pre code`, `code` | Code sur plusieurs lignes |
| Code inline | `code` | Code en ligne |
| Image | `img` | Image insérée |
| Tags (en bas des notes) | `.tag` | Balises de tags Markdown |
### 2. Propriétés CSS utiles (et exemples pour obsidian)
| Propriété CSS | Exemple | Utilité |
|---------------------|--------------------------------|-------------------------------------------------------------|
| `color` | `color: #ff0000;` | Couleur du texte |
| `background-color` | `background-color: #f0f0f0;` | Couleur de fond |
| `font-size` | `font-size: 1.2em;` | Taille du texte |
| `font-family` | `font-family: 'Fira Code';` | Police du texte |
| `font-weight` | `font-weight: bold;` | Gras ou fin |
| `text-align` | `text-align: center;` | Alignement du texte (left, right, center, justify) |
| `text-decoration` | `text-decoration: underline;` | Souligné, barré, etc. |
| `text-transform` | `text-transform: uppercase;` | Majuscules, minuscules |
| `padding` | `padding: 10px;` | Espace intérieur |
| `margin` | `margin: 20px;` | Espace extérieur |
| `border` | `border: 1px solid #ccc;` | Bordure autour dun élément |
| `border-radius` | `border-radius: 8px;` | Coins arrondis |
| `box-shadow` | `box-shadow: 2px 2px 5px #aaa;`| Ombre portée |
| `line-height` | `line-height: 1.5;` | Espacement entre les lignes |
| `display` | `display: block;` | Type d'affichage (inline, block, flex...) |
| `max-width` | `max-width: 800px;` | Limiter la largeur dun élément |
| `overflow` | `overflow: auto;` | Gérer le débordement (utile pour blocs de code/tables) |
### 3. Tableau spécial : personnalisation des tableaux et blocs de code
| Élément | Sélecteur CSS | Propriétés utiles | Exemple |
|--------------------|-----------------------------------|----------------------------------------------------------------------|---------------------------------------------------------------------|
| Tableau | `table` | `border`, `width`, `border-collapse`, `margin`, `background-color` | `table { border: 1px solid #ccc; border-collapse: collapse; }` |
| Ligne de tableau | `tr` | `background-color`, `border-bottom`, `hover` effects | `tr:hover { background-color: #f5f5f5; }` |
| Cellule | `td`, `th` | `padding`, `text-align`, `color` | `td { padding: 8px; text-align: left; }` |
| Tête de tableau | `thead th` | `font-weight`, `background-color` | `thead th { background-color: #eee; font-weight: bold; }` |
| Bloc de code | `pre code` | `background-color`, `padding`, `font-family`, `border-radius` | `pre code { background-color: #f4f4f4; padding: 12px; }` |
| Code inline | `code` | `background`, `padding`, `font-family`, `border-radius` | `code { background: #eee; padding: 2px 4px; }` |
| Scroll horizontal | `pre` | `overflow-x`, `max-width` | `pre { overflow-x: auto; max-width: 100%; }` |

View File

@ -0,0 +1,79 @@
---
## ✅ **1. Plugin recommandé : "Obsidian Shell commands"** (anciennement appelé "Terminal")
### 🔧 Ce plugin te permet de :
- Lancer des **commandes shell** directement dans Obsidian
- Exécuter des scripts Bash, PowerShell, Python, etc.
- Afficher la sortie **dans une note** ou un panneau dédié
---
### ▶️ **Installation pas à pas :**
1. Ouvre Obsidian
2. Va dans `Paramètres > Extensions communautaires`
3. Active `Mode restreint (Restricted Mode)` → **désactivé**
4. Clique sur `Parcourir` et cherche **Shell commands**
5. Clique sur **Installer**, puis **Activer**
---
### 🧪 Exemple dutilisation :
Une fois activé, tu peux :
- Créer une commande comme :
```bash
echo "Bonjour depuis Obsidian"
```
- Ou exécuter un script Python :
```bash
python mon_script.py
```
Le résultat saffiche dans un volet ou directement dans une note si tu le configures ainsi.
---
## 🧰 Alternatives ou usages complémentaires :
|Plugin|Fonction principale|
|---|---|
|**Templater**|Peut exécuter des scripts shell ou node.js|
|**Advanced URI**|Permet de lancer des actions externes depuis Obsidian|
|**Dataview JS**|Peut interagir avec Node.js si bien configuré|
|**Canvas**|Peut contenir des scripts via lien externe|
---
## ⚠️ Limites :
- Ce **nest pas un terminal interactif complet** (comme bash/zsh natif)
- Les entrées sont **prédéfinies** (tu ne tapes pas en temps réel comme dans VSCode)
- Mais cest suffisant pour :
- Lancer des scripts
- Automatiser des tâches
- Compiler, nettoyer, ouvrir des fichiers, etc.
---
## ✅ Bonus : sur Windows ou Linux
Tu peux aussi **ouvrir ton terminal système depuis Obsidian** via :
- **Lien vers un script `.sh`, `.bat`, `.ps1`**
- Ou un lien du type :
```
[Ouvrir Terminal](file:///C:/mon_script.bat)
```
---

View File

@ -0,0 +1,117 @@
# ollama_interface.py
import requests
class OllamaInterface:
def __init__(self, model="mistral", **params):
self.model = model
self.params = params
self.api_url = "http://localhost:11434/api/generate"
def generate(self, prompt: str) -> str:
payload = {"model": self.model, "prompt": prompt, **self.params}
try:
response = requests.post(self.api_url, json=payload)
response.raise_for_status()
return response.json().get("response", "")
except Exception as e:
return f"[Error] {e}"
# base_agent.py
from ollama_interface import OllamaInterface
class BaseAgent:
def __init__(self, name, model="mistral", system_prompt="", **params):
self.name = name
self.system_prompt = system_prompt.strip()
self.llm = OllamaInterface(model=model, **params)
def process(self, input_text: str) -> str:
prompt = f"{self.system_prompt}\n\n{input_text}" if self.system_prompt else input_text
return self.llm.generate(prompt)
# agents.py
from base_agent import BaseAgent
class ObsidianAgent(BaseAgent):
def __init__(self):
super().__init__(
name="ObsidianAgent",
model="mistral",
system_prompt="Tu es un assistant spécialisé dans la structuration et la synthèse de notes Markdown dans Obsidian.",
temperature=0.6, top_k=40, top_p=0.95
)
class CursorAgent(BaseAgent):
def __init__(self):
super().__init__(
name="CursorAgent",
model="codellama:13b-python",
system_prompt="Tu es un assistant de développement intégré à Cursor, spécialisé Python. Reste précis, rapide et concis.",
temperature=0.3, top_k=60, top_p=0.9
)
class MistralServerAgent(BaseAgent):
def __init__(self):
super().__init__(
name="MistralServerAgent",
model="mistral:7b-instruct",
system_prompt="Tu es un chatbot concis et réactif utilisé via une interface web.",
temperature=0.7, top_k=40, top_p=0.92
)
# agent_chain.py
class AgentChain:
def __init__(self, chain_mode=True):
self.agents = []
self.chain_mode = chain_mode
def add_agent(self, agent):
self.agents.append(agent)
def run(self, input_text):
if not self.agents:
return "[Error] Aucun agent enregistré."
if self.chain_mode:
result = input_text
for agent in self.agents:
result = agent.process(result)
return result
else:
return {agent.name: agent.process(input_text) for agent in self.agents}
# main.py
from agents import ObsidianAgent, CursorAgent, MistralServerAgent
from agent_chain import AgentChain
obsidian = ObsidianAgent()
cursor = CursorAgent()
mistral_web = MistralServerAgent()
# Exemple avec chain_mode=False pour obtenir toutes les réponses séparément
dual_chain = AgentChain(chain_mode=False)
dual_chain.add_agent(obsidian)
dual_chain.add_agent(cursor)
dual_chain.add_agent(mistral_web)
input_text = "Organise mes notes Markdown sur un projet de chatbot Python."
results = dual_chain.run(input_text)
for agent_name, output in results.items():
print(f"\n[{agent_name}]\n{output}")
# Exemple avec chain_mode=True pour chaîner les réponses
print("\n--- Mode Chaîné ---")
chained = AgentChain(chain_mode=True)
chained.add_agent(obsidian)
chained.add_agent(cursor)
chained.add_agent(mistral_web)
final_output = chained.run(input_text)
print("\n[Résultat Final Chaîné]\n", final_output)
[[Agent LLM recherches 2]]
[[Création de classes agents pour LLM locaux avec Cursor et Ollama]]

View File

@ -0,0 +1,230 @@
# Tutoriel Complet : Créer et Utiliser des Agents LLM Dynamiques avec Ollama, Python, CLI, Streamlit et Cursor
---
## Objectif
- **Obsidian** (notes, organisation)
- **Cursor** (code, développement)
- **Streamlit** (interface utilisateur graphique)
- **CLI** (ligne de commande)
Chaque agent peut :
- Être instancié avec un **modèle différent** (mistral, codellama, etc.)
- Avoir un **rôle personnalisé** défini dynamiquement à l'appel
- Utiliser des **paramètres avancés** comme temperature, top_p, top_k
- Travailler en **mode synchrone ou asynchrone**
---
## I. Architecture des fichiers
```bash
llm_agents/
├── ollama_interface.py # Interface générique avec Ollama
├── base_agent.py # Classe d'agent configurable
├── agent_factory.py # Création d'agents depuis JSON
├── agent_router.py # Routage intelligent selon le contenu
├── cli.py # Interface terminale (CLI)
├── streamlit_app.py # Interface Streamlit dynamique
├── main.py # Démo complète
├── profiles.json # Profils agents (modèles, rôles)
└── agents/ # Agents spécialisés (optionnel)
```
---
## II. Interface avec Ollama (ollama_interface.py)
```python
import requests
class OllamaInterface:
def __init__(self, model, **params):
self.model = model
self.api_url = "http://localhost:11434/api/generate"
self.params = params
def generate(self, prompt):
payload = {"model": self.model, "prompt": prompt, **self.params}
try:
response = requests.post(self.api_url, json=payload)
response.raise_for_status()
return response.json().get("response", "")
except Exception as e:
return f"[Erreur Ollama] {e}"
```
---
## III. Classe de base des agents (base_agent.py)
```python
import logging
from ollama_interface import OllamaInterface
class BaseAgent:
def __init__(self, name, model, system_prompt="", async_mode=False, enable_logging=True, **params):
self.name = name
self.system_prompt = system_prompt.strip()
self.async_mode = async_mode
self.enable_logging = enable_logging
self.llm = OllamaInterface(model=model, **params)
self.history = []
if enable_logging:
logging.basicConfig(
filename=f"{self.name}.log",
level=logging.INFO,
format="%(asctime)s [%(name)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
def set_role(self, prompt_system):
self.system_prompt = prompt_system.strip()
def build_prompt(self, user_input):
return f"{self.system_prompt}\n\n{user_input}" if self.system_prompt else user_input
def log(self, prompt, response):
if self.enable_logging:
logging.getLogger(self.name).info(f"Prompt:\n{prompt}\nRéponse:\n{response}\n")
def process(self, user_input):
prompt = self.build_prompt(user_input)
response = self.llm.generate(prompt)
self.log(prompt, response)
self.history.append((prompt, response))
return response
```
---
## IV. Création d'agents dynamiques avec des rôles
```python
from base_agent import BaseAgent
agent1 = BaseAgent("AnalyseurNote", model="mistral")
agent1.set_role("Tu analyses les notes markdown pour en extraire la structure.")
agent2 = BaseAgent("Correcteur", model="mistral")
agent2.set_role("Tu corriges l'orthographe et mets en page le texte Markdown.")
note = "ceci est une not mal structuré avec des errurs"
print(agent1.process(note))
print(agent2.process(note))
```
---
## V. AgentRouter — routage intelligent selon le contenu
```python
class AgentRouter:
def __init__(self, agents):
self.agents = {agent.name.lower(): agent for agent in agents}
def route(self, prompt):
if "code" in prompt.lower():
return self.agents["codeoptimizer"].process(prompt)
elif "note" in prompt.lower() or "obsidian" in prompt.lower():
return self.agents["analyseurnote"].process(prompt)
else:
return self.agents["correcteur"].process(prompt)
```
---
## VI. Exemple avec plusieurs agents dynamiques (main.py)
```python
from base_agent import BaseAgent
analyse = BaseAgent("analyseur", model="mistral")
analyse.set_role("Tu es un expert Obsidian. Analyse les notes et suggère des améliorations.")
optimiseur = BaseAgent("codeoptimizer", model="codellama:13b-python")
optimiseur.set_role("Tu es un assistant Python. Améliore le code donné.")
texte = "Voici une note mal formée sur FastAPI"
code = "def app(): return None"
print(analyse.process(texte))
print(optimiseur.process(code))
```
---
## VII. Interface CLI (cli.py)
```python
from base_agent import BaseAgent
name = input("Nom de l'agent : ")
model = input("Modèle Ollama (ex: mistral) : ")
role = input("Décris le rôle de l'agent : ")
agent = BaseAgent(name=name, model=model)
agent.set_role(role)
while True:
prompt = input("\nPrompt > ")
if prompt in ["exit", "quit"]:
break
print(agent.process(prompt))
```
---
## VIII. Interface Streamlit (streamlit_app.py)
```python
import streamlit as st
from base_agent import BaseAgent
st.title("Créateur d'agents LLM dynamiques")
name = st.text_input("Nom de l'agent")
model = st.text_input("Modèle Ollama", value="mistral")
role = st.text_area("Prompt système (rôle)")
prompt = st.text_area("Message utilisateur")
if st.button("Créer et exécuter"):
agent = BaseAgent(name=name, model=model)
agent.set_role(role)
st.write(agent.process(prompt))
```
---
## IX. Exemple de configuration JSON (profiles.json)
```json
{
"agents": [
{
"name": "ObsidianNoteur",
"model": "mistral",
"system_prompt": "Tu aides à structurer des notes Markdown.",
"temperature": 0.6
},
{
"name": "PythonHelper",
"model": "codellama:13b-python",
"system_prompt": "Tu améliores du code Python.",
"temperature": 0.4
}
]
}
```
---
## Conclusion
Tu disposes maintenant :
- D'une **base agent dynamique** et paramétrable
- De **rôles personnalisables** via `set_role()`
- D'exemples concrets dans Obsidian, Cursor, CLI et Streamlit

View File

@ -0,0 +1,153 @@
---
## 🎯 Objectif du document
Mettre en place une architecture de classes Python orientées agent pour exploiter tes modèles locaux avec **Ollama**, accessibles facilement depuis **Cursor**, tout en permettant :
- Une configuration précise des modèles (température, top-k, top-p, prompt system).
- Une gestion unifiée des LLM installés sur plusieurs machines.
- Une structure extensible pour ajouter ou spécialiser des agents par tâche.
---
## 🧠 Vision : Agents = Interfaces contrôlées sur tes LLM
n8n + MCP toffrent une **vision visuelle et événementielle des agents**, mais en Python tu peux :
- Instancier des "agents" comme **classes Python**.
- Utiliser des **paramètres dynamiques**, prompts, fonctions de routage.
- Contrôler finement lappel à chaque LLM local via API Ollama.
---
## 📦 Organisation des fichiers Python
```bash
llm_agents/
├── base_agent.py # Classe de base commune à tous les agents
├── ollama_interface.py # Interface API Ollama
├── agent_mistral.py # Agent général Mistral
├── agent_code.py # Agent codellama spécialisé
├── agent_docs.py # Agent lecture & synthèse de documents
└── main.py # Exemple dappel centralisé depuis Cursor
```
---
## 🧩 `ollama_interface.py` Appels API Ollama centralisés
```python
import requests
class OllamaInterface:
def __init__(self, model="mistral", temperature=0.7, top_k=40, top_p=0.9):
self.model = model
self.temperature = temperature
self.top_k = top_k
self.top_p = top_p
self.api_url = f"http://localhost:11434/api/generate"
def generate(self, prompt):
payload = {
"model": self.model,
"prompt": prompt,
"temperature": self.temperature,
"top_k": self.top_k,
"top_p": self.top_p
}
response = requests.post(self.api_url, json=payload)
return response.json().get("response", "")
```
---
## 🧬 `base_agent.py` Classe de base
```python
from ollama_interface import OllamaInterface
class BaseAgent:
def __init__(self, name, model="mistral", **kwargs):
self.name = name
self.llm = OllamaInterface(model=model, **kwargs)
def respond(self, prompt):
raise NotImplementedError("Chaque agent doit définir sa méthode respond.")
```
---
## 🤖 `agent_mistral.py` Agent généraliste
```python
from base_agent import BaseAgent
class MistralAgent(BaseAgent):
def respond(self, prompt):
system_prompt = "Tu es un assistant personnel expert et structuré."
full_prompt = f"{system_prompt}\n\n{prompt}"
return self.llm.generate(full_prompt)
```
---
## 💻 `agent_code.py` Agent spécialisé codellama
```python
from base_agent import BaseAgent
class CodeAgent(BaseAgent):
def respond(self, prompt):
full_prompt = f"Tu es un assistant Python. Corrige, commente ou optimise ce code :\n{prompt}"
return self.llm.generate(full_prompt)
```
---
## 📚 `agent_docs.py` Agent pour résumer ou structurer des documents
```python
from base_agent import BaseAgent
class DocAgent(BaseAgent):
def respond(self, content):
full_prompt = f"Voici un document brut, résume-le de manière claire et concise :\n{content}"
return self.llm.generate(full_prompt)
```
---
## 🚀 `main.py` Exemple d'utilisation dans Cursor
```python
from agent_code import CodeAgent
from agent_mistral import MistralAgent
code_agent = CodeAgent(name="CodeLLM", model="codellama")
mistral_agent = MistralAgent(name="Assistant")
print(mistral_agent.respond("Organise-moi un plan de projet pour une API REST en FastAPI."))
print(code_agent.respond("def addition(a, b): return a + b"))
```
---
## 🧩 Extensions possibles
- Ajouter un système de **profil JSON par agent**.
- Intégrer la **gestion via n8n** (webhook qui déclenche un agent).
- Exécuter lagent depuis une **interface Streamlit locale ou TUI**.
- Ajout futur : classe `MultiAgentRouter` qui oriente la requête selon le besoin (code, doc, discussion).
---
## ✅ Avantages
- Contrôle total sur les modèles.
- Usage rapide dans Cursor.
- Base solide pour agents orchestrables.
---
Souhaites-tu que je taide à créer un routeur ou une interface CLI/Streamlit pour tester ça en live ?

View File

@ -0,0 +1,212 @@
---
## Schéma détaillé de l'installation
```
PC Principal (Windows 11 Pro)
├── Disque principal (Crucial T700 - 2 To)
│ ├── Windows 11
│ ├── Logiciels principaux
│ ├── Ollama + WSL2
├── Disques Crucial P3 (4 To x2)
│ ├── P3 (1)
│ │ ├── Modèles LLM
│ │ └── Fine-tuning (LoRA)
│ └── P3 (2)
│ └── Données (notes, code, contenus)
└── SSD MX500 SATA
└── Sauvegardes & temporaires
Serveur Windows Server 2025
├── Disque NVMe Gen3
│ ├── OS
│ ├── IIS
│ ├── Next.js
│ ├── Strapi
│ └── Base vectorielle (RAG avec Ragflow)
├── SSD 240 Go SATA
│ ├── FastAPI
│ └── Ollama (Mistral 7B)
├── HDD RAID1
│ └── Données site web (images, médias)
└── HDD 8To / 3To
└── Sauvegardes & archives
```
---
## Intégration et Avantages de n8n et MCP
### n8n (Automatisation de workflows open-source)
- **Description :** Plateforme visuelle d'automatisation permettant de créer des workflows entre API, fichiers, bases de données et services locaux ou cloud.
- **Licence :** Gratuit en auto-hébergement, version cloud payante si hébergée par n8n.io
- **Utilisations recommandées :**
- Automatiser la synchronisation entre Ragflow, Strapi, fichiers de code, notes Obsidian
- Déclencher des actions : sauvegarde automatique, traitement de données, appel de modèles LLM
- Lier des événements : création dun fichier → ajout dans la base vectorielle
#### 🚀 Installation de n8n (Docker - Serveur ou PC Principal)
```bash
docker run -it --rm \
-p 5678:5678 \
-v ~/.n8n:/home/node/.n8n \
-e N8N_HOST=localhost \
-e N8N_PORT=5678 \
n8nio/n8n
```
- Accès ensuite à linterface : [http://localhost:5678](http://localhost:5678/)
- Créer un utilisateur, commencer à connecter tes services.
#### ✅ Exemples de workflows utiles
- Fichier ajouté dans `/mnt/d/notes` → envoyer dans Ragflow via HTTP Request
- Webhook Strapi → traitement avec LLM → export JSON/Markdown
- Surveillance dun dossier → déclenchement dun fine-tuning
---
### MCP (Machine Learning Control Panel)
- **Description :** Interface open-source pour gérer et visualiser les modèles LLM, entraînements, datasets.
- **Licence :** Gratuit (open-source), fonctionne via Docker ou installation manuelle.
#### 🔧 Installation MCP (avec Docker)
```bash
git clone https://github.com/mgoin/MCP.git
cd MCP
sudo docker-compose up --build
```
- Interface Web accessible à : [http://localhost:8000](http://localhost:8000/) ou via ton IP réseau
#### ✅ Utilisation typique
- Visualisation en temps réel de lactivité de tes modèles (RAM, VRAM, charge CPU)
- Gestion de sessions de fine-tuning via interface graphique
- Déploiement local de modèles LoRA/Ollama
- Intégration avec ChromaDB ou Ragflow pour annotation automatique
#### 💡 Fonctionnalités supplémentaires intéressantes
- Création de profils pour tes différents modèles
- Suivi des performances GPU/CPU (intégration avec `nvitop` ou Prometheus)
- Logs centralisés de toutes les exécutions
---
## Utilisation combinée n8n + MCP
### 🔄 Scénario synergique
- **n8n** automatise les déclenchements (surveillance de dossiers, synchronisation de données, webhooks dObsidian ou Strapi)
- **MCP** exécute les tâches IA correspondantes et fournit un tableau de bord pour suivre chaque étape.
### 🔗 Exemple concret
1. n8n surveille `/mnt/d/notes` sur ton PC principal.
2. Lorsquun nouveau fichier est détecté, il appelle une API FastAPI (ou script Python) qui :
- alimente Ragflow avec le contenu
- déclenche une session de fine-tuning si besoin (via API MCP ou ligne de commande)
3. MCP enregistre lopération, affiche létat de la RAM/VRAM, et permet de suivre l'entraînement.
### 🧠 Avantages de la combinaison
- **Automatisation complète sans intervention manuelle.**
- **Contrôle fin et centralisé de toutes les IA.**
- **Surveillance continue avec logs et retour visuel.**
---
## Tirer le Meilleur Parti de ChatGPT Plus & Cursor Pro
### Avantages de ChatGPT Plus
- Accès prioritaire et performances optimisées
- Complémentarité avec modèles locaux
### Avantages de Cursor Pro
- IDE optimisé pour l'IA
- Intégration transparente avec modèles locaux et GPT-4
---
## Installation et Optimisation de Ragflow (sur le serveur)
#### Pré-requis
```bash
npm install -g ragflow-cli
```
#### Configuration
```bash
ragflow init rag-db
cd rag-db
```
#### Installation des dépendances
```bash
pip install ragflow chromadb
```
#### Démarrage de Ragflow
```bash
ragflow start
```
### Optimisation des ressources
- **Disque :** NVMe Gen3
- **RAM dédiée :** 24 Go
---
## Optimisation RAMDISK
- Accélère accès temporaires durant fine-tuning
- Taille : 16 Go (PC principal)
- Logiciel : **ImDisk Toolkit**
---
## Tableau des commandes Nvidia
|Commande|Description|
|---|---|
|`nvidia-smi`|Affiche usage GPU actuel, mémoire, température.|
|`nvidia-smi -l 1`|Rafraîchissement toutes les secondes|
|`nvidia-smi -q`|Rapport complet GPU|
|`nvcc --version`|Version CUDA installée|
|`nvitop`|Surveillance interactive temps réel (GPU)|
---
## Surveillance Ollama
```bash
ollama ps
```
Ce guide intègre désormais des outils puissants comme **n8n** pour lautomatisation, et **MCP** pour le contrôle de tes modèles IA, tous deux auto-hébergeables et gratuits, parfaitement intégrés à ton infrastructure locale, avec une synergie complète pour automatiser, surveiller et ajuster intelligemment ton flux de travail IA.
[[Agent LLM Classes recherches 1]]
[[LLM Cursor]]
[[LLM Obsidian]]
[[Piste d'améliorations du projet IA locale]]
[[Optimisation bios serveur]]

View File

@ -0,0 +1,176 @@
---
## Schéma détaillé de l'installation
```
PC Principal (Windows 11 Pro)
├── Disque principal (Crucial T700 - 2 To)
│ ├── Windows 11
│ ├── Logiciels principaux
│ ├── Ollama + WSL2
├── Disques Crucial P3 (4 To x2)
│ ├── P3 (1)
│ │ ├── Modèles LLM
│ │ └── Fine-tuning (LoRA)
│ └── P3 (2)
│ └── Données (notes, code, contenus)
└── SSD MX500 SATA
└── Sauvegardes & temporaires
Serveur Windows Server 2025
├── Disque NVMe Gen3
│ ├── OS
│ ├── IIS
│ ├── Next.js
│ ├── Strapi
│ └── Base vectorielle (RAG avec Ragflow)
├── SSD 240 Go SATA
│ ├── FastAPI
│ └── Ollama (Mistral 7B)
├── HDD RAID1
│ └── Données site web (images, médias)
└── HDD 8To / 3To
└── Sauvegardes & archives
```
---
## Optimisation RAMDISK
### Pourquoi utiliser RAMDISK ?
- Accélère significativement les accès aux fichiers temporaires durant le fine-tuning.
- Parfait pour des opérations intensives ponctuelles.
### Recommandation d'utilisation RAMDISK
- Taille recommandée : jusqu'à 16 Go sur le PC principal lors du fine-tuning uniquement.
- Logiciel recommandé sous Windows : **ImDisk Toolkit**.
- Créer/détruire le RAMDISK uniquement pendant les sessions de fine-tuning pour libérer les ressources après utilisation.
---
## Commande Nvidia : `nvitop`
### Installation de `nvitop` :
```bash
pip install nvitop
```
### Utilisation :
```bash
nvitop
```
- Affiche une vue interactive avancée des ressources GPU en temps réel (similaire à `htop` pour GPU).
- Indispensable pour surveiller efficacement la consommation GPU lors du fine-tuning et utilisation des modèles LLM.
---
## Optimisation Fine-tuning (LoRA)
- **Répertoire dédié :** Crucial P3 (1) ou RAMDISK pour vitesse optimale.
- **RAM recommandée :** jusqu'à 16 Go durant le fine-tuning.
- **Pause des modèles en jeu :**
```bash
ollama stop <modèle>
```
---
## Tableau des commandes Nvidia détaillées
|Commande|Description|
|---|---|
|`nvidia-smi`|Affiche usage GPU actuel, mémoire, température.|
|`nvidia-smi -l 1`|Rafraîchissement toutes les secondes|
|`nvidia-smi -q`|Rapport complet GPU|
|`nvidia-smi topo -m`|Topologie GPU (multi-GPU)|
|`nvcc --version`|Version CUDA installée|
|`watch -n 1 nvidia-smi`|Suivi temps réel GPU (Linux/WSL)|
|`nvitop`|Surveillance interactive temps réel (GPU)|
---
## Script Python : Surveillance des Ressources Systèmes
### Dépendances
```bash
pip install psutil GPUtil
```
### Code
```python
import psutil
import GPUtil
import time
def get_system_usage():
cpu_usage = psutil.cpu_percent(interval=1)
ram_usage = psutil.virtual_memory().percent
gpu_info = GPUtil.getGPUs()[0] # GPU principal
gpu_load = gpu_info.load * 100
gpu_temp = gpu_info.temperature
print(f"CPU Usage: {cpu_usage}%")
print(f"RAM Usage: {ram_usage}%")
print(f"GPU Load: {gpu_load}%")
print(f"GPU Temperature: {gpu_temp}°C")
if __name__ == "__main__":
while True:
get_system_usage()
print("-"*30)
time.sleep(5)
```
### Surveillance Ollama (modèles en cours d'utilisation)
```bash
ollama ps
```
### Gestion par WSL2
Par défaut, tous les disques Windows sont automatiquement montés dans WSL2 sous le répertoire :
```bash
/mnt/
```
Par exemple :
- Disque C sous Windows → `/mnt/c`
- Disque D sous Windows → `/mnt/d`
- Et ainsi de suite pour chaque disque disponible.
### Exemple :
Pour accéder à ton disque Crucial P3 (1), si sous Windows il est assigné à la lettre `D`, tu feras :
```bash
cd /mnt/d/
```
Ainsi, toutes les opérations (installation Ollama, Ragflow, scripts Python, etc.) peuvent être réalisées directement depuis WSL en bénéficiant pleinement des performances de tes disques NVMe.
C'est d'ailleurs la méthode recommandée pour utiliser Ollama, les modèles LLM, et Ragflow efficacement tout en profitant de la simplicité de gestion offerte par WSL2.
Ce guide optimisé prend en compte la centralisation Ragflow sur serveur, la gestion fine du fine-tuning avec RAMDISK optionnel, et la flexibilité pour maximiser les performances gaming tout en utilisant efficacement la RAM et le GPU.
[[automatiser-lancement-serveur-windows]]
[[Préversion IA locales personnelle]]
[[Infrastructure Optimisée d'IA Locale (version 2)]]

View File

@ -0,0 +1,212 @@
# Guide Complet : Intégration des Agents LLM Dynamiques dans Cursor avec Cline
---
## Objectif
- Lancer des modèles localement (codellama, mistral, etc.)
- Créer des **agents dynamiques spécialisés** pour coder, expliquer, corriger
- Utiliser et configurer **Cline** pour interagir visuellement avec tes agents
---
## I. Prérequis
- Avoir installé **Cursor** : [https://cursor.so](https://cursor.so/)
- Avoir installé **Ollama** : [[https://ollama.com](https://ollama.com/))
- Avoir Python 3.10+ installé
### Installer un modèle avec Ollama :
```bash
ollama pull codellama:13b-python
ollama pull mistral
```
Teste le bon fonctionnement :
```bash
ollama run mistral
```
---
## II. Intégrer Ollama à Cursor via `cursor-agent.json`
Crée ce fichier à la racine du projet :
```json
{
"name": "LLM Local Agent",
"entry": "main.py",
"llm": {
"provider": "custom",
"completion_url": "http://localhost:11434/api/generate",
"method": "POST",
"headers": { "Content-Type": "application/json" },
"input_key": "prompt",
"output_key": "response"
}
}
```
> Ce fichier connecte Cursor à ton modèle local via API HTTP.
---
## III. Cline dans Cursor : installation, configuration et usage
### Qu'est-ce que **Cline** ?
Cline est la **barre latérale interactive** dans Cursor. Elle te permet de :
- Créer des agents avec rôles personnalisés
- Interagir avec ton code sélectionné ou tout le fichier
- Voir la réponse du modèle directement à droite
- Ajouter des prompts, des messages système ou modifier des paramètres
### Comment lactiver ?
1. Sélectionne du code
2. Tape `//` pour activer un prompt (comme un commentaire)
3. Cline souvre automatiquement à droite
4. Tu peux :
- Choisir ton modèle (`cursor-agent.json` doit être actif)
- Envoyer un prompt
- Lire et copier la réponse
### Pourquoi cest utile ?
Cline est **idéal pour le développement assisté par LLM**, car tu peux :
- Corriger le code sélectionné
- Générer automatiquement du code ou des tests
- Interagir avec différents agents en parallèle
- Comparer les retours selon les rôles
---
## IV. Créer un agent dynamique personnalisé (main.py)
```python
from base_agent import BaseAgent
agent = BaseAgent("CodeExplainer", model="mistral")
agent.set_role("Tu es un assistant Python expert. Tu expliques de manière claire le fonctionnement dun code donné.")
prompt = input("Prompt utilisateur : ")
print(agent.process(prompt))
```
---
## V. Exemple de rôles dagents Cursor
```python
explainer = BaseAgent("Explainer", model="mistral")
optimizer = BaseAgent("Optimizer", model="codellama:13b-python")
refactor = BaseAgent("Refactor", model="codellama:13b-python")
explainer.set_role("Explique ce que fait le code avec précision.")
optimizer.set_role("Optimise ce code Python pour la performance.")
refactor.set_role("Refactore le code pour quil soit plus lisible.")
code = '''
def process(x): return [i*2 for i in x if i > 0]'''
print(explainer.process(code))
```
---
## VI. Support multi-machine : Agents locaux ou distants (serveur)
Tu peux travailler avec un **Ollama local sur ton PC principal** ou utiliser un **serveur distant** qui héberge un modèle (par ex. Mistral 7B déjà actif sur ton site).
### 1. Classe RemoteLLMInterface
```python
import requests
class RemoteLLMInterface:
def __init__(self, model, host="http://192.168.1.150:11434", **params):
self.model = model
self.api_url = f"{host}/api/generate"
self.params = params
def generate(self, prompt):
payload = {"model": self.model, "prompt": prompt, **self.params}
response = requests.post(self.api_url, json=payload)
return response.json().get("response", "")
```
### 2. Créer un agent distant :
```python
from remote_llm_interface import RemoteLLMInterface
class RemoteAgent:
def __init__(self, name, model="mistral", host="http://192.168.1.150:11434", **params):
self.name = name
self.interface = RemoteLLMInterface(model, host, **params)
self.system_prompt = ""
def set_role(self, prompt):
self.system_prompt = prompt.strip()
def process(self, user_input):
full_prompt = f"{self.system_prompt}\n\n{user_input}" if self.system_prompt else user_input
return self.interface.generate(full_prompt)
```
> Tu peux ainsi appeler le modèle Mistral 7B de ton site **depuis Cursor**, sans le réinstaller localement.
---
## VII. Changer dagent facilement (CLI rapide)
```python
from base_agent import BaseAgent
name = input("Nom de lagent : ")
model = input("Modèle Ollama (ex: mistral) : ")
role = input("Quel est le rôle de lagent ? : ")
prompt = input("Quel est le prompt ? : ")
agent = BaseAgent(name=name, model=model)
agent.set_role(role)
print(agent.process(prompt))
```
---
## VIII. Exemples d'agents à utiliser dans Cursor
|Nom Agent|Modèle|Rôle assigné|
|---|---|---|
|`Optimizer`|`codellama:13b-python`|Optimise le code|
|`Explainer`|`mistral`|Explique le code|
|`BugFinder`|`codellama:13b-python`|Trouve des erreurs|
|`DocGen`|`mistral`|Génère des docstrings|
|`Formatter`|`codellama`|Reformate proprement le code|
---
## IX. Bonnes pratiques avec Cursor et Cline
- Utilise `//` pour poser des questions précises à ton agent
- Crée plusieurs agents avec des rôles spécialisés : rapide à réutiliser
- Utilise des raccourcis clavier pour alterner entre agents dans Cline
- Sauvegarde tes rôles les plus utiles dans un fichier JSON ou via script
- Combine les agents dans une chaîne pour effectuer plusieurs actions à la suite
---
## Conclusion
Tu maîtrises maintenant :
- Linstallation dOllama et des modèles
- La configuration de Cursor et lutilisation de `cursor-agent.json`
- Linteraction avancée avec Cline (prompts, agents multiples, feedback instantané)
- La création dagents dynamiques **locaux ou distants**, selon ton architecture

214
Serveur perso/LLM Cursor.md Normal file
View File

@ -0,0 +1,214 @@
# Guide Complet : Intégration des Agents LLM Dynamiques dans Cursor avec Cline
---
## Objectif
- Lancer des modèles localement (codellama, mistral, etc.)
- Créer des **agents dynamiques spécialisés** pour coder, expliquer, corriger
- Utiliser et configurer **Cline** pour interagir visuellement avec tes agents
---
## I. Prérequis
- Avoir installé **Cursor** : [https://cursor.so](https://cursor.so/)
- Avoir installé **Ollama** : [[https://ollama.com](https://ollama.com/))
- Avoir Python 3.10+ installé
### Installer un modèle avec Ollama :
```bash
ollama pull codellama:13b-python
ollama pull mistral
```
Teste le bon fonctionnement :
```bash
ollama run mistral
```
---
## II. Intégrer Ollama à Cursor via `cursor-agent.json`
Crée ce fichier à la racine du projet :
```json
{
"name": "LLM Local Agent",
"entry": "main.py",
"llm": {
"provider": "custom",
"completion_url": "http://localhost:11434/api/generate",
"method": "POST",
"headers": { "Content-Type": "application/json" },
"input_key": "prompt",
"output_key": "response"
}
}
```
> Ce fichier connecte Cursor à ton modèle local via API HTTP.
---
## III. Cline dans Cursor : installation, configuration et usage
### Qu'est-ce que **Cline** ?
Cline est la **barre latérale interactive** dans Cursor. Elle te permet de :
- Créer des agents avec rôles personnalisés
- Interagir avec ton code sélectionné ou tout le fichier
- Voir la réponse du modèle directement à droite
- Ajouter des prompts, des messages système ou modifier des paramètres
### Comment lactiver ?
1. Sélectionne du code
2. Tape `//` pour activer un prompt (comme un commentaire)
3. Cline souvre automatiquement à droite
4. Tu peux :
- Choisir ton modèle (`cursor-agent.json` doit être actif)
- Envoyer un prompt
- Lire et copier la réponse
### Pourquoi cest utile ?
Cline est **idéal pour le développement assisté par LLM**, car tu peux :
- Corriger le code sélectionné
- Générer automatiquement du code ou des tests
- Interagir avec différents agents en parallèle
- Comparer les retours selon les rôles
---
## IV. Créer un agent dynamique personnalisé (main.py)
```python
from base_agent import BaseAgent
agent = BaseAgent("CodeExplainer", model="mistral")
agent.set_role("Tu es un assistant Python expert. Tu expliques de manière claire le fonctionnement dun code donné.")
prompt = input("Prompt utilisateur : ")
print(agent.process(prompt))
```
---
## V. Exemple de rôles dagents Cursor
```python
explainer = BaseAgent("Explainer", model="mistral")
optimizer = BaseAgent("Optimizer", model="codellama:13b-python")
refactor = BaseAgent("Refactor", model="codellama:13b-python")
explainer.set_role("Explique ce que fait le code avec précision.")
optimizer.set_role("Optimise ce code Python pour la performance.")
refactor.set_role("Refactore le code pour quil soit plus lisible.")
code = '''
def process(x): return [i*2 for i in x if i > 0]'''
print(explainer.process(code))
```
---
## VI. Support multi-machine : Agents locaux ou distants (serveur)
Tu peux travailler avec un **Ollama local sur ton PC principal** ou utiliser un **serveur distant** qui héberge un modèle (par ex. Mistral 7B déjà actif sur ton site).
### 1. Classe RemoteLLMInterface
```python
import requests
class RemoteLLMInterface:
def __init__(self, model, host="http://192.168.1.150:11434", **params):
self.model = model
self.api_url = f"{host}/api/generate"
self.params = params
def generate(self, prompt):
payload = {"model": self.model, "prompt": prompt, **self.params}
response = requests.post(self.api_url, json=payload)
return response.json().get("response", "")
```
### 2. Créer un agent distant :
```python
from remote_llm_interface import RemoteLLMInterface
class RemoteAgent:
def __init__(self, name, model="mistral", host="http://192.168.1.150:11434", **params):
self.name = name
self.interface = RemoteLLMInterface(model, host, **params)
self.system_prompt = ""
def set_role(self, prompt):
self.system_prompt = prompt.strip()
def process(self, user_input):
full_prompt = f"{self.system_prompt}\n\n{user_input}" if self.system_prompt else user_input
return self.interface.generate(full_prompt)
```
> Tu peux ainsi appeler le modèle Mistral 7B de ton site **depuis Cursor**, sans le réinstaller localement.
---
## VII. Changer dagent facilement (CLI rapide)
```python
from base_agent import BaseAgent
name = input("Nom de lagent : ")
model = input("Modèle Ollama (ex: mistral) : ")
role = input("Quel est le rôle de lagent ? : ")
prompt = input("Quel est le prompt ? : ")
agent = BaseAgent(name=name, model=model)
agent.set_role(role)
print(agent.process(prompt))
```
---
## VIII. Exemples d'agents à utiliser dans Cursor
|Nom Agent|Modèle|Rôle assigné|
|---|---|---|
|`Optimizer`|`codellama:13b-python`|Optimise le code|
|`Explainer`|`mistral`|Explique le code|
|`BugFinder`|`codellama:13b-python`|Trouve des erreurs|
|`DocGen`|`mistral`|Génère des docstrings|
|`Formatter`|`codellama`|Reformate proprement le code|
---
## IX. Bonnes pratiques avec Cursor et Cline
- Utilise `//` pour poser des questions précises à ton agent
- Crée plusieurs agents avec des rôles spécialisés : rapide à réutiliser
- Utilise des raccourcis clavier pour alterner entre agents dans Cline
- Sauvegarde tes rôles les plus utiles dans un fichier JSON ou via script
- Combine les agents dans une chaîne pour effectuer plusieurs actions à la suite
---
## Conclusion
Tu maîtrises maintenant :
- Linstallation dOllama et des modèles
- La configuration de Cursor et lutilisation de `cursor-agent.json`
- Linteraction avancée avec Cline (prompts, agents multiples, feedback instantané)
- La création dagents dynamiques **locaux ou distants**, selon ton architecture
[[LLM Cursor version2]]

View File

@ -0,0 +1,143 @@
# Guide : Intégration et Utilisation des LLM avec Agents Dynamiques dans Obsidian
---
## Objectif du guide
- Installer et configurer les LLM localement avec Ollama
- Intégrer ces modèles dans Obsidian grâce à des agents dynamiques
- Utiliser tes notes comme base de données intelligente
- Créer plusieurs agents spécialisés pour enrichir ton workflow de prise de notes
Le tout en restant simple, modulaire, réutilisable.
---
## I. Prérequis
### 1. Systèmes compatibles
- Windows 10/11 (avec WSL recommandé) ou Linux
### 2. Logiciels à installer
- [Ollama](https://ollama.com/) (pour exécuter les LLM en local)
- Python 3.10+
- Obsidian (avec le plugin "Templater" ou "Custom Plugins" activé)
---
## II. Installer et tester les modèles LLM avec Ollama
### 1. Installation dOllama
```bash
# Linux/WSL
curl -fsSL https://ollama.com/install.sh | sh
# macOS (brew)
brew install ollama
```
### 2. Lancer un modèle (exemple : mistral)
```bash
ollama run mistral
```
Pour télécharger un autre modèle :
```bash
ollama pull codellama:13b-python
```
Liste des modèles : [https://ollama.com/library](https://ollama.com/library)
### 3. Vérification API locale
```bash
curl http://localhost:11434
```
---
## III. Créer des agents dynamiques spécialisés pour Obsidian
### Structure minimale dun agent
```python
from base_agent import BaseAgent
agent = BaseAgent("RestructurationObsidian", model="mistral")
agent.set_role("Tu restructures les notes Markdown pour les rendre lisibles et organisées.")
note = "cette note est en désordre. elle na pas de titres, ni de sections."
print(agent.process(note))
```
### Exemples dagents à créer
|Nom de lagent|Rôle assigné|
|---|---|
|AnalyseurStructure|Analyse la structure de la note|
|CorrecteurMarkdown|Corrige orthographe + mise en page|
|SuggestionTagsLiens|Propose des tags internes et liens|
|OptimiseurObsidian|Propose des améliorations visuelles (CSS/templating)|
|ClasseurNotes|Classe la note dans un dossier pertinent|
### Organisation recommandée dans Obsidian
- Dossier `scripts/agents/`
- Fichier `agents_runner.py` exécutable via script shell ou Templater
```bash
python agents/agents_runner.py "notes/ma_note.md"
```
### Exemple via plugin Templater
Crée un template qui appelle un script :
```markdown
<% tp.system.run('python3 agents/agents_runner.py "' + tp.file.path(true) + '"') %>
```
---
## IV. Exploitation avancée avec AgentChain
Tu peux enchaîner plusieurs agents pour automatiser un traitement complet :
```python
from agent_chain import AgentChain
a1 = BaseAgent("analyse", model="mistral")
a2 = BaseAgent("structure", model="mistral")
a3 = BaseAgent("correction", model="mistral")
a1.set_role("Analyse le contenu de la note.")
a2.set_role("Restructure la note.")
a3.set_role("Corrige lorthographe.")
chain = AgentChain(chain_mode=True)
chain.add(a1)
chain.add(a2)
chain.add(a3)
with open("notes/ma_note.md") as f:
print(chain.run(f.read()))
```
---
## V. Astuces pratiques
- Utilise le tag YAML `#traitement_ai` dans tes notes à traiter automatiquement
- Stocke les retours dagent dans un champ frontmatter YAML ou un fichier à part
- Utilise le modèle `phi` pour les agents rapides, `mistral` pour polyvalence, `codellama` uniquement si tu traites du code Markdown
---
## VI. À suivre
Tu peux combiner cette configuration avec un système de base de données vectorielle RAG plus tard pour lindexation des notes.

View File

@ -0,0 +1,109 @@
---
## 🧠 Configuration BIOS Optimisée - ASUS Z390-E Gaming
### 📌 Objectifs :
- **Stabilité maximale** pour serveur
- **Compatibilité mémoire** avec barrettes différentes
- **Performance CPU équilibrée**
- Quelques **réglages BIOS recommandés** pour un usage serveur
---
## 1. ⚙️ Configuration RAM mixte
### 🎯 Problème :
Tu as :
- 2x8 Go Corsair Vengeance Pro RGB 3600 MHz
- 2x32 Go Crucial Pro 3200 MHz
Les barrettes les plus lentes vont **dicter la fréquence** max fiable. Il faut forcer le BIOS à se caler sur les valeurs stables de la Crucial.
### ✅ Réglages recommandés :
Dans le BIOS (mode avancé) :
```
AI Tweaker > Ai Overclock Tuner : Manual
```
Ensuite :
|Paramètre BIOS|Valeur recommandée|
|---|---|
|DRAM Frequency|DDR4-3200 MHz|
|DRAM Voltage|1.35V (si XMP l'indique, sinon 1.25V)|
|Load XMP Profile|**Désactivé** pour éviter conflit XMP mixte|
|DRAM Timing Control|Laisser en AUTO pour la stabilité|
💡 **Important** : ne pas activer XMP avec des barrettes différentes. Tu risques des crashes, reboots ou des boots instables.
---
## 2. 🔧 Réglage CPU i9-9900K
### 🎯 Objectif : Équilibre performance / stabilité / refroidissement
Le i9-9900K peut chauffer très fort. Pour un serveur, tu nas pas besoin des 5 GHz constants.
### ✅ Réglages recommandés :
```
AI Tweaker > Ai Overclock Tuner : Manual
```
Ensuite :
|Paramètre BIOS|Valeur recommandée|
|---|---|
|CPU Core Ratio|Sync All Cores|
|All Core Ratio Limit|**45x (4.5 GHz)** ou **47x (4.7 GHz)**|
|CPU Core/Cache Voltage|Manual Mode|
|CPU Core Voltage|1.200V (stable pour 4.5 GHz)|
|AVX Offset|2 (ou plus si besoin, réduit la fréquence en charge AVX)|
|Long Duration Package Power Limit|125W (ou 95W si tu veux limiter davantage)|
|Short Duration Power Limit|150W (ou 125W)|
|CPU Load-line Calibration|Level 6 (ou Level 5 pour une meilleure stabilité)|
🎯 Tu peux ajuster plus bas (4.2 ou 4.3 GHz) pour gagner encore en température/stabilité.
---
## 3. 🧬 Paramètres BIOS Serveur recommandés
|Catégorie|Réglage BIOS|Valeur recommandée|
|---|---|---|
|**Boot**|Fast Boot|Disabled|
||Boot Logo|Disabled|
|**Power**|ErP Ready|Enabled (économie énergie)|
||Restore AC Power Loss|Power On (pour reboot auto)|
|**SATA**|Hot Plug (sur tous ports)|Enabled (utile si hot swap HDD)|
|**Advanced > CPU**|Intel SpeedStep|Enabled|
||Intel C-State|Enabled (C3, C6, C7 activés)|
|**Onboard Devices**|WiFi / BT|Enabled/Disabled selon besoin|
|**Monitoring**|Q-Fan Configuration|Silent ou Custom (ventilos discrets)|
|**Security**|TPM (PTT)|Enabled (utile pour Windows Server)|
---
## 🧪 Stress Test après configuration
Après avoir appliqué tout ça :
1. Lance un **MemTest86** depuis clé USB (au moins 1 passe complète)
2. Teste le CPU avec un **stress test comme OCCT** ou **Cinebench R23** en boucle
3. Surveille les températures avec **HWiNFO64**
---
## 📁 À venir (si tu veux aller plus loin)
- Script PowerShell pour surveiller stabilité sous Windows Server
- Création dun profil StreamDeck pour surveiller ressources serveur
- Optimisation réseau (QoS, jumbo frames, etc.)
---

View File

@ -0,0 +1,134 @@
---
## Intégration et Avantages de n8n
### n8n (Automatisation de workflows open-source)
- **Description :** Plateforme visuelle d'automatisation permettant de créer des workflows entre API, fichiers, bases de données et services locaux ou cloud.
- **Licence :** Gratuit en auto-hébergement, version cloud payante si hébergée par n8n.io
- **Utilisations recommandées :**
- Automatiser la synchronisation entre Ragflow, Strapi, fichiers de code, notes Obsidian
- Déclencher des actions : sauvegarde automatique, traitement de données, appel de modèles LLM
- Lier des événements : création dun fichier → ajout dans la base vectorielle
#### 🚀 Installation de n8n (Docker - Serveur ou PC Principal)
```
docker run -it --rm \
-p 5678:5678 \
-v ~/.n8n:/home/node/.n8n \
-e N8N_HOST=localhost \
-e N8N_PORT=5678 \
n8nio/n8n
```
- Accès ensuite à linterface : http://localhost:5678
- Créer un utilisateur, commencer à connecter tes services.
#### ✅ Exemples de workflows utiles
- Fichier ajouté dans `/mnt/d/notes` → envoyer dans Ragflow via HTTP Request
- Webhook Strapi → traitement avec LLM → export JSON/Markdown
- Surveillance dun dossier → déclenchement dun fine-tuning
---
## Intégration et Avantages de MPC
### MCP (Machine Learning Control Panel)
- **Description :** Interface open-source pour gérer et visualiser les modèles LLM, entraînements, datasets.
- **Licence :** Gratuit (open-source), fonctionne via Docker ou installation manuelle.
#### 🔧 Installation MCP (avec Docker)
```
git clone https://github.com/mgoin/MCP.git
cd MCP
sudo docker-compose up --build
```
- Interface Web accessible à : http://localhost:8000 ou via ton IP réseau
#### ✅ Utilisation typique
- Visualisation en temps réel de lactivité de tes modèles (RAM, VRAM, charge CPU)
- Gestion de sessions de fine-tuning via interface graphique
- Déploiement local de modèles LoRA/Ollama
- Intégration avec ChromaDB ou Ragflow pour annotation automatique
#### 💡 Fonctionnalités supplémentaires intéressantes
- Création de profils pour tes différents modèles
- Suivi des performances GPU/CPU (intégration avec `nvitop` ou Prometheus)
- Logs centralisés de toutes les exécutions
---
## Utilisation combinée n8n + MCP
### 🔄 Scénario synergique
- **n8n** automatise les déclenchements (surveillance de dossiers, synchronisation de données, webhooks dObsidian ou Strapi)
- **MCP** exécute les tâches IA correspondantes et fournit un tableau de bord pour suivre chaque étape.
### 🔗 Exemple concret
1. n8n surveille `/mnt/d/notes` sur ton PC principal.
2. Lorsquun nouveau fichier est détecté, il appelle une API FastAPI (ou script Python) qui :
- alimente Ragflow avec le contenu
- déclenche une session de fine-tuning si besoin (via API MCP ou ligne de commande)
3. MCP enregistre lopération, affiche létat de la RAM/VRAM, et permet de suivre l'entraînement.
### 🧠 Avantages de la combinaison
- **Automatisation complète sans intervention manuelle.**
- **Contrôle fin et centralisé de toutes les IA.**
- **Surveillance continue avec logs et retour visuel.**
---
## Tirer le Meilleur Parti de ChatGPT Plus & Cursor Pro
### Avantages de ChatGPT Plus
- **Accès prioritaire et performances optimisées**
- **Complémentarité avec modèles locaux**
### Avantages de Cursor Pro
- **IDE optimisé pour l'IA**
- **Intégration transparente avec modèles locaux et GPT-4**
---

View File

@ -0,0 +1,153 @@
# Infrastructure Optimisée d'IA Locale
---
## PC Principal (Windows 11 Pro)
### Objectifs :
- Intégrer 2 modèles LLM locaux 13B (Obsidian et Cursor).
- Installer Ollama sur Windows (WSL2 recommandé).
- Base de données vectorielle (RAG) pour stocker : notes, code, site web.
- Pipeline via Node.js.
### 1. Installation et gestion Ollama (WSL2 recommandé)
WSL2 est recommandé pour une meilleure performance avec Ollama et l'utilisation directe du GPU Nvidia (RTX 4090).
**Commandes essentielles :**
```bash
# Installer WSL2
wsl --install
# Installer Ubuntu (recommandé)
wsl --install -d Ubuntu
# Installation Ollama sous WSL2
curl -fsSL https://ollama.com/install.sh | sh
# Télécharger et exécuter un modèle LLM
ollama pull mistral
ollama run mistral
# Vérification GPU (Nvidia)
nvidia-smi
```
### 2. Sélection des Modèles LLM
- **Obsidian** : Modèle adapté à l'organisation et à la rédaction (Ex : Mistral 13B).
- **Cursor** : Modèle spécialisé en programmation (Ex : CodeLlama 13B Python).
**Exemples commandes Ollama :**
```bash
ollama pull mistral:13b-instruct
ollama pull codellama:13b-python
```
### 3. Organisation Disque et Installation
**Architecture de stockage recommandée :**
- **Disque principal (Crucial T700 - 2 To)** : Windows 11, logiciels principaux, Ollama, environnement WSL.
- **Disques Crucial P3 (2 x 4 To)** :
- P3 (1) : Modèles LLM et base vectorielle (RAG).
- P3 (2) : Stockage des données (notes, code, contenus divers).
- **SSD MX500 SATA** : Sauvegardes automatiques et fichiers temporaires.
### 4. Base de Données Vectorielle (RAG)
Utilisation de [ChromaDB](https://github.com/chroma-core/chroma) pour la simplicité et la performance avec Node.js pour pipelines.
```bash
# Installation Node.js (Windows / WSL)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Installation ChromaDB
pip install chromadb
```
### 5. Fine-tuning (LoRA)
- Utiliser [QLoRA](https://github.com/artidoro/qlora) pour fine-tuning efficace sur GPU.
```bash
pip install peft
pip install transformers datasets accelerate bitsandbytes
```
### 6. Gestion GPU et IA (Pause/Reprise)
- Facilité par les commandes Ollama.
```bash
ollama stop <modèle>
ollama start <modèle>
```
---
## Serveur Windows Server 2025
### Objectifs :
- Héberger site (Next.js, Strapi).
- Chatbot (FastAPI + Mistral 7B).
- RAG centralisé.
### Architecture
- **Disque NVMe Gen3** : OS, IIS, Next.js, Strapi.
- **SSD 240 Go SATA** : Applications légères, FastAPI.
- **HDD RAID1** : Données site web (images, médias).
- **HDD 8To / 3To** : Sauvegardes, archives.
### Installation et Configuration
- **IIS pour Next.js et Strapi :**
- Hébergement via reverse-proxy IIS vers Node.js.
- **FastAPI et Chatbot :**
```bash
pip install fastapi uvicorn ollama
```
- **Modèle Ollama (Mistral 7B)** :
```bash
ollama pull mistral:7b
```
### Pipeline RAG centralisé
- Synchronisation automatique via scripts Node.js et API ChromaDB.
```bash
npm init -y
npm install axios express
```
---
## Résumé des commandes essentielles :
|Tâche|Commande essentielle|
|---|---|
|Installer WSL2|`wsl --install`|
|Installation Ollama|`curl -fsSL [https://ollama.com/install.sh](https://ollama.com/install.sh)|
|Gestion Ollama (modèles)|`ollama pull <modèle>` / `ollama run <modèle>`|
|Vérifier GPU Nvidia|`nvidia-smi`|
|Installer ChromaDB|`pip install chromadb`|
|Installer FastAPI|`pip install fastapi uvicorn`|
|Installation Node.js|`curl -fsSL [https://deb.nodesource.com/setup_20.x](https://deb.nodesource.com/setup_20.x)|
|Installer QLoRA|`pip install peft transformers datasets accelerate bitsandbytes`|
---
[[Recherche modèles]]
[[Plan d'apprentissage détaillé sur Ollama]]

View File

@ -0,0 +1,75 @@
Voici une réflexion approfondie sur les meilleurs modèles LLM adaptés spécifiquement à tes cas d'utilisation, optimisés pour tes ressources matérielles :
## 📌 Critères de sélection :
- **Performance sur matériel local (RTX 4090)**
- **Spécialisation** (usage généraliste, productivité, programmation)
- **Adaptabilité au fine-tuning (LoRA)**
- **Optimisation GPU (quantification efficace)**
---
## ✅ Recommandations par cas dusage :
### 1. **Productivité (Notes, Obsidian, organisation générale) :**
- **Mistral 13B Instruct**
- 🔹 **Points forts :** polyvalence, rapidité d'inférence, très bon en français.
- 🔹 **Utilisation idéale :** prise de notes, rédaction assistée, organisation de connaissances.
- 🔹 **Quantification recommandée :** `Q4_K_M` via Ollama pour meilleur compromis qualité/performance.
**Commande Ollama :**
```bash
ollama pull mistral:13b-instruct-q4_K_M
```
---
### 2. **Programmation (Cursor, Python, développement général) :**
- **CodeLlama 13B Python**
- 🔹 **Points forts :** spécialisé en code, excellente précision syntaxique, efficace en autocomplétion et génération de scripts.
- 🔹 **Utilisation idéale :** assistance en programmation Python (ou autres langages), debugging, génération automatisée de code.
- 🔹 **Quantification recommandée :** `Q4_K_S` pour un équilibre optimal précision/vitesse sur RTX 4090.
**Commande Ollama :**
```bash
ollama pull codellama:13b-python-q4_K_S
```
---
### 3. **Chatbot web général (hébergement serveur avec FastAPI) :**
- **Mistral 7B Instruct**
- 🔹 **Points forts :** faible latence, consommation GPU modérée, parfait pour interactions rapides en ligne.
- 🔹 **Utilisation idéale :** chatbot réactif intégré à ton site web.
- 🔹 **Quantification recommandée :** `Q4_K_M` très rapide, adapté à ta RTX 2080 Ti sur ton serveur.
**Commande Ollama :**
```bash
ollama pull mistral:7b-instruct-q4_K_M
```
---
## 📚 **Résumé des modèles choisis** :
|Usage|Modèle recommandé|Quantification|GPU idéal|Performance attendue|
|---|---|---|---|---|
|Productivité (Obsidian)|Mistral 13B Instruct|`Q4_K_M`|RTX 4090|✅ Excellente|
|Programmation (Cursor)|CodeLlama 13B Python|`Q4_K_S`|RTX 4090|✅ Très bonne|
|Chatbot Web|Mistral 7B Instruct|`Q4_K_M`|RTX 2080 Ti|✅ Très bonne|
---
Ces modèles offrent une combinaison optimale entre performances, qualité et spécialisation pour tes usages et ton matériel actuel. Ils sont faciles à ajuster via LoRA, répondent à tes exigences actuelles, et sont évolutifs pour tes besoins futurs.

View File

@ -0,0 +1,125 @@
# 🚀 Automatiser le lancement de Strapi, Next.js et FastAPI au démarrage de Windows Server 2025
## 🎯 Objectif
Automatiser le lancement des 3 services suivants au **démarrage du serveur** :
| Service | Dossier | Commande |
|-----------|----------------------------------------|------------------------------------------------------------|
| **Strapi** | `J:\my-next-site\cmsbackend\` | `npm run develop` |
| **Next.js** | `J:\my-next-site\` | `npm run dev` |
| **FastAPI** | `J:\my-next-site\llm-api\` | `uvicorn api:app --host 0.0.0.0 --port 8000` |
## ✅ Stratégie recommandée
Utiliser un **script PowerShell** lancé via le **Planificateur de tâches Windows** :
- Simple à maintenir
- Exécution dans des fenêtres indépendantes
- Redémarrage automatique après un redémarrage
- Pas besoin de créer un service Windows
---
## 🧰 Étape 1 Créer le script PowerShell
### 📄 Script : `start-my-site.ps1`
```powershell
# Lancer Strapi
Start-Process powershell -ArgumentList "cd 'J:\my-next-site\cmsbackend'; npm run develop" -WindowStyle Normal
# Lancer Next.js
Start-Process powershell -ArgumentList "cd 'J:\my-next-site'; npm run dev" -WindowStyle Normal
# Lancer FastAPI
Start-Process powershell -ArgumentList "cd 'J:\my-next-site\llm-api'; uvicorn api:app --host 0.0.0.0 --port 8000" -WindowStyle Normal
```
> 💾 Sauvegarder ce script dans un emplacement fixe (ex. : `J:\my-next-site\start-my-site.ps1`)
---
## 🧰 Étape 2 Créer une tâche planifiée
### 🧭 Ouvrir le planificateur
- `Win + R``taskschd.msc`
### ⚙️ Onglet **Général**
- **Nom** : `Lancer mes services web`
- Coche : `Exécuter avec les autorisations maximales`
- Choisir un **compte administrateur**
### ⚙️ Onglet **Déclencheurs**
- **Nouveau**
- Déclencheur : `Au démarrage`
- Délai (optionnel) : `30 secondes`
- Cocher : `Activé`
### ⚙️ Onglet **Actions**
- **Programme/script** : `powershell.exe`
- **Ajouter des arguments** :
```bash
-ExecutionPolicy Bypass -File "J:\my-next-site\start-my-site.ps1"
```
### ⚙️ Onglet **Conditions**
- Décocher : `Démarrer uniquement si lordinateur est sur secteur`
### ⚙️ Onglet **Paramètres**
- Coche :
- `Autoriser lexécution de la tâche à la demande`
- `Redémarrer en cas déchec`
- `Réessayer toutes les 1 min`
- (optionnel) `Arrêter si la tâche dure trop longtemps`
---
## 🔁 Gestion des plantages
Le planificateur peut relancer automatiquement le script si les options sont activées.
Cependant, pour une meilleure résilience, tu peux envisager :
## ⚡️ Bonus : Utiliser `pm2` pour Node.js
```bash
npm install -g pm2
# Lancer Strapi
cd J:\my-next-site\cmsbackend
pm2 start npm --name strapi -- run develop
# Lancer Next.js
cd J:\my-next-site
pm2 start npm --name next -- run dev
# Sauvegarder et rendre permanent
pm2 save
pm2 startup
```
PM2 permet de :
- Redémarrer automatiquement en cas de crash
- Avoir des logs
- Démarrer avec le système
---
## ✅ Résumé
| Élément | Action |
|--------------|------------------------------------------------------------------------|
| Script PS1 | `start-my-site.ps1` avec `Start-Process` pour chaque service |
| Planificateur| Tâche lancée **au démarrage**, en **admin**, avec **PowerShell** |
| Résilience | Gérée via **planificateur** ou via **PM2** pour Node.js |
---
> ✉️ Besoin : export `.ps1` prêt à lemploi ou `.xml` du planificateur ? Demande-moi !

View File

@ -1,5 +1,5 @@
- [ ] Validation format JSON
- [ ] Pipeline nodes vs FastAPI
- [ ] Validation format JSON
- [ ] Mise en place de scripts
- [ ] argument + script pour execution
- [ ] bibliothèque de scripts bien précis pour la récupération des données
@ -13,4 +13,6 @@
- [ ] langchain, ...
- [ ] besoin fine-tuning?
- [ ] Voir efficacité de guider l'utilisateur pour récupérer les informations plus rapidement
- [ ] Mise en place d'une interface locale? (Gradio ou autre) avec enregistrement des conversations pour tests et ajout des conversations au JSON pour regrouper es données concernant la demande
- [ ] Mise en place d'une interface locale? (Gradio ou autre) avec enregistrement des conversations pour tests et ajout des conversations au JSON pour regrouper es données concernant la demande
[[20 mars réponses Karim]]

View File

@ -0,0 +1,52 @@
base de donnée sur elastic search
Récupérer les tickets avec demandes et solutions
- voir ticket et demandes voir les réponses
- celles clôturés question/réponse possibilité d'injection dans le LLM
- sur le RAG synthétisé la question et synthétiser la réponse (fils de discussion client et support)
- Attention plusieurs questions dans la demande
- traité les images donner une explication au format texte pour l'intégrer dans la synthèse Q/R
- Si quelque chose a été signalé en cours de traitement
- Comment faire une recherche en base de donnée
- Quand on fait fine-tuning lora injecte ce qui est nouveau une fois par mois
- Fine-tuning refaire une synthèse résumé de l'ensemble
- cleaning du data set
- dans le rag pdf
- possibilité de signalé un problème qui est récurrent
- voir retraining si mauvaise réponse
- Dabord en cours
- ticket une fois corrigé pas besoin
- faire un exercice et les donner à un llm grand et lui demander d'extracter le problème et la solution Demander quel est le probleme
- lui demander d'analyser les images
- On compile avec le fil de discussion on peut laisser image avec le texte LLM Vision
- Vision a déjà la partie discussion ça dépend la stratégie
- llama-vision (llava) voir comment il réagit et modifier la réponse pour qu'il comprenne comment cela va fonctionner
- Mieux tout sur llava et voir le résultat
- 3 agents,
- Réajuster les réponses et les réinjecter
- Demander au client de plus décrire les choses
- content rôle du llm 2emequestion 3eme réponse cette option
- agent qui va résumé question, résumé réponse,
- contexte pour chaque type de demande
- Normes dans le RAG knowledgebase
- mode hybride RAG / fine tuning
- Meme LLM qui va avoir différents agents
- Voir les screen des différents datasets
- huggin face
- https://www.kaggle.com/ plus mathématique
- dataset interessants pour le béton reprendre la logique
- voir postgres
configurer vscode avec les agents et et les différents modèles du servuer ollama
documentation ollama
voir Cline()
- voir dans vscode pour lui assigner un rôle comme agent (ex: tu dois convertir du code wlangage en python)
- puis lui demander de convertir tels fichiers à convertir et travailler le prompt
- et continue égalment dans vscode plus assigner à une tâche
documentation ollama API
- voir paramètrage
- voir utilisation précise dans vscode
[Commencer \| DataCamp](https://www.datacamp.com/fr/users/sign_up?redirect=%2Ftracks%2Fai-fundamentals%2Fenroll) grascalvet.fernand@gmail.com Lestat66!
[[Agent]]
[[guide_ollama_complet]]

109
Stage/Agent.md Normal file
View File

@ -0,0 +1,109 @@
#### <u><font color="#92cddc">Paramètres utilisés pour les modèles:</font></u>
| ==**Paramètre**== | ==**Description**== | ==**Valeurs typiques recommandées**== |
| :------------------------ | :--------------------------------------------------------------------------------------------------- | :------------------------------------------- |
| ==**temperature**== | Contrôle la créativité du modèle (variablilité des réponses) | 0.1 (précis) à 1.0+(créatif) |
| ==**top_p**== | (sampling nucleus) Sélectionne des tokens parmi les plus probables jusqu'à atteindre la somme top_p. | 0.9 à 0.99 |
| ==**top_k**== | Sélectionne les tokens parmi les top K les plus probables uniquement. | 40 à 100 |
| ==**num_ctx**== | Longueur maximale du contexte (nombre de tokens) | selon modèle (ex: 4096, 8192, 32000, 128000) |
| ==**repeat_penalty**== | pénalise les répétitions de phrases ou mots déjà utilisés. | 1.0 (désactivé), typiquement 1.1 à 1.3 |
| ==**presence_penalty**== | Pénalise la présence répétée de mots, encourage diversité. | 0.0 à 1.0 |
| ==**frequency_panalty**== | Pénalise les répétitions fréquents de même mots. | 0.0 à 1.0 |
| ==**mirostat**== | Contrôle adaptaif de la perplexité (cohérence/répétition). | 0 (désactivé), & ou 2 (activé) |
| ==**mirostat_tau**== | Ajuste précisément le niveau cible de perplexité(avec mirostat) | typiquement 5.0 à 8.0 |
| ==**mirostat_eta**== | Vitesse d'ajustement adaptatif de mirostat | typiquement 0.1 |
| ==**stop**== | Liste de mots ou tokens qui arrêtent automatiquement la génération. | ex: ["\n", "</s>, ""] |
| ==**num_predict**== | Nombre maximal de tokens générés pour la réponse. | typiquement 128 à 2048+ |
| ==**seed**== | Seed (graine) pour garantir la reproductibilité des réponses. | entier fixe (42 par exemple) |
Exemple d'utilisation de ces paramètres lors de l'initialisation d'un agent:
```python
from base_agent import BaseOllamaAgent
class AdvancedQwenCoderAgent(BaseOllamaAgent):
def __init__(self):
super().__init__(
model_name="hf.co/unsloth/Qwen2.5-Coder-32B-Instruct-128K-GGUF:Q8_0",
options={
- "temperature": 0.2,
"top_p": 0.95,
"top_k": 50,
"repeat_penalty": 1.2,
"frequency_penalty": 0.5,
"presence_penalty": 0.3,
"num_ctx": 128000,
"mirostat": 1,
"mirostat_tau": 5.5,
"mirostat_eta": 0.1,
"num_predict": 1024,
"seed": 42
}
)
```
#### <u><font color="#92cddc">Recherche sur paramètres llama_vision3.2 90b paramétrage optimal:</font></u>
1. <font color="#974806">**Tests sur des Images:**</font>
- **<font color="#76923c">Description d'images:</font>**
- **Objectif:** Evaluer la capacité du modèle à générer des descriptions et détaillées des images fournies. [DOC : Llama 3.2 Overview — NVIDIA NIM for Vision Language Models (VLMs)](https://docs.nvidia.com/nim/vision-language-models/1.2.0/examples/llama3-2/overview.html)
- **Paramètres recommandés :**
- **Température :** 0,7
- *Justification* : Une température modérée favorise la créativité tout en mainteant la cohérence des descriptions.
- **Top-p (nucléus sampling) :** 0,9
- *Justification* : Cettte valeur permet au modèle de considérer un large éventail de mots probables, améliorant ainsi la richesse des descriptions.
- **<font color="#76923c">Questions-Réponses Basées sur des Images :</font>**
- **Objectif :** Tester la capacité du modèle à répondre avec précision à des questions spécifiques concernant le contenu d'une image.
- **Paramètres recommandés :**
- **Température:** 0,5
- *Justification :* Une température plus basse favorise des réponses plus précises et factuelles.
- **Top-p:** 0.8 [DOC : Llama 3.2 Vision Models — NVIDIA NeMo Framework User Guide](https://docs.nvidia.com/nemo-framework/user-guide/latest/vlms/mllama.html)
- *Justification :* Cette valeur réduit la probabilité de réponses incohérents en limitant la sélection aux mots les plus probables.
- **<font color="#76923c">Reconnaissance de Concepts Visuels :</font>**
- **Objectif :** Evaluer la capacité du modèle à identifier et comprendre des objets, scènes ou actions spécifiques dans une image.
- **Paramètres recommandés :**
- **Température** : 0,6
- *Justification :* Un équilibre entre créativité et précision est nécessaire pour cette tâche.
- **Top-p** : 0,85
- *Justification*: Cette valeur assure que le modèle considère les options les plus probables tout en conservant une certaine diversité.
---
2.**<font color="#974806"> Tests sur des Fichiers JSON</font>**
- **<font color="#76923c">Validation de la Structure JSON :</font>**
- **Objectif :** Vérifier la capacité du modèle à identifier des erreurs de structure dans des fichiers JSON.
- **Paramètres recommandés :**
- **Température** : 0,3
- Justification : Une température basse est idéale pour des tâches nécessitant une analyse précise et factuelle.
- **Top-p** : 0,7
- Justification : Cette valeur limite la génération à des options hautement probables, réduisant les risques d'erreurs.
- **<font color="#76923c">Extraction d'informations :</font>**
- **Objectif:** Tester la capacité du modèle à extraire des informations spécifiques à partir de fichiers JSON complexes.
- **Paramètres recommandés:**
- **Température :** 0,4
- *Justification* : Favorise la précision lors de l'extraction d'informations spécifiques.
- **Top-p :** 0,75 [DOC : Llama 3.2 \| Model Cards and Prompt formats](https://www.llama.com/docs/model-cards-and-prompt-formats/llama3_2/)
- *Justification* : Assure que le modèle se concentre sur les informations les plus pertinentes.
- **<font color="#76923c">Transformation de Données :</font>**
- **Objectif :** Evaluer la capacité du modèle à transformer des données JSON d'un format à un autre.
- **Paramètres recommandés:**
- **Température :** 0,5
- *Justification :* Un équilibre entre créativité et précision est nécessaire pour reformater les données correctement.
- **Top-p :** 0,8
- *Justification:* Permet une certaine flexibilité tout en maintenant la cohérence dans la transformation des données.
- **<font color="#76923c">Génération de Fichiers JSON :</font>**
- **Objectif :** Tester la capacité du modèle à générer des structures JSON valides à partir de descriptions textuelles ou de spécifications.
- **Paramètres recommandés :**
- **Température :** 0,6
- *Justification :* Encourage une génération légèrement créative tout en respectant les structures attendues.
- **Top-p :** 0,85
- *Justification :* Assure que le modèle considère les options les plus probables pour maintenir la validité du JSON.
---
3. **<font color="#974806">Considérations Supplémentaires</font>**
- longueur du Contexte : le modèle LLama 3.2 Vision 90B supporte une longueur de contexte allant jusqu'à 128K tokens, ce qui est particulièrement utile pour traiter de longs documents ou des images avec des descriptions détaillées.

View File

@ -0,0 +1,82 @@
# Support
Partie vue avec Fabien et Romuald
## **Partie** **logiciel**
### **BRG**-**Lab**
Ou l'on va retrouver tout ce qui est essais échantillons béton
Différentes normes
#### In situ routier
test routier (calcul moyenne sur portion en fonction de la norme)
Sondages
prélèvement et analyse du sol
contrôle de production
Travail labo et producteurs
analyse béton à chaque étape
### Formulation
Composition du béton en fonction du besoin
norme NF EN 206+A2 CN
## Fonctionnement global du support
BHFSQL base de donnée windev/webdev partie cœur de métier (données client, échantillons etc...)
- documentation sur ce type de base de donnée
- Essayer de récupérer un windev/webdev sur pc perso afin de travailler dessus
- Une base de donnée par client et son nom de domaine
- base de donnée sur serveur mutaliser ou dédier voir doc CBAO pour ramification serveurs et base de donnée
- Accès VPN
**La partie serveur Prestataire Adamentis boulou**
**Egalement partie logiciel gestion du matériel (en laboratoire suivi métrologie matériel)**
- Tel vert page support
Deux type de demandes possibles:
- soit formulaire support avec info utiles qui vont permettre de répondre arrive directement dans Odoo
- ou par mail Odoo récupère le mail si non lu
- Documentation fonctionnement Odoo
- Oddo différentes tâches a effectuer
**fabien ticket support demandes**:
- qualification de la demande
- technique/plus base, dysfonctionnement ou nouvelle fonctionnalités voir si existe sinon voir possibilités et devis si besoin passe en suggestion
- sur le traitement si client non référencé le créer
#### **backoffice**
- erreurs qui remonte des clients va permettre de mieux analyser les erreurs au niveau client
- API qui permet de récupérer les données de production avec leur automate de production
- Récupération composition du béton
- organigramme du travail
- Llm catégorisation de la demande pouvoir la lire le pdf qui s'y rattache essentiellement du webdev voir tuto
- [ ] Dans un premier temps se connecter à l'écosystème
- [x] Mot de passe : Cbao!1998
- [x] se connecter à odoo (odoo.cbao.fr)
- [ ] se connecter au différentes URL logiciel
- [ ] Connexion logiciel BRG-lab (demo.brg-lab.com)
- [ ] Connexion portail.cbao.lan/FR
- [x] création d'un git privé pour les notes obsidian
- [x] adresse: fernand@cbao.fr
- [x] mail ODOO@fernand66
- https://odoo.cbao.fr
- fernand@cbao.fr
- Lestat66!
- [x] Webdev
- FERNAND
- fernand
- ]ke8,9R#qqt7=\rb+)
- [ ] Connexion RAGFLOW
- [ ] comprendre ragflow
- [ ] recuperer espace de travail de laurent
- fernand@cbao.fr
- Lestat66!
- fernand66
- [x] OpenVPN
- FERNAND
- fernand
- adresse: 10.8.1.12
- [ ] Ollama
- [ ] ubuntu
- [ ] 217.182.105.173
- [ ] hl00-380-grall
****
[[Réunion 13 mars]]
[[Notes webdev]]

Some files were not shown because too many files have changed in this diff Show More