chore: inital commit

This commit is contained in:
Jan Meyer
2026-02-27 11:13:09 +01:00
commit ca1f47efc8
32 changed files with 40344 additions and 0 deletions

5
.obsidian/app.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"trashOption": "local",
"vimMode": true,
"alwaysUpdateLinks": true
}

5
.obsidian/appearance.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"theme": "obsidian",
"interfaceFontFamily": "Noto Sans",
"cssTheme": "Tokyo Night"
}

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

@@ -0,0 +1,6 @@
[
"obsidian-minimal-settings",
"obsidian-typst-cli",
"edit-in-neovim",
"obsidian-git"
]

33
.obsidian/core-plugins.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": false,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}

22
.obsidian/graph.json vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"collapse-filter": true,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"collapse-display": true,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": false,
"centerStrength": 0,
"repelStrength": 0,
"linkStrength": 0.500822368421053,
"linkDistance": 30,
"scale": 1,
"close": false
}

View File

@@ -0,0 +1,17 @@
{
"terminal": "wezterm",
"listenOn": "127.0.0.1:2006",
"openNeovimOnLoad": false,
"supportedFileTypes": [
"txt",
"md",
"css",
"js",
"ts",
"tsx",
"jsx",
"json"
],
"pathToBinary": "",
"appname": ""
}

33192
.obsidian/plugins/edit-in-neovim/main.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
{
"id": "edit-in-neovim",
"name": "Edit in Neovim",
"version": "1.4.0",
"minAppVersion": "0.15.0",
"description": "Open a Neovim buffer for the currently open file",
"author": "Theseus",
"authorUrl": "https://github.com/TheseusGrey",
"isDesktopOnly": true
}

View File

@@ -0,0 +1,68 @@
{
"commitMessage": "vault backup: {{date}}",
"autoCommitMessage": "vault backup: {{date}}",
"commitMessageScript": "",
"commitDateFormat": "YYYY-MM-DD HH:mm:ss",
"autoSaveInterval": 0,
"autoPushInterval": 0,
"autoPullInterval": 0,
"autoPullOnBoot": false,
"autoCommitOnlyStaged": false,
"disablePush": false,
"pullBeforePush": true,
"disablePopups": false,
"showErrorNotices": true,
"disablePopupsForNoChanges": false,
"listChangedFilesInMessageBody": false,
"showStatusBar": true,
"updateSubmodules": false,
"syncMethod": "merge",
"mergeStrategy": "none",
"customMessageOnAutoBackup": false,
"autoBackupAfterFileChange": false,
"treeStructure": false,
"refreshSourceControl": true,
"basePath": "",
"differentIntervalCommitAndPush": false,
"changedFilesInStatusBar": false,
"showedMobileNotice": true,
"refreshSourceControlTimer": 7000,
"showBranchStatusBar": true,
"setLastSaveToLastCommit": false,
"submoduleRecurseCheckout": false,
"gitDir": "",
"showFileMenu": true,
"authorInHistoryView": "full",
"dateInHistoryView": true,
"diffStyle": "split",
"hunks": {
"showSigns": false,
"hunkCommands": false,
"statusBar": "disabled"
},
"lineAuthor": {
"show": false,
"followMovement": "inactive",
"authorDisplay": "initials",
"showCommitHash": false,
"dateTimeFormatOptions": "date",
"dateTimeFormatCustomString": "YYYY-MM-DD HH:mm",
"dateTimeTimezone": "viewer-local",
"coloringMaxAge": "1y",
"colorNew": {
"r": 255,
"g": 150,
"b": 150
},
"colorOld": {
"r": 120,
"g": 160,
"b": 255
},
"textColorCss": "var(--text-muted)",
"ignoreWhitespace": false,
"gutterSpacingFallbackLength": 5,
"lastShownAuthorDisplay": "initials",
"lastShownDateTimeFormatOptions": "date"
}
}

452
.obsidian/plugins/obsidian-git/main.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
{
"author": "Vinzent",
"authorUrl": "https://github.com/Vinzent03",
"id": "obsidian-git",
"name": "Git",
"description": "Integrate Git version control with automatic backup and other advanced features.",
"isDesktopOnly": false,
"fundingUrl": "https://ko-fi.com/vinzent",
"version": "2.37.1"
}

View File

@@ -0,0 +1,705 @@
@keyframes loading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.git-signs-gutter {
.cm-gutterElement {
/* Needed to align the sign properly for different line heigts. Such as
* when having a heading or list item.
*/
padding-top: 0 !important;
}
}
.workspace-leaf-content[data-type="git-view"] .button-border {
border: 2px solid var(--interactive-accent);
border-radius: var(--radius-s);
}
.workspace-leaf-content[data-type="git-view"] .view-content {
padding-left: 0;
padding-top: 0;
padding-right: 0;
}
.workspace-leaf-content[data-type="git-history-view"] .view-content {
padding-left: 0;
padding-top: 0;
padding-right: 0;
}
.loading {
overflow: hidden;
}
.loading > svg {
animation: 2s linear infinite loading;
transform-origin: 50% 50%;
display: inline-block;
}
.obsidian-git-center {
margin: auto;
text-align: center;
width: 50%;
}
.obsidian-git-textarea {
display: block;
margin-left: auto;
margin-right: auto;
}
.obsidian-git-disabled {
opacity: 0.5;
}
.obsidian-git-center-button {
display: block;
margin: 20px auto;
}
.tooltip.mod-left {
overflow-wrap: break-word;
}
.tooltip.mod-right {
overflow-wrap: break-word;
}
/* Limits the scrollbar to the view body */
.git-view {
display: flex;
flex-direction: column;
position: relative;
height: 100%;
}
.git-tools {
display: flex;
margin-left: auto;
}
.git-tools .type {
padding-left: var(--size-2-1);
display: flex;
align-items: center;
justify-content: center;
width: 11px;
}
.git-tools .type[data-type="M"] {
color: orange;
}
.git-tools .type[data-type="D"] {
color: red;
}
.git-tools .buttons {
display: flex;
}
.git-tools .buttons > * {
padding: 0 0;
height: auto;
}
.workspace-leaf-content[data-type="git-view"] .tree-item-self,
.workspace-leaf-content[data-type="git-history-view"] .tree-item-self {
align-items: center;
}
.workspace-leaf-content[data-type="git-view"]
.tree-item-self:hover
.clickable-icon,
.workspace-leaf-content[data-type="git-history-view"]
.tree-item-self:hover
.clickable-icon {
color: var(--icon-color-hover);
}
/* Highlight an item as active if it's diff is currently opened */
.is-active .git-tools .buttons > * {
color: var(--nav-item-color-active);
}
.git-author {
color: var(--text-accent);
}
.git-date {
color: var(--text-accent);
}
.git-ref {
color: var(--text-accent);
}
/* ====== diff2html ======
The following styles are adapted from the obsidian-version-history plugin by
@kometenstaub https://github.com/kometenstaub/obsidian-version-history-diff/blob/main/src/styles.scss
which itself is adapted from the diff2html library with the following original license:
https://github.com/rtfpessoa/diff2html/blob/master/LICENSE.md
Copyright 2014-2016 Rodrigo Fernandes https://rtfpessoa.github.io/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
.theme-dark,
.theme-light {
--git-delete-bg: #ff475040;
--git-delete-hl: #96050a75;
--git-insert-bg: #68d36840;
--git-insert-hl: #23c02350;
--git-change-bg: #ffd55840;
--git-selected: #3572b0;
--git-delete: #c33;
--git-insert: #399839;
--git-change: #d0b44c;
--git-move: #3572b0;
}
.git-diff {
.d2h-d-none {
display: none;
}
.d2h-wrapper {
text-align: left;
border-radius: 0.25em;
overflow: auto;
}
.d2h-file-header.d2h-file-header {
background-color: var(--background-secondary);
border-bottom: 1px solid var(--background-modifier-border);
font-family:
Source Sans Pro,
Helvetica Neue,
Helvetica,
Arial,
sans-serif;
height: 35px;
padding: 5px 10px;
}
.d2h-file-header,
.d2h-file-stats {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.d2h-file-header {
display: none;
}
.d2h-file-stats {
font-size: 14px;
margin-left: auto;
}
.d2h-lines-added {
border: 1px solid var(--color-green);
border-radius: 5px 0 0 5px;
color: var(--color-green);
padding: 2px;
text-align: right;
vertical-align: middle;
}
.d2h-lines-deleted {
border: 1px solid var(--color-red);
border-radius: 0 5px 5px 0;
color: var(--color-red);
margin-left: 1px;
padding: 2px;
text-align: left;
vertical-align: middle;
}
.d2h-file-name-wrapper {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-size: 15px;
width: 100%;
}
.d2h-file-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text-normal);
font-size: var(--h5-size);
}
.d2h-file-wrapper {
border: 1px solid var(--background-secondary-alt);
border-radius: 3px;
margin-bottom: 1em;
max-height: 100%;
}
.d2h-file-collapse {
-webkit-box-pack: end;
-ms-flex-pack: end;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
border: 1px solid var(--background-secondary-alt);
border-radius: 3px;
cursor: pointer;
display: none;
font-size: 12px;
justify-content: flex-end;
padding: 4px 8px;
}
.d2h-file-collapse.d2h-selected {
background-color: var(--git-selected);
}
.d2h-file-collapse-input {
margin: 0 4px 0 0;
}
.d2h-diff-table {
border-collapse: collapse;
font-family: var(--font-monospace);
font-size: var(--code-size);
width: 100%;
}
.d2h-files-diff {
width: 100%;
}
.d2h-file-diff {
/*
overflow-y: scroll;
*/
border-radius: 5px;
font-size: var(--font-text-size);
line-height: var(--line-height-normal);
}
.d2h-file-side-diff {
display: inline-block;
margin-bottom: -8px;
margin-right: -4px;
overflow-x: scroll;
overflow-y: hidden;
width: 50%;
}
.d2h-code-line {
padding-left: 6em;
padding-right: 1.5em;
}
.d2h-code-line,
.d2h-code-side-line {
display: inline-block;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
width: 100%;
}
.d2h-code-side-line {
/* needed to be changed */
padding-left: 0.5em;
padding-right: 0.5em;
}
.d2h-code-line-ctn {
word-wrap: normal;
background: none;
display: inline-block;
padding: 0;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
vertical-align: middle;
width: 100%;
/* only works for line-by-line */
white-space: pre-wrap;
}
.d2h-code-line del,
.d2h-code-side-line del {
background-color: var(--git-delete-hl);
color: var(--text-normal);
}
.d2h-code-line del,
.d2h-code-line ins,
.d2h-code-side-line del,
.d2h-code-side-line ins {
border-radius: 0.2em;
display: inline-block;
margin-top: -1px;
text-decoration: none;
vertical-align: middle;
}
.d2h-code-line ins,
.d2h-code-side-line ins {
background-color: var(--git-insert-hl);
text-align: left;
}
.d2h-code-line-prefix {
word-wrap: normal;
background: none;
display: inline;
padding: 0;
white-space: pre;
}
.line-num1 {
float: left;
}
.line-num1,
.line-num2 {
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
/*
padding: 0 0.5em;
*/
text-overflow: ellipsis;
width: 2.5em;
padding-left: 0;
}
.line-num2 {
float: right;
}
.d2h-code-linenumber {
background-color: var(--background-primary);
border: solid var(--background-modifier-border);
border-width: 0 1px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: var(--text-faint);
cursor: pointer;
display: inline-block;
position: absolute;
text-align: right;
width: 5.5em;
}
.d2h-code-linenumber:after {
content: "\200b";
}
.d2h-code-side-linenumber {
background-color: var(--background-primary);
border: solid var(--background-modifier-border);
border-width: 0 1px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: var(--text-faint);
cursor: pointer;
overflow: hidden;
padding: 0 0.5em;
text-align: right;
text-overflow: ellipsis;
width: 4em;
/* needed to be changed */
display: table-cell;
position: relative;
}
.d2h-code-side-linenumber:after {
content: "\200b";
}
.d2h-code-side-emptyplaceholder,
.d2h-emptyplaceholder {
background-color: var(--background-primary);
border-color: var(--background-modifier-border);
}
.d2h-code-line-prefix,
.d2h-code-linenumber,
.d2h-code-side-linenumber,
.d2h-emptyplaceholder {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.d2h-code-linenumber,
.d2h-code-side-linenumber {
direction: rtl;
}
.d2h-del {
background-color: var(--git-delete-bg);
border-color: var(--git-delete-hl);
}
.d2h-ins {
background-color: var(--git-insert-bg);
border-color: var(--git-insert-hl);
}
.d2h-info {
background-color: var(--background-primary);
border-color: var(--background-modifier-border);
color: var(--text-faint);
}
.d2h-del,
.d2h-ins,
.d2h-file-diff .d2h-change {
color: var(--text-normal);
}
.d2h-file-diff .d2h-del.d2h-change {
background-color: var(--git-change-bg);
}
.d2h-file-diff .d2h-ins.d2h-change {
background-color: var(--git-insert-bg);
}
.d2h-file-list-wrapper {
a {
text-decoration: none;
cursor: default;
-webkit-user-drag: none;
}
svg {
display: none;
}
}
.d2h-file-list-header {
text-align: left;
}
.d2h-file-list-title {
display: none;
}
.d2h-file-list-line {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
text-align: left;
}
.d2h-file-list {
}
.d2h-file-list > li {
border-bottom: 1px solid var(--background-modifier-border);
margin: 0;
padding: 5px 10px;
}
.d2h-file-list > li:last-child {
border-bottom: none;
}
.d2h-file-switch {
cursor: pointer;
display: none;
font-size: 10px;
}
.d2h-icon {
fill: currentColor;
margin-right: 10px;
vertical-align: middle;
}
.d2h-deleted {
color: var(--git-delete);
}
.d2h-added {
color: var(--git-insert);
}
.d2h-changed {
color: var(--git-change);
}
.d2h-moved {
color: var(--git-move);
}
.d2h-tag {
background-color: var(--background-secondary);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-size: 10px;
margin-left: 5px;
padding: 0 2px;
}
.d2h-deleted-tag {
border: 1px solid var(--git-delete);
}
.d2h-added-tag {
border: 1px solid var(--git-insert);
}
.d2h-changed-tag {
border: 1px solid var(--git-change);
}
.d2h-moved-tag {
border: 1px solid var(--git-move);
}
/* needed for line-by-line*/
.d2h-diff-tbody {
position: relative;
}
}
/* ====================== Line Authoring Information ====================== */
.cm-gutterElement.obs-git-blame-gutter {
/* Add background color to spacing inbetween and around the gutter for better aesthetics */
border-width: 0px 2px 0.2px 2px;
border-style: solid;
border-color: var(--background-secondary);
background-color: var(--background-secondary);
}
.cm-gutterElement.obs-git-blame-gutter > div,
.line-author-settings-preview {
/* delegate text color to settings */
color: var(--obs-git-gutter-text);
font-family: monospace;
height: 100%; /* ensure, that age-based background color occupies entire parent */
text-align: right;
padding: 0px 6px 0px 6px;
white-space: pre; /* Keep spaces and do not collapse them. */
}
@media (max-width: 800px) {
/* hide git blame gutter not to superpose text */
.cm-gutterElement.obs-git-blame-gutter {
display: none;
}
}
.git-unified-diff-view,
.git-split-diff-view .cm-deletedLine .cm-changedText {
background-color: #ee443330;
}
.git-unified-diff-view,
.git-split-diff-view .cm-insertedLine .cm-changedText {
background-color: #22bb2230;
}
.git-obscure-prompt[git-is-obscured="true"] #git-show-password:after {
-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-eye"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"></path><circle cx="12" cy="12" r="3"></circle></svg>');
}
.git-obscure-prompt[git-is-obscured="false"] #git-show-password:after {
-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-eye-off"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"></path><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"></path><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"></path><path d="m2 2 20 20"></path></svg>');
}
/* Override styling of Codemirror merge view "collapsed lines" indicator */
.git-split-diff-view .ͼ2 .cm-collapsedLines {
background: var(--interactive-normal);
border-radius: var(--radius-m);
color: var(--text-accent);
font-size: var(--font-small);
padding: var(--size-4-1) var(--size-4-1);
}
.git-split-diff-view .ͼ2 .cm-collapsedLines:hover {
background: var(--interactive-hover);
color: var(--text-accent-hover);
}
.git-signs-gutter {
.cm-gutterElement {
display: grid;
}
}
.git-gutter-marker:hover {
border-radius: 2px;
}
.git-gutter-marker.git-add {
background-color: var(--color-green);
justify-self: center;
height: inherit;
width: 0.2rem;
}
.git-gutter-marker.git-change {
background-color: var(--color-yellow);
justify-self: center;
height: inherit;
width: 0.2rem;
}
.git-gutter-marker.git-changedelete {
color: var(--color-yellow);
font-weight: var(--font-bold);
font-size: 1rem;
justify-self: center;
height: inherit;
}
.git-gutter-marker.git-delete {
background-color: var(--color-red);
height: 0.2rem;
width: 0.8rem;
align-self: end;
}
.git-gutter-marker.git-topdelete {
background-color: var(--color-red);
height: 0.2rem;
width: 0.8rem;
align-self: start;
}
div:hover > .git-gutter-marker.git-change {
width: 0.6rem;
}
div:hover > .git-gutter-marker.git-add {
width: 0.6rem;
}
div:hover > .git-gutter-marker.git-delete {
height: 0.6rem;
}
div:hover > .git-gutter-marker.git-topdelete {
height: 0.6rem;
}
div:hover > .git-gutter-marker.git-changedelete {
font-weight: var(--font-bold);
}
.git-gutter-marker.staged {
opacity: 0.5;
}
.git-diff {
.cm-merge-revert {
width: 4em;
}
/* Ensure that merge revert markers are positioned correctly */
.cm-merge-revert > * {
position: absolute;
background-color: var(--background-secondary);
display: flex;
}
}
/* Prevent shifting of the editor when git signs gutter is the only gutter present */
.cm-gutters.cm-gutters-before:has(> .git-signs-gutter:only-child) {
margin-inline-end: 0;
.git-signs-gutter {
margin-inline-start: -1rem;
}
}
.git-changes-status-bar-colored {
.git-add {
color: var(--color-green);
}
.git-change {
color: var(--color-yellow);
}
.git-delete {
color: var(--color-red);
}
}
.git-changes-status-bar .git-add {
margin-right: 0.3em;
}
.git-changes-status-bar .git-change {
margin-right: 0.3em;
}

View File

@@ -0,0 +1,34 @@
{
"lightStyle": "minimal-light",
"darkStyle": "minimal-dark",
"lightScheme": "minimal-default-light",
"darkScheme": "minimal-flexoki-dark",
"editorFont": "",
"lineHeight": 1.5,
"lineWidth": 40,
"lineWidthWide": 50,
"maxWidth": 88,
"textNormal": 16,
"textSmall": 13,
"imgGrid": false,
"imgWidth": "img-default-width",
"tableWidth": "table-default-width",
"iframeWidth": "iframe-default-width",
"mapWidth": "map-default-width",
"chartWidth": "chart-default-width",
"colorfulHeadings": false,
"colorfulFrame": false,
"colorfulActiveStates": false,
"trimNames": true,
"labeledNav": false,
"fullWidthMedia": true,
"bordersToggle": true,
"minimalStatus": true,
"focusMode": false,
"underlineInternal": true,
"underlineExternal": true,
"folding": true,
"lineNumbers": false,
"readableLineLength": true,
"devBlockWidth": false
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
{
"id": "obsidian-minimal-settings",
"name": "Minimal Theme Settings",
"version": "8.1.1",
"minAppVersion": "1.1.9",
"description": "Change the colors, fonts and features of Minimal Theme.",
"author": "@kepano",
"authorUrl": "https://www.twitter.com/kepano",
"fundingUrl": "https://www.buymeacoffee.com/kepano",
"isDesktopOnly": false
}

View File

@@ -0,0 +1,11 @@
{
"typstPath": "typst",
"enableInlineMath": true,
"enableDisplayMath": true,
"debugMode": false,
"showDetailedErrors": true,
"useWatchMode": false,
"enableLivePreview": false,
"forceSyncCompile": true,
"syncOnlyDuringExport": true
}

View File

@@ -0,0 +1,805 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// main.ts
var main_exports = {};
__export(main_exports, {
default: () => TypstMathPlugin
});
module.exports = __toCommonJS(main_exports);
var import_child_process = require("child_process");
var import_fs = require("fs");
var import_obsidian = require("obsidian");
var os = __toESM(require("os"));
var path = __toESM(require("path"));
var DEFAULT_SETTINGS = {
typstPath: "typst",
enableInlineMath: true,
enableDisplayMath: true,
debugMode: false,
showDetailedErrors: false,
useWatchMode: false,
enableLivePreview: true,
forceSyncCompile: false,
syncOnlyDuringExport: true
};
var TypstMathPlugin = class extends import_obsidian.Plugin {
constructor() {
super(...arguments);
// Internal flag set when a print/export flow is active
this.exportInProgress = false;
// Hold original window.print so we can restore it on unload
this._originalWindowPrint = null;
// Keep reference to matchMedia listener so we can remove it
this._printMediaListener = null;
this.watchers = /* @__PURE__ */ new Map();
// Store typst source content for blocks that are pending compilation
this.pendingTypstContent = /* @__PURE__ */ new Map();
this.renderCache = /* @__PURE__ */ new Map();
this.handleBeforePrint = () => {
this.exportInProgress = true;
if (this.settings.debugMode)
console.log("Typst plugin: export/print started");
};
this.handleAfterPrint = () => {
this.exportInProgress = false;
if (this.settings.debugMode)
console.log("Typst plugin: export/print finished");
};
}
async onload() {
var _a;
await this.loadSettings();
this.tempDir = path.join(os.tmpdir(), "obsidian-typst-math");
await this.ensureTempDir();
this.registerMarkdownCodeBlockProcessor(
"math",
this.processMathBlock.bind(this)
);
this.registerMarkdownCodeBlockProcessor(
"typst",
this.processMathBlock.bind(this)
);
await (0, import_obsidian.loadMathJax)();
if (!globalThis.MathJax) {
new import_obsidian.Notice("MathJax failed to load. Math rendering may not work.");
console.error("MathJax failed to load.");
} else {
this.originalTex2chtml = globalThis.MathJax.tex2chtml;
globalThis.MathJax.tex2chtml = (latex, options) => {
return this.renderWithTypst(latex, options);
};
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian.MarkdownView);
if (activeView) {
(_a = activeView.previewMode) == null ? void 0 : _a.rerender(true);
if (this.settings.enableLivePreview) {
const editor = activeView.editor;
if (editor) {
const cursor = editor.getCursor();
editor.setCursor(cursor);
}
}
}
}
if (typeof window !== "undefined") {
window.addEventListener("beforeprint", this.handleBeforePrint);
window.addEventListener("afterprint", this.handleAfterPrint);
try {
if (typeof window.print === "function") {
this._originalWindowPrint = window.print.bind(window);
window.print = (...args) => {
this.handleBeforePrint();
try {
const res = this._originalWindowPrint(...args);
setTimeout(() => this.handleAfterPrint(), 1500);
return res;
} catch (e) {
this.handleAfterPrint();
throw e;
}
};
}
} catch (e) {
if (this.settings.debugMode)
console.warn("Failed to patch window.print", e);
}
try {
const mql = window.matchMedia && window.matchMedia("print");
if (mql) {
this._printMediaListener = (ev) => {
if (ev.matches)
this.handleBeforePrint();
else
this.handleAfterPrint();
};
if (typeof mql.addEventListener === "function") {
mql.addEventListener("change", this._printMediaListener);
} else if (typeof mql.addListener === "function") {
mql.addListener(this._printMediaListener);
}
}
} catch (e) {
if (this.settings.debugMode)
console.warn("Failed to attach matchMedia print listener", e);
}
}
this.addSettingTab(new TypstMathSettingTab(this.app, this));
this.addCommand({
id: "typst-prepare-export",
name: "Typst: Prepare export (sync compile all math)",
callback: () => {
void this.prepareExport();
}
});
console.log("Typst Math Plugin loaded");
}
async onunload() {
var _a;
if (this.originalTex2chtml && globalThis.MathJax) {
globalThis.MathJax.tex2chtml = this.originalTex2chtml;
(_a = this.app.workspace.getActiveViewOfType(import_obsidian.MarkdownView)) == null ? void 0 : _a.previewMode.rerender(true);
}
for (const [id, process] of this.watchers) {
process.kill();
}
this.watchers.clear();
try {
await import_fs.promises.rm(this.tempDir, { recursive: true, force: true });
} catch (error) {
console.error("Error cleaning up temp directory:", error);
}
try {
if (typeof window !== "undefined") {
window.removeEventListener("beforeprint", this.handleBeforePrint);
window.removeEventListener("afterprint", this.handleAfterPrint);
if (this._printMediaListener && window.matchMedia) {
const mql = window.matchMedia("print");
if (mql) {
if (typeof mql.removeEventListener === "function") {
mql.removeEventListener("change", this._printMediaListener);
} else if (typeof mql.removeListener === "function") {
mql.removeListener(this._printMediaListener);
}
}
}
if (this._originalWindowPrint) {
try {
window.print = this._originalWindowPrint;
} catch (e) {
}
}
}
} catch (e) {
if (this.settings.debugMode)
console.warn("Error restoring print handlers", e);
}
console.log("Typst Math Plugin unloaded");
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
async ensureTempDir() {
try {
await import_fs.promises.mkdir(this.tempDir, { recursive: true });
} catch (error) {
console.error("Error creating temp directory:", error);
}
}
formatError(error, isInline = false) {
const errorMsg = typeof error === "string" ? error : error.message;
let friendlyMsg = "There was an error with your Typst code";
if (errorMsg.includes("ENOENT") || errorMsg.includes("not found")) {
friendlyMsg = "Typst CLI not found";
} else if (errorMsg.includes("syntax error") || errorMsg.includes("unexpected")) {
friendlyMsg = "Syntax error in Typst code";
} else if (errorMsg.includes("undefined")) {
friendlyMsg = "Undefined symbol or function";
} else if (errorMsg.includes("type")) {
friendlyMsg = "Type error in expression";
}
const errorClass = isInline ? "typst-error-inline" : "typst-error";
if (this.settings.showDetailedErrors) {
return `<span class="${errorClass}">${friendlyMsg}</span><span class="typst-error-details">${errorMsg}</span>`;
} else {
return `<span class="${errorClass}">${friendlyMsg}</span>`;
}
}
async processMathBlock(source, el, ctx) {
const blockId = this.generateBlockId(source, ctx.sourcePath);
if (this.renderCache.has(blockId)) {
el.empty();
const container2 = el.createDiv({ cls: "typst-math-container" });
const cached = this.renderCache.get(blockId);
container2.innerHTML = cached != null ? cached : "";
return;
}
el.empty();
const container = el.createDiv({ cls: "typst-math-container" });
container.innerHTML = '<div class="typst-loading">Rendering with Typst...</div>';
container.setAttribute("data-typst-blockid", blockId);
try {
const typstContent = this.wrapInTypstDocument(source);
const typstFile = path.join(this.tempDir, `${blockId}.typ`);
const htmlFile = path.join(this.tempDir, `${blockId}.html`);
this.pendingTypstContent.set(blockId, typstContent);
await import_fs.promises.writeFile(typstFile, typstContent, "utf-8");
if (this.settings.useWatchMode) {
await this.renderTypstWithWatch(typstFile, htmlFile, container, blockId);
} else {
await this.renderTypstToHtml(typstFile, htmlFile, container, blockId);
}
} catch (error) {
container.innerHTML = this.formatError(error, false);
if (this.settings.debugMode) {
console.error("Typst rendering error:", error);
}
}
}
renderWithTypst(latex, options) {
const isBlock = options.display || false;
if (isBlock && !this.settings.enableDisplayMath) {
return this.originalTex2chtml(latex, options);
}
if (!isBlock && !this.settings.enableInlineMath) {
return this.originalTex2chtml(latex, options);
}
if (this.hasLatexCommand(latex)) {
}
const typstContent = this.convertLatexToTypst(latex);
const blockId = this.generateBlockId(typstContent, `math-${Date.now()}`);
const container = document.createElement(isBlock ? "div" : "span");
container.className = isBlock ? "typst-math-container" : "typst-math-inline";
container.innerHTML = '<span class="typst-loading">Rendering with Typst...</span>';
try {
container.setAttribute("data-typst-blockid", blockId);
this.pendingTypstContent.set(blockId, typstContent);
} catch (e) {
}
this.renderTypstMath(typstContent, container, blockId, isBlock);
return container;
}
hasLatexCommand(expr) {
return false;
}
convertLatexToTypst(latex) {
let content = latex.trim();
content = content.replace(/^\$\$/, "").replace(/\$\$$/, "");
content = content.replace(/^\$/, "").replace(/\$$/, "");
const conversions = [
// Fractions
[/\\frac\{([^}]+)\}\{([^}]+)\}/g, "($1)/($2)"],
// Superscripts and subscripts (already mostly compatible)
// Greek letters (mostly the same, just remove backslash)
[/\\alpha\b/g, "alpha"],
[/\\beta\b/g, "beta"],
[/\\gamma\b/g, "gamma"],
[/\\delta\b/g, "delta"],
[/\\epsilon\b/g, "epsilon"],
[/\\zeta\b/g, "zeta"],
[/\\eta\b/g, "eta"],
[/\\theta\b/g, "theta"],
[/\\iota\b/g, "iota"],
[/\\kappa\b/g, "kappa"],
[/\\lambda\b/g, "lambda"],
[/\\mu\b/g, "mu"],
[/\\nu\b/g, "nu"],
[/\\xi\b/g, "xi"],
[/\\pi\b/g, "pi"],
[/\\rho\b/g, "rho"],
[/\\sigma\b/g, "sigma"],
[/\\tau\b/g, "tau"],
[/\\phi\b/g, "phi"],
[/\\chi\b/g, "chi"],
[/\\psi\b/g, "psi"],
[/\\omega\b/g, "omega"],
// Capital Greek
[/\\Gamma\b/g, "Gamma"],
[/\\Delta\b/g, "Delta"],
[/\\Theta\b/g, "Theta"],
[/\\Lambda\b/g, "Lambda"],
[/\\Xi\b/g, "Xi"],
[/\\Pi\b/g, "Pi"],
[/\\Sigma\b/g, "Sigma"],
[/\\Phi\b/g, "Phi"],
[/\\Psi\b/g, "Psi"],
[/\\Omega\b/g, "Omega"],
// Common functions
[/\\sin\b/g, "sin"],
[/\\cos\b/g, "cos"],
[/\\tan\b/g, "tan"],
[/\\log\b/g, "log"],
[/\\ln\b/g, "ln"],
[/\\exp\b/g, "exp"],
// Sums and integrals
[/\\sum/g, "sum"],
[/\\prod/g, "product"],
[/\\int/g, "integral"],
[/\\infty\b/g, "oo"],
// Arrows
[/\\rightarrow\b/g, "->"],
[/\\leftarrow\b/g, "<-"],
[/\\Rightarrow\b/g, "=>"],
[/\\Leftarrow\b/g, "<="],
// Operators
[/\\times\b/g, "times"],
[/\\cdot\b/g, "dot"],
[/\\pm\b/g, "plus.minus"],
[/\\mp\b/g, "minus.plus"],
// Special sets
[/\\mathbb\{R\}/g, "RR"],
[/\\mathbb\{N\}/g, "NN"],
[/\\mathbb\{Z\}/g, "ZZ"],
[/\\mathbb\{Q\}/g, "QQ"],
[/\\mathbb\{C\}/g, "CC"],
// Limits
[/\\lim/g, "lim"],
[/\\to\b/g, "->"],
// Parentheses (mostly the same)
[/\\left\(/g, "("],
[/\\right\)/g, ")"],
[/\\left\[/g, "["],
[/\\right\]/g, "]"],
[/\\left\{/g, "{"],
[/\\right\}/g, "}"],
// Sqrt
[/\\sqrt\{([^}]+)\}/g, "sqrt($1)"],
// Text
[/\\text\{([^}]+)\}/g, '"$1"']
];
for (const [pattern, replacement] of conversions) {
content = content.replace(pattern, replacement);
}
return content.trim();
}
async renderTypstMath(mathContent, container, blockId, isBlock) {
if (this.renderCache.has(blockId)) {
container.innerHTML = this.renderCache.get(blockId);
return;
}
try {
const wrappedContent = `$ ${mathContent} $`;
const typstContent = this.wrapInTypstDocument(wrappedContent, isBlock);
const typstFile = path.join(this.tempDir, `${blockId}.typ`);
const htmlFile = path.join(this.tempDir, `${blockId}.html`);
this.pendingTypstContent.set(blockId, typstContent);
await import_fs.promises.writeFile(typstFile, typstContent, "utf-8");
await this.renderTypstToHtml(typstFile, htmlFile, container, blockId);
} catch (error) {
container.innerHTML = this.formatError(error, true);
if (this.settings.debugMode) {
console.error("Typst rendering error:", error);
}
}
}
// Synchronously compile a single block (used by prepareExport)
async syncCompileBlock(blockId) {
try {
const typstContent = this.pendingTypstContent.get(blockId);
if (!typstContent)
return;
const typstFile = path.join(this.tempDir, `${blockId}.typ`);
const htmlFile = path.join(this.tempDir, `${blockId}.html`);
(0, import_fs.writeFileSync)(typstFile, typstContent, "utf-8");
const args = [
"compile",
typstFile,
htmlFile,
"--features",
"html",
"--format",
"html"
];
if (this.settings.debugMode) {
console.log("Typst sync compile (prepareExport):", this.settings.typstPath, args.join(" "));
}
const res = (0, import_child_process.spawnSync)(this.settings.typstPath, args, { encoding: "utf-8" });
if (res.error || res.status !== 0) {
const errStr = res.stderr || res.error && res.error.message || `Typst exited ${res.status}`;
throw new Error(errStr);
}
const html = (0, import_fs.readFileSync)(htmlFile, "utf-8");
const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
const content = bodyMatch ? bodyMatch[1] : html;
this.renderCache.set(blockId, content);
try {
const el = document.querySelector(`[data-typst-blockid="${blockId}"]`);
if (el instanceof HTMLElement)
el.innerHTML = content;
} catch (e) {
}
} catch (error) {
if (this.settings.debugMode)
console.error("Error in syncCompileBlock:", error);
throw error;
}
}
// Prepare the document for export by sync-compiling all pending Typst blocks
async prepareExport() {
const pending = Array.from(this.pendingTypstContent.keys());
if (pending.length === 0) {
new import_obsidian.Notice("No pending Typst math blocks to prepare");
return;
}
new import_obsidian.Notice(`Preparing ${pending.length} Typst math blocks for export...`);
const prevForce = this.settings.forceSyncCompile;
const prevSyncOnly = this.settings.syncOnlyDuringExport;
this.settings.forceSyncCompile = true;
this.settings.syncOnlyDuringExport = false;
this.exportInProgress = true;
let success = 0;
for (const id of pending) {
try {
await this.syncCompileBlock(id);
success++;
} catch (e) {
console.error("prepareExport: failed to compile block", id, e);
}
}
this.settings.forceSyncCompile = prevForce;
this.settings.syncOnlyDuringExport = prevSyncOnly;
this.exportInProgress = false;
new import_obsidian.Notice(`Prepared ${success}/${pending.length} Typst math blocks for export`);
}
wrapInTypstDocument(mathContent, isBlock = true) {
const sizeConfig = isBlock ? "16pt" : "14pt";
return `
#set text(size: ${sizeConfig})
#show math.equation: html.frame
#show math.equation.where(block: false): box
${mathContent}
`;
}
generateBlockId(source, sourcePath) {
const hash = this.simpleHash(source + sourcePath);
return `block-${hash}`;
}
simpleHash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return Math.abs(hash).toString(36);
}
/**
* Parse the full Typst-generated HTML and return a cleaned HTML string.
* - Merges paginated pages if present
* - Removes placeholder ellipsis-only nodes
* - Strips scripts/styles that could interfere
*/
parseTypstHtml(html) {
try {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
doc.querySelectorAll("script, style").forEach((n) => n.remove());
const pageSelectors = [".typst-page", ".page", ".typst-doc", "#content", "body > div"];
let parts = [];
const typstDoc = doc.querySelector(".typst-doc");
if (typstDoc) {
const children = Array.from(typstDoc.children);
if (children.length > 1) {
for (const c of children)
parts.push(c.innerHTML);
} else {
parts.push(typstDoc.innerHTML);
}
} else {
for (const sel of pageSelectors) {
const nodes = Array.from(doc.querySelectorAll(sel));
if (nodes.length > 1) {
for (const n of nodes)
parts.push(n.innerHTML);
break;
} else if (nodes.length === 1 && parts.length === 0) {
parts.push(nodes[0].innerHTML);
}
}
}
if (parts.length === 0) {
const bodyHtml = doc.body ? doc.body.innerHTML : html;
parts = [bodyHtml];
}
parts = parts.map((p) => {
var _a;
const partDoc = parser.parseFromString(`<div>${p}</div>`, "text/html");
const walker = document.createTreeWalker(partDoc.body, NodeFilter.SHOW_ELEMENT, null);
const toRemove = [];
let node = walker.nextNode();
while (node) {
const el = node;
const txt = (_a = el.textContent) == null ? void 0 : _a.trim();
if (txt && (/^\.{3,}$/.test(txt) || /^…+$/.test(txt) || txt === "\u22EF")) {
toRemove.push(el);
}
node = walker.nextNode();
}
toRemove.forEach((e) => e.remove());
return partDoc.body.innerHTML;
});
const joined = parts.map((p, i) => `<div class="typst-merged-page">${p}</div>`).join('\n<hr class="typst-page-break">\n');
return joined;
} catch (e) {
return html;
}
}
async renderTypstToHtml(typstFile, htmlFile, container, blockId) {
const useSync = this.settings.forceSyncCompile || this.settings.syncOnlyDuringExport && this.exportInProgress;
if (useSync) {
try {
const args = [
"compile",
typstFile,
htmlFile,
"--features",
"html",
"--format",
"html"
];
if (this.settings.debugMode) {
console.log("Running Typst (sync):", this.settings.typstPath, args.join(" "));
}
const res = (0, import_child_process.spawnSync)(this.settings.typstPath, args, { encoding: "utf-8" });
if (res.error) {
const errMsg = res.error.message || String(res.error);
container.innerHTML = this.formatError(errMsg, false);
throw res.error;
}
if (res.status !== 0) {
const errStr = res.stderr || `Typst process exited with code ${res.status}`;
container.innerHTML = this.formatError(errStr, false);
throw new Error(errStr);
}
const html = (0, import_fs.readFileSync)(htmlFile, "utf-8");
const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
const content = bodyMatch ? bodyMatch[1] : html;
this.renderCache.set(blockId, content);
container.innerHTML = content;
return Promise.resolve();
} catch (err) {
if (this.settings.debugMode)
console.error("Typst sync render error:", err);
return Promise.reject(err);
}
}
return new Promise((resolve, reject) => {
var _a;
if (this.watchers.has(blockId)) {
(_a = this.watchers.get(blockId)) == null ? void 0 : _a.kill();
this.watchers.delete(blockId);
}
const args = [
"compile",
typstFile,
htmlFile,
"--features",
"html",
"--format",
"html"
];
if (this.settings.debugMode) {
console.log(
"Running Typst command:",
this.settings.typstPath,
args.join(" ")
);
}
const typstProcess = (0, import_child_process.spawn)(this.settings.typstPath, args);
let stderr = "";
typstProcess.stderr.on("data", (data) => {
stderr += data.toString();
});
typstProcess.on("close", async (code) => {
if (code === 0) {
try {
const html = await import_fs.promises.readFile(htmlFile, "utf-8");
const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
const content = bodyMatch ? bodyMatch[1] : html;
this.renderCache.set(blockId, content);
container.innerHTML = content;
resolve();
} catch (error) {
container.innerHTML = this.formatError(error, false);
reject(error);
}
} else {
const errorMsg = stderr || `Typst process exited with code ${code}`;
container.innerHTML = this.formatError(errorMsg, false);
reject(new Error(errorMsg));
}
});
typstProcess.on("error", (error) => {
container.innerHTML = this.formatError(error, false);
reject(error);
});
});
}
async renderTypstWithWatch(typstFile, htmlFile, container, blockId) {
return new Promise((resolve, reject) => {
var _a;
if (this.watchers.has(blockId)) {
(_a = this.watchers.get(blockId)) == null ? void 0 : _a.kill();
this.watchers.delete(blockId);
}
const args = [
"watch",
typstFile,
htmlFile,
"--features",
"html",
"--format",
"html"
];
if (this.settings.debugMode) {
console.log(
"Running Typst watch:",
this.settings.typstPath,
args.join(" ")
);
}
const typstProcess = (0, import_child_process.spawn)(this.settings.typstPath, args);
this.watchers.set(blockId, typstProcess);
let stderr = "";
let hasRendered = false;
const checkForUpdates = async () => {
try {
const html = await import_fs.promises.readFile(htmlFile, "utf-8");
const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
const content = bodyMatch ? bodyMatch[1] : html;
this.renderCache.set(blockId, content);
container.innerHTML = content;
if (!hasRendered) {
hasRendered = true;
resolve();
}
} catch (error) {
if (this.settings.debugMode) {
console.log("Waiting for Typst to generate output...");
}
}
};
typstProcess.stderr.on("data", (data) => {
stderr += data.toString();
if (stderr.includes("error:")) {
container.innerHTML = this.formatError(stderr, false);
}
});
typstProcess.stdout.on("data", (data) => {
const output = data.toString();
if (this.settings.debugMode) {
console.log("Typst watch output:", output);
}
if (output.includes("written to") || output.includes("compiled")) {
setTimeout(checkForUpdates, 100);
}
});
setTimeout(checkForUpdates, 500);
typstProcess.on("close", (code) => {
this.watchers.delete(blockId);
if (code !== 0 && code !== null && !hasRendered) {
const errorMsg = stderr || `Typst watch exited with code ${code}`;
container.innerHTML = this.formatError(errorMsg, false);
reject(new Error(errorMsg));
}
});
typstProcess.on("error", (error) => {
this.watchers.delete(blockId);
container.innerHTML = this.formatError(error, false);
reject(error);
});
});
}
};
var TypstMathSettingTab = class extends import_obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "Typst Math Renderer Settings" });
new import_obsidian.Setting(containerEl).setName("Typst CLI path").setDesc('Path to the Typst executable (e.g., "typst" or full path)').addText(
(text) => text.setPlaceholder("typst").setValue(this.plugin.settings.typstPath).onChange(async (value) => {
this.plugin.settings.typstPath = value;
await this.plugin.saveSettings();
})
);
new import_obsidian.Setting(containerEl).setName("Enable inline math").setDesc("Process inline math blocks ($...$)").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.enableInlineMath).onChange(async (value) => {
this.plugin.settings.enableInlineMath = value;
await this.plugin.saveSettings();
})
);
new import_obsidian.Setting(containerEl).setName("Enable display math").setDesc("Process display math blocks ($$...$$)").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.enableDisplayMath).onChange(async (value) => {
this.plugin.settings.enableDisplayMath = value;
await this.plugin.saveSettings();
})
);
new import_obsidian.Setting(containerEl).setName("Debug mode").setDesc("Enable debug logging in the console").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.debugMode).onChange(async (value) => {
this.plugin.settings.debugMode = value;
await this.plugin.saveSettings();
})
);
new import_obsidian.Setting(containerEl).setName("Show detailed errors").setDesc("Display detailed Typst error messages (useful for debugging)").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.showDetailedErrors).onChange(async (value) => {
this.plugin.settings.showDetailedErrors = value;
await this.plugin.saveSettings();
})
);
new import_obsidian.Setting(containerEl).setName("Use watch mode").setDesc("Enable watch mode for code blocks (auto-recompile on changes) - experimental").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.useWatchMode).onChange(async (value) => {
this.plugin.settings.useWatchMode = value;
await this.plugin.saveSettings();
})
);
new import_obsidian.Setting(containerEl).setName("Force synchronous compile (for exports)").setDesc("Use a synchronous Typst compile which can improve reliability when exporting to PDF. This will block rendering while Typst runs.").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.forceSyncCompile).onChange(async (value) => {
this.plugin.settings.forceSyncCompile = value;
await this.plugin.saveSettings();
new import_obsidian.Notice("Force sync compile setting updated");
})
);
new import_obsidian.Setting(containerEl).setName("Sync only during print/export").setDesc("If enabled, synchronous compilation will only be used during a print/export flow. Disable to always use sync compilation when enabled.").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.syncOnlyDuringExport).onChange(async (value) => {
this.plugin.settings.syncOnlyDuringExport = value;
await this.plugin.saveSettings();
new import_obsidian.Notice("Sync-only-during-export setting updated");
})
);
new import_obsidian.Setting(containerEl).setName("Enable live preview").setDesc("Render Typst math in live preview mode (works automatically via MathJax override)").addToggle(
(toggle) => toggle.setValue(this.plugin.settings.enableLivePreview).onChange(async (value) => {
this.plugin.settings.enableLivePreview = value;
await this.plugin.saveSettings();
new import_obsidian.Notice("Reload Obsidian for this change to take full effect");
})
);
containerEl.createEl("h3", { text: "Usage" });
containerEl.createEl("p", {
text: "Create a code block with ```math or ```typst and write your Typst math syntax inside."
});
containerEl.createEl("pre", {
text: "```math\n$ sum_(i=1)^n i = (n(n+1))/2 $\n```"
});
containerEl.createEl("h3", { text: "Installation" });
containerEl.createEl("p", {
text: "Make sure you have Typst CLI installed. Visit https://github.com/typst/typst for installation instructions."
});
}
};

View File

@@ -0,0 +1,10 @@
{
"id": "obsidian-typst-cli",
"name": "Typst CLI Math Integration",
"version": "1.3.0",
"minAppVersion": "0.15.0",
"description": "Replaces default math blocks with Typst-rendered math blocks using the Typst CLI",
"author": "Your Name",
"authorUrl": "https://yourwebsite.com",
"isDesktopOnly": true
}

View File

@@ -0,0 +1,176 @@
/* Styles for Typst Math Renderer Plugin */
.typst-math-container {
margin: 1em 0;
padding: 0.5em;
background-color: var(--background-primary);
border-radius: 4px;
color: #deb4ae;
}
.typst-math-inline {
display: inline-flex;
align-items: baseline;
margin: 0;
padding: 0 0.2em;
color: #deb4ae;
}
.typst-loading {
color: var(--text-muted);
font-style: italic;
text-align: center;
padding: 1em;
}
.typst-error {
color: #e74c3c;
background-color: transparent;
padding: 0.2em 0.4em;
border-radius: 3px;
font-family: var(--font-interface);
font-size: 0.95em;
font-weight: 500;
white-space: normal;
word-break: break-word;
}
.typst-error-inline {
display: inline;
color: #e74c3c;
font-size: 0.9em;
}
.typst-error-details {
display: block;
margin-top: 0.3em;
padding: 0.5em;
background-color: rgba(231, 76, 60, 0.1);
border-radius: 3px;
font-family: var(--font-monospace);
font-size: 0.85em;
color: var(--text-muted);
white-space: pre-wrap;
word-break: break-word;
}
/* Style the Typst output - inherit theme colors */
.typst-math-container svg,
.typst-math-inline svg,
.typst-math-container .typst-doc,
.typst-math-inline .typst-doc {
max-width: 100%;
height: auto;
display: block;
margin: 0 auto;
color: var(--text-normal);
}
.typst-math-inline svg,
.typst-math-inline .typst-doc {
display: inline-block;
vertical-align: middle;
}
/* Override Typst's default black text in SVG */
.typst-math-container svg *[fill="#000000"],
.typst-math-inline svg *[fill="#000000"],
.typst-math-container svg *[fill="black"],
.typst-math-inline svg *[fill="black"] {
fill: #deb4ae !important;
}
.typst-math-container svg *[stroke="#000000"],
.typst-math-inline svg *[stroke="#000000"],
.typst-math-container svg *[stroke="black"],
.typst-math-inline svg *[stroke="black"] {
stroke: #deb4ae !important;
}
/* Also target when SVGs are directly in code blocks */
.markdown-preview-view .cm-preview-code-block svg *[fill="#000000"],
.markdown-preview-view .cm-preview-code-block svg *[fill="black"] {
fill: #deb4ae !important;
}
.markdown-preview-view .cm-preview-code-block svg *[stroke="#000000"],
.markdown-preview-view .cm-preview-code-block svg *[stroke="black"] {
stroke: #deb4ae !important;
}
/* Ensure the typst-doc class gets color */
.typst-doc {
color: #deb4ae;
}
/* Override any remaining color specifications */
.typst-math-container *,
.typst-math-inline * {
color: inherit;
}
/* Center block math */
.typst-math-container p {
text-align: center;
margin: 0;
color: inherit;
}
/* Ensure proper spacing for math content */
.typst-math-container > * {
margin: 0;
}
/* Print-specific rules: when exporting to PDF, use document/default colors
and avoid any truncation/ellipsis or SVG recoloring that may break prints */
@media print {
/* Restore default text color so printed PDFs look like the document */
.typst-math-container,
.typst-math-inline,
.typst-doc,
.typst-math-container *,
.typst-math-inline * {
color: initial !important;
-webkit-text-fill-color: initial !important;
background: transparent !important;
}
/* Ensure SVGs keep their original fills/strokes in print (do not force plugin color) */
.typst-math-container svg *[fill="#000000"],
.typst-math-inline svg *[fill="#000000"],
.typst-math-container svg *[fill="black"],
.typst-math-inline svg *[fill="black"],
.markdown-preview-view .cm-preview-code-block svg *[fill="#000000"],
.markdown-preview-view .cm-preview-code-block svg *[fill="black"] {
fill: initial !important;
}
.typst-math-container svg *[stroke="#000000"],
.typst-math-inline svg *[stroke="#000000"],
.typst-math-container svg *[stroke="black"],
.typst-math-inline svg *[stroke="black"],
.markdown-preview-view .cm-preview-code-block svg *[stroke="#000000"],
.markdown-preview-view .cm-preview-code-block svg *[stroke="black"] {
stroke: initial !important;
}
/* Avoid text-overflow/ellipsis in printed output */
.typst-math-container,
.typst-math-inline,
.typst-math-container *,
.typst-math-inline * {
white-space: normal !important;
text-overflow: clip !important;
overflow: visible !important;
}
/* Remove any max-width/inline-block constraints that might clip content */
.typst-math-inline svg,
.typst-math-inline .typst-doc,
.typst-math-container svg,
.typst-math-container .typst-doc {
max-width: none !important;
height: auto !important;
display: inline !important;
}
}

View File

@@ -0,0 +1,8 @@
{
"name": "Minimal",
"version": "8.0.4",
"minAppVersion": "1.9.0",
"author": "@kepano",
"authorUrl": "https://twitter.com/kepano",
"fundingUrl": "https://www.buymeacoffee.com/kepano"
}

2251
.obsidian/themes/Minimal/theme.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
{
"name": "Tokyo Night",
"version": "1.1.6",
"minAppVersion": "0.0.1",
"author": "tcmmichaelb139"
}

2129
.obsidian/themes/Tokyo Night/theme.css vendored Normal file

File diff suppressed because it is too large Load Diff

202
.obsidian/workspace.json vendored Normal file
View File

@@ -0,0 +1,202 @@
{
"main": {
"id": "687d1c86232da224",
"type": "split",
"children": [
{
"id": "15fadcc006380479",
"type": "tabs",
"children": [
{
"id": "6b7a81afba2d55ca",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "DAS/Set Theory.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Set Theory"
}
},
{
"id": "197c8e18c8d8ef8c",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "DAS/Functions.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Functions"
}
}
],
"currentTab": 1
}
],
"direction": "vertical"
},
"left": {
"id": "9ec91dab2caa0289",
"type": "split",
"children": [
{
"id": "3eac170f3e784f0a",
"type": "tabs",
"children": [
{
"id": "7a0e7b37bd89861d",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Files"
}
},
{
"id": "4f49c1281d39a560",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Search"
}
},
{
"id": "2e48ff6ec7a1cd18",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Bookmarks"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "8a65bc0c1d4d98f2",
"type": "split",
"children": [
{
"id": "9a7ddad3818b86d0",
"type": "tabs",
"children": [
{
"id": "93d7330db83403ee",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "Studium.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks for Studium"
}
},
{
"id": "6d8323e062c2ca0a",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links"
}
},
{
"id": "10b1fc99e21f5952",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tags"
}
},
{
"id": "9ef86e6061e150c0",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Outline"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"bases:Create new base": false
}
},
"active": "197c8e18c8d8ef8c",
"lastOpenFiles": [
"DAS/Set Theory.md",
"DAS/Functions.md",
"mathe/notation.md",
"Studium.md",
"ET/Netzwerke.md",
"ET/Kirchhoffsche Regeln.md",
"ET/Grundlagen.md",
"DAS",
"ET/images/beispiel_knotenregel.png",
"ET/images",
"ET",
"mathe/notation.md~",
"mathe/4913",
"mathe"
]
}

27
DAS/Functions.md Normal file
View File

@@ -0,0 +1,27 @@
A function takes in an element from its **domain**, transforms it in someway and outputs that transformed element, which is part of the **co-domain**.
Every element of the **domain** must map to a value in the **co-domain**, all values of the **co-domain** that are mapped to form the functions **image**.
A function must be **deterministic** - one input can only map to a single output.
## Notation
General function notation: $f: X -> Y$
> [!INFO]
> $f$: name of the function
> $X$: Domain
> $Y$: Co-domain
> $f(x)$: Image of $f$
> $X$, $f(x)$ and $Y$ are [[Set Theory | Set]]
For any $x in X$ the output $f(x)$ is an element of $Y$.
## Mapping Properties
### Injectivity
A function is _injective_ if every element in $Y$ has _at most_ one matching $x in X$.
- $forall y in Y,exists^(<=1) x in X : f(x) = y$
### Surjectivity
A function is _surjective_ if every element $y in Y$ has _at minimum_ one matching $x in X$
- $forall y in Y, exists x in X : f(x) = y$
### Bijectivity
A function is _bijective_ if every element $y in Y$ has _exactly_ one matching $x in X$ (it is _injective_ and _surjective_)

85
DAS/Set Theory.md Normal file
View File

@@ -0,0 +1,85 @@
> A set is a collection of _unordered_ elements.
> A set cannot contain duplicates.
## Notation
### Set Notation
Declaration of a set $A$ with elements $a$, $b$, $c$:
$$ A := {a, b, c} $$
### Cardinality
Amount of Elements in a set $A$
Notation: $|A|$
$$
A := {1, 2, 3, 4} \
|A| = 4
$$
### Well-Known Sets
- Empty Set: $emptyset = {}$
- Natural Numbers: $N = {1, 2, 3, ...}$
- Integers: $ZZ = {-2, -1, 0, 1, 2}$
- Rational Numbers: $QQ = {1/2, 22/7 }$
- Real Numbers: $RR = {1, pi, sqrt(2)}$
- Complex Numbers: $CC = {i, pi, 1, sqrt(-1)}$
### Set-Builder Notation
Common form of notation to create sets without explicitly specifying elements.
$$
A := {x in N | 0 <= x <= 5} \
A = {1, 2, 3, 4, 5}
$$
### Member of
Denote whether $x$ is an element of the set $A$
Notation: $x in A$
Negation: $x in.not A$
### Subsets
| Type | Explanation | Notation |
| ------------------------ | ---------------------------------------------------------------------- | ------------------- |
| **Subset** | Every element of $A$ is in $B$ | $A subset B$ |
| **Subset or equal to** | Every element of $A$ is in $B$, or they are the exactly same set | $A subset.eq B$ |
| **Proper subset** | Every element of $A$ is in $B$, but $A$ is definitely smaller than $B$ | $A subset.sq B$<br> |
| **Superset**<br> | $A$ contains everything that is in $B$ | $A supset B$ |
| **Superset or equal to** | $A$ contains everything that is in $B$, or they are identical | $A supset.eq B$ |
## Operations
### Union
Notation: $A union B$
Definition: all elements from both sets _without adding duplicates_
$$ A := {1, 2, 3}\ B := {3, 4, 5}\ A union B = {1, 2, 3, 4, 5} $$
### Intersection
Notation:$A inter B$
Definition: all elements _contained in both sets_
$$
A := {1, 2, 3} \
B := {2, 3, 4} \
A inter B = {2, 3}
$$
### Difference
Notation: $A backslash B$
Definition: all elements _in $A$ that are not in $B$_
$$
A := {1, 2, 3} \
B := {3, 4, 5} \
A backslash B = {1, 2}
$$
### Symmetric Difference
Notation: $A Delta B$
Definition: all elements _only in $A$ or only in $B$_
$$
A := {1, 2, 3} \
B := {2, 3, 4} \
A Delta B = {1, 4}
$$
### Cartesian Product
Notation: $A times B$
Definition: all pairs of all elements in $A$ and $B$
$$
A := {1, 2} \
B := {3, 4, 5} \
A times B = {(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)}
$$
### Powerset
Notation: $cal(P)(A)$
Definition: all possible _Subsets of A_
$$
A := {1, 2, 3} \
cal(P)(A) = {emptyset, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}
$$

8
ET/Grundlagen.md Normal file
View File

@@ -0,0 +1,8 @@
## Formelzeichen, Einheiten, Konstanten
- Leistung \[$P$] in __Watt__ \[$W$]
- Stromstärke \[$I$] in __Ampere__ \[$A$]
- Widerstand \[$R$] in __Ohm__ \[$Omega$]
- Spannung \[$U$] in __Volt__ \[$V$]
- Ladung \[$Q$] in __Coulomb__ \[$C$]
- $Q = -e approx -1.602 * 10^(-19)C$
## Netzwerke

View File

@@ -0,0 +1,14 @@
## Knotenregel
- Die Summe aller in einen Knoten hinein und herausfließenden Ströme entspricht 0
- _"Alles was reinfließt muss auch wieder rausfließen"_
$$sum_(k=1)^(n)I_k = 0$$
### Beispiel Knotenregel
![[beispiel_knotenregel.png|250]]
$$ ("I") wide && I + I_2 - I_1 &= 0 \
("II") wide && I_1 + I_3 + I_q &= 0 \
("III") wide && -I_q - I_3 - I_2 - I &= 0 $$
## Maschenregel
- Die Summe aller Spannung in einer Masche

22
ET/Netzwerke.md Normal file
View File

@@ -0,0 +1,22 @@
- In einem Netzwerk kann man allgemein $k - 1$ unabhängige [[Kirchhoffsche Regeln#Knotenregel|-> Knotengleichungen]] aufstellen ($k$ ist hier die Anzahl der Knoten)
## Bezugspfeile
- Richtung egal -> ändert nur Vorzeichen in der Rechnung
### Verbraucherpfeilsystem
Liegt vor wenn Spannung $U$ und Stromstärke $I$ in die selbe Richtung zeigen.
_Es gelten:_
- $P = U * I$
- $U eq R * I$
Wenn $P$ positiv ist, wird Leistung aufgenommen (**verbraucht**).
### Erzeugerpfeilsystem
Liegt vor wenn Spannung $U$ und Stromstärke $I$ in entgegengesetzte Richtungen Zeigen.
_Es gelten:_
- $P = U * I$
- $U = -R * I$
Wenn $P$ positiv ist, wird Leistung abgegeben (**erzeugt**)
> Es ist sinnvoll die Bezugspfeile an Widerständen in Richtung der
> Stromstärke zu wählen (-> [[#Verbraucherpfeilsystem]]), da ein Widerstand
> nur Leistung aufnehmen kann.
> Dies vermeidet Vorzeichenfehler beim rechnen.

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

7
Studium.md Normal file
View File

@@ -0,0 +1,7 @@
> [!INFO]
> **Semester**: `#1` - WiSe 25/26
> **Kurse**:
> - *DAS*: Diskrete Algebraische Strukturen
> - *ET*
>

5
mathe/notation.md Normal file
View File

@@ -0,0 +1,5 @@
# Notation
## 1. Sets and Logic
$|A|$: The *cardinality* (size) of finite set $A$.
$script(p)$