chore: update TypeScript build info cache

This commit is contained in:
Bruno Charest 2025-09-28 23:04:52 -04:00
parent a8b60f87f6
commit 1c7a49fd0e
40 changed files with 4337 additions and 126 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,137 +1,152 @@
{ {
"hash": "550e7d4b", "hash": "7e911bc9",
"configHash": "625eb836", "configHash": "6d2fe504",
"lockfileHash": "77f35274", "lockfileHash": "610c0484",
"browserHash": "a276ee59", "browserHash": "449bae22",
"optimized": { "optimized": {
"@angular/cdk/a11y": {
"src": "../../../../../../node_modules/@angular/cdk/fesm2022/a11y.mjs",
"file": "@angular_cdk_a11y.js",
"fileHash": "ba521394",
"needsInterop": false
},
"@angular/common": { "@angular/common": {
"src": "../../../../../../node_modules/@angular/common/fesm2022/common.mjs", "src": "../../../../../../node_modules/@angular/common/fesm2022/common.mjs",
"file": "@angular_common.js", "file": "@angular_common.js",
"fileHash": "05936fd0", "fileHash": "7db29729",
"needsInterop": false "needsInterop": false
}, },
"@angular/common/http": { "@angular/common/http": {
"src": "../../../../../../node_modules/@angular/common/fesm2022/http.mjs", "src": "../../../../../../node_modules/@angular/common/fesm2022/http.mjs",
"file": "@angular_common_http.js", "file": "@angular_common_http.js",
"fileHash": "7c938c00", "fileHash": "9fd91a95",
"needsInterop": false "needsInterop": false
}, },
"@angular/common/locales/fr": { "@angular/common/locales/fr": {
"src": "../../../../../../node_modules/@angular/common/locales/fr.js", "src": "../../../../../../node_modules/@angular/common/locales/fr.js",
"file": "@angular_common_locales_fr.js", "file": "@angular_common_locales_fr.js",
"fileHash": "3f6dc116", "fileHash": "b1d8412a",
"needsInterop": false "needsInterop": false
}, },
"@angular/core": { "@angular/core": {
"src": "../../../../../../node_modules/@angular/core/fesm2022/core.mjs", "src": "../../../../../../node_modules/@angular/core/fesm2022/core.mjs",
"file": "@angular_core.js", "file": "@angular_core.js",
"fileHash": "51703fe3", "fileHash": "4aab6957",
"needsInterop": false "needsInterop": false
}, },
"@angular/core/rxjs-interop": { "@angular/core/rxjs-interop": {
"src": "../../../../../../node_modules/@angular/core/fesm2022/rxjs-interop.mjs", "src": "../../../../../../node_modules/@angular/core/fesm2022/rxjs-interop.mjs",
"file": "@angular_core_rxjs-interop.js", "file": "@angular_core_rxjs-interop.js",
"fileHash": "d9952fa8", "fileHash": "83149d22",
"needsInterop": false "needsInterop": false
}, },
"@angular/forms": { "@angular/forms": {
"src": "../../../../../../node_modules/@angular/forms/fesm2022/forms.mjs", "src": "../../../../../../node_modules/@angular/forms/fesm2022/forms.mjs",
"file": "@angular_forms.js", "file": "@angular_forms.js",
"fileHash": "2b783004", "fileHash": "1fffec30",
"needsInterop": false "needsInterop": false
}, },
"@angular/platform-browser": { "@angular/platform-browser": {
"src": "../../../../../../node_modules/@angular/platform-browser/fesm2022/platform-browser.mjs", "src": "../../../../../../node_modules/@angular/platform-browser/fesm2022/platform-browser.mjs",
"file": "@angular_platform-browser.js", "file": "@angular_platform-browser.js",
"fileHash": "330b2f60", "fileHash": "8a1d0c5e",
"needsInterop": false "needsInterop": false
}, },
"angular-calendar": { "angular-calendar": {
"src": "../../../../../../node_modules/angular-calendar/fesm2022/angular-calendar.mjs", "src": "../../../../../../node_modules/angular-calendar/fesm2022/angular-calendar.mjs",
"file": "angular-calendar.js", "file": "angular-calendar.js",
"fileHash": "3f18ca62", "fileHash": "6ade82aa",
"needsInterop": false "needsInterop": false
}, },
"angular-calendar/date-adapters/date-fns": { "angular-calendar/date-adapters/date-fns": {
"src": "../../../../../../node_modules/angular-calendar/date-adapters/esm/date-fns/index.js", "src": "../../../../../../node_modules/angular-calendar/date-adapters/esm/date-fns/index.js",
"file": "angular-calendar_date-adapters_date-fns.js", "file": "angular-calendar_date-adapters_date-fns.js",
"fileHash": "50981191", "fileHash": "bc3d3c33",
"needsInterop": false "needsInterop": false
}, },
"highlight.js": { "highlight.js": {
"src": "../../../../../../node_modules/highlight.js/es/index.js", "src": "../../../../../../node_modules/highlight.js/es/index.js",
"file": "highlight__js.js", "file": "highlight__js.js",
"fileHash": "093a5a02", "fileHash": "1c76d52d",
"needsInterop": false "needsInterop": false
}, },
"markdown-it": { "markdown-it": {
"src": "../../../../../../node_modules/markdown-it/index.mjs", "src": "../../../../../../node_modules/markdown-it/index.mjs",
"file": "markdown-it.js", "file": "markdown-it.js",
"fileHash": "902d4090", "fileHash": "8e6c68f6",
"needsInterop": false "needsInterop": false
}, },
"markdown-it-anchor": { "markdown-it-anchor": {
"src": "../../../../../../node_modules/markdown-it-anchor/dist/markdownItAnchor.mjs", "src": "../../../../../../node_modules/markdown-it-anchor/dist/markdownItAnchor.mjs",
"file": "markdown-it-anchor.js", "file": "markdown-it-anchor.js",
"fileHash": "ba1f7b46", "fileHash": "5e692d12",
"needsInterop": false "needsInterop": false
}, },
"markdown-it-attrs": { "markdown-it-attrs": {
"src": "../../../../../../node_modules/markdown-it-attrs/index.js", "src": "../../../../../../node_modules/markdown-it-attrs/index.js",
"file": "markdown-it-attrs.js", "file": "markdown-it-attrs.js",
"fileHash": "09d13132", "fileHash": "2c29aea3",
"needsInterop": true "needsInterop": true
}, },
"markdown-it-footnote": { "markdown-it-footnote": {
"src": "../../../../../../node_modules/markdown-it-footnote/index.js", "src": "../../../../../../node_modules/markdown-it-footnote/index.js",
"file": "markdown-it-footnote.js", "file": "markdown-it-footnote.js",
"fileHash": "7d35f2e8", "fileHash": "4ea0b149",
"needsInterop": true "needsInterop": true
}, },
"markdown-it-multimd-table": { "markdown-it-multimd-table": {
"src": "../../../../../../node_modules/markdown-it-multimd-table/index.js", "src": "../../../../../../node_modules/markdown-it-multimd-table/index.js",
"file": "markdown-it-multimd-table.js", "file": "markdown-it-multimd-table.js",
"fileHash": "26b36290", "fileHash": "13033d9b",
"needsInterop": true "needsInterop": true
}, },
"markdown-it-task-lists": { "markdown-it-task-lists": {
"src": "../../../../../../node_modules/markdown-it-task-lists/index.js", "src": "../../../../../../node_modules/markdown-it-task-lists/index.js",
"file": "markdown-it-task-lists.js", "file": "markdown-it-task-lists.js",
"fileHash": "283c7022", "fileHash": "b724aca3",
"needsInterop": true "needsInterop": true
}, },
"mermaid": { "mermaid": {
"src": "../../../../../../node_modules/mermaid/dist/mermaid.core.mjs", "src": "../../../../../../node_modules/mermaid/dist/mermaid.core.mjs",
"file": "mermaid.js", "file": "mermaid.js",
"fileHash": "6efe0ec4", "fileHash": "b2047cf6",
"needsInterop": false "needsInterop": false
}, },
"rxjs": { "rxjs": {
"src": "../../../../../../node_modules/rxjs/dist/esm5/index.js", "src": "../../../../../../node_modules/rxjs/dist/esm5/index.js",
"file": "rxjs.js", "file": "rxjs.js",
"fileHash": "ff4ac288", "fileHash": "bff53593",
"needsInterop": false "needsInterop": false
} }
}, },
"chunks": { "chunks": {
"diagram-S2PKOQOG-RM7ASWFZ": { "sankeyDiagram-TZEHDZUN-GH26R5YW": {
"file": "diagram-S2PKOQOG-RM7ASWFZ.js" "file": "sankeyDiagram-TZEHDZUN-GH26R5YW.js"
}, },
"diagram-QEK2KX5R-QLL2LDZJ": { "diagram-S2PKOQOG-D6F7ANDO": {
"file": "diagram-QEK2KX5R-QLL2LDZJ.js" "file": "diagram-S2PKOQOG-D6F7ANDO.js"
}, },
"blockDiagram-VD42YOAC-6W666JF2": { "diagram-QEK2KX5R-KMPAAIQN": {
"file": "blockDiagram-VD42YOAC-6W666JF2.js" "file": "diagram-QEK2KX5R-KMPAAIQN.js"
}, },
"architectureDiagram-VXUJARFQ-7JNJRGGM": { "blockDiagram-VD42YOAC-KZTUA5HK": {
"file": "architectureDiagram-VXUJARFQ-7JNJRGGM.js" "file": "blockDiagram-VD42YOAC-KZTUA5HK.js"
}, },
"diagram-PSM6KHXK-3GNQQWOU": { "architectureDiagram-VXUJARFQ-WEBFVMSU": {
"file": "diagram-PSM6KHXK-3GNQQWOU.js" "file": "architectureDiagram-VXUJARFQ-WEBFVMSU.js"
},
"diagram-PSM6KHXK-OYEWFDFJ": {
"file": "diagram-PSM6KHXK-OYEWFDFJ.js"
},
"classDiagram-2ON5EDUG-NO6W7S54": {
"file": "classDiagram-2ON5EDUG-NO6W7S54.js"
}, },
"classDiagram-v2-WZHVMYZB-J2EUDOJH": { "classDiagram-v2-WZHVMYZB-J2EUDOJH": {
"file": "classDiagram-v2-WZHVMYZB-J2EUDOJH.js" "file": "classDiagram-v2-WZHVMYZB-J2EUDOJH.js"
}, },
"chunk-SOIGDKSE": {
"file": "chunk-SOIGDKSE.js"
},
"stateDiagram-FKZM4ZOC-JBDO72I4": { "stateDiagram-FKZM4ZOC-JBDO72I4": {
"file": "stateDiagram-FKZM4ZOC-JBDO72I4.js" "file": "stateDiagram-FKZM4ZOC-JBDO72I4.js"
}, },
@ -150,20 +165,26 @@
"mindmap-definition-VGOIOE7T-LIQX7OEO": { "mindmap-definition-VGOIOE7T-LIQX7OEO": {
"file": "mindmap-definition-VGOIOE7T-LIQX7OEO.js" "file": "mindmap-definition-VGOIOE7T-LIQX7OEO.js"
}, },
"kanban-definition-3W4ZIXB7-GUMHX2OD": { "kanban-definition-3W4ZIXB7-H4KIKSB7": {
"file": "kanban-definition-3W4ZIXB7-GUMHX2OD.js" "file": "kanban-definition-3W4ZIXB7-H4KIKSB7.js"
}, },
"sankeyDiagram-TZEHDZUN-GH26R5YW": { "gitGraphDiagram-NY62KEGX-DAVBKLGM": {
"file": "sankeyDiagram-TZEHDZUN-GH26R5YW.js" "file": "gitGraphDiagram-NY62KEGX-DAVBKLGM.js"
}, },
"ganttDiagram-LVOFAZNH-HYMY4RKD": { "ganttDiagram-LVOFAZNH-HYMY4RKD": {
"file": "ganttDiagram-LVOFAZNH-HYMY4RKD.js" "file": "ganttDiagram-LVOFAZNH-HYMY4RKD.js"
}, },
"infoDiagram-F6ZHWCRC-HMHRPPWW": { "infoDiagram-F6ZHWCRC-L22DC2WZ": {
"file": "infoDiagram-F6ZHWCRC-HMHRPPWW.js" "file": "infoDiagram-F6ZHWCRC-L22DC2WZ.js"
}, },
"pieDiagram-ADFJNKIX-HTPFO6AD": { "pieDiagram-ADFJNKIX-QYG3H4AZ": {
"file": "pieDiagram-ADFJNKIX-HTPFO6AD.js" "file": "pieDiagram-ADFJNKIX-QYG3H4AZ.js"
},
"chunk-PNW5KFH4": {
"file": "chunk-PNW5KFH4.js"
},
"chunk-ORIZ2BG5": {
"file": "chunk-ORIZ2BG5.js"
}, },
"quadrantDiagram-AYHSOK5B-G2SG5IZD": { "quadrantDiagram-AYHSOK5B-G2SG5IZD": {
"file": "quadrantDiagram-AYHSOK5B-G2SG5IZD.js" "file": "quadrantDiagram-AYHSOK5B-G2SG5IZD.js"
@ -177,69 +198,63 @@
"sequenceDiagram-WL72ISMW-O3J6HVSP": { "sequenceDiagram-WL72ISMW-O3J6HVSP": {
"file": "sequenceDiagram-WL72ISMW-O3J6HVSP.js" "file": "sequenceDiagram-WL72ISMW-O3J6HVSP.js"
}, },
"classDiagram-2ON5EDUG-NO6W7S54": { "chunk-3WIYXQMB": {
"file": "classDiagram-2ON5EDUG-NO6W7S54.js" "file": "chunk-3WIYXQMB.js"
}, },
"chunk-SOIGDKSE": { "erDiagram-Q2GNP2WA-JTEYVNF6": {
"file": "chunk-SOIGDKSE.js" "file": "erDiagram-Q2GNP2WA-JTEYVNF6.js"
}, },
"info-63CPKGFF-W56KXM6Z": { "info-63CPKGFF-W56KXM6Z": {
"file": "info-63CPKGFF-W56KXM6Z.js" "file": "info-63CPKGFF-W56KXM6Z.js"
}, },
"packet-HUATNLJX-LCJ3BRNR": {
"file": "packet-HUATNLJX-LCJ3BRNR.js"
},
"pie-WTHONI2E-7JKUTNCJ": {
"file": "pie-WTHONI2E-7JKUTNCJ.js"
},
"architecture-O4VJ6CD3-IBEWAQYB": {
"file": "architecture-O4VJ6CD3-IBEWAQYB.js"
},
"gitGraph-ZV4HHKMB-6SC2CHQE": {
"file": "gitGraph-ZV4HHKMB-6SC2CHQE.js"
},
"radar-NJJJXTRR-IXC2PP4O": {
"file": "radar-NJJJXTRR-IXC2PP4O.js"
},
"treemap-75Q7IDZK-IP775KCD": {
"file": "treemap-75Q7IDZK-IP775KCD.js"
},
"gitGraphDiagram-NY62KEGX-DAVBKLGM": {
"file": "gitGraphDiagram-NY62KEGX-DAVBKLGM.js"
},
"chunk-PNW5KFH4": {
"file": "chunk-PNW5KFH4.js"
},
"chunk-ORIZ2BG5": {
"file": "chunk-ORIZ2BG5.js"
},
"chunk-3WIYXQMB": {
"file": "chunk-3WIYXQMB.js"
},
"chunk-BUI4I457": { "chunk-BUI4I457": {
"file": "chunk-BUI4I457.js" "file": "chunk-BUI4I457.js"
}, },
"packet-HUATNLJX-LCJ3BRNR": {
"file": "packet-HUATNLJX-LCJ3BRNR.js"
},
"chunk-CHJ5BV6S": { "chunk-CHJ5BV6S": {
"file": "chunk-CHJ5BV6S.js" "file": "chunk-CHJ5BV6S.js"
}, },
"pie-WTHONI2E-7JKUTNCJ": {
"file": "pie-WTHONI2E-7JKUTNCJ.js"
},
"chunk-XP22GJHQ": { "chunk-XP22GJHQ": {
"file": "chunk-XP22GJHQ.js" "file": "chunk-XP22GJHQ.js"
}, },
"architecture-O4VJ6CD3-IBEWAQYB": {
"file": "architecture-O4VJ6CD3-IBEWAQYB.js"
},
"chunk-NYZY7JGI": { "chunk-NYZY7JGI": {
"file": "chunk-NYZY7JGI.js" "file": "chunk-NYZY7JGI.js"
}, },
"gitGraph-ZV4HHKMB-6SC2CHQE": {
"file": "gitGraph-ZV4HHKMB-6SC2CHQE.js"
},
"chunk-FNEVJCCX": { "chunk-FNEVJCCX": {
"file": "chunk-FNEVJCCX.js" "file": "chunk-FNEVJCCX.js"
}, },
"radar-NJJJXTRR-IXC2PP4O": {
"file": "radar-NJJJXTRR-IXC2PP4O.js"
},
"chunk-R33GOAXK": { "chunk-R33GOAXK": {
"file": "chunk-R33GOAXK.js" "file": "chunk-R33GOAXK.js"
}, },
"treemap-75Q7IDZK-IP775KCD": {
"file": "treemap-75Q7IDZK-IP775KCD.js"
},
"chunk-5SXTVVUG": { "chunk-5SXTVVUG": {
"file": "chunk-5SXTVVUG.js" "file": "chunk-5SXTVVUG.js"
}, },
"chunk-WHHJWK6B": { "chunk-WHHJWK6B": {
"file": "chunk-WHHJWK6B.js" "file": "chunk-WHHJWK6B.js"
}, },
"chunk-BSULYXPT": {
"file": "chunk-BSULYXPT.js"
},
"chunk-B5NQPFQG": {
"file": "chunk-B5NQPFQG.js"
},
"katex-JJTYNRHT": { "katex-JJTYNRHT": {
"file": "katex-JJTYNRHT.js" "file": "katex-JJTYNRHT.js"
}, },
@ -255,6 +270,9 @@
"chunk-6SIVX7OU": { "chunk-6SIVX7OU": {
"file": "chunk-6SIVX7OU.js" "file": "chunk-6SIVX7OU.js"
}, },
"chunk-NGEE2U2J": {
"file": "chunk-NGEE2U2J.js"
},
"cose-bilkent-S5V4N54A-5WYXQMNH": { "cose-bilkent-S5V4N54A-5WYXQMNH": {
"file": "cose-bilkent-S5V4N54A-5WYXQMNH.js" "file": "cose-bilkent-S5V4N54A-5WYXQMNH.js"
}, },
@ -273,24 +291,12 @@
"chunk-I4QIIVJ7": { "chunk-I4QIIVJ7": {
"file": "chunk-I4QIIVJ7.js" "file": "chunk-I4QIIVJ7.js"
}, },
"erDiagram-Q2GNP2WA-JTEYVNF6": {
"file": "erDiagram-Q2GNP2WA-JTEYVNF6.js"
},
"chunk-PLWNSIKB": { "chunk-PLWNSIKB": {
"file": "chunk-PLWNSIKB.js" "file": "chunk-PLWNSIKB.js"
}, },
"chunk-LHH5RO5K": { "chunk-LHH5RO5K": {
"file": "chunk-LHH5RO5K.js" "file": "chunk-LHH5RO5K.js"
}, },
"chunk-BSULYXPT": {
"file": "chunk-BSULYXPT.js"
},
"chunk-B5NQPFQG": {
"file": "chunk-B5NQPFQG.js"
},
"chunk-NGEE2U2J": {
"file": "chunk-NGEE2U2J.js"
},
"chunk-JSZQKJT3": { "chunk-JSZQKJT3": {
"file": "chunk-JSZQKJT3.js" "file": "chunk-JSZQKJT3.js"
}, },

View File

@ -12,14 +12,14 @@ import "./chunk-FNEVJCCX.js";
import "./chunk-R33GOAXK.js"; import "./chunk-R33GOAXK.js";
import "./chunk-5SXTVVUG.js"; import "./chunk-5SXTVVUG.js";
import "./chunk-WHHJWK6B.js"; import "./chunk-WHHJWK6B.js";
import "./chunk-6SIVX7OU.js";
import {
cytoscape as cytoscape2
} from "./chunk-4434HPF7.js";
import { import {
selectSvgElement selectSvgElement
} from "./chunk-B5NQPFQG.js"; } from "./chunk-B5NQPFQG.js";
import "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js"; import "./chunk-NGEE2U2J.js";
import {
cytoscape as cytoscape2
} from "./chunk-4434HPF7.js";
import { import {
createText, createText,
getIconSVG, getIconSVG,
@ -8843,4 +8843,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=architectureDiagram-VXUJARFQ-7JNJRGGM.js.map //# sourceMappingURL=architectureDiagram-VXUJARFQ-WEBFVMSU.js.map

View File

@ -4,10 +4,10 @@ import {
import { import {
clone_default clone_default
} from "./chunk-6SIVX7OU.js"; } from "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js";
import { import {
getIconStyles getIconStyles
} from "./chunk-I4QIIVJ7.js"; } from "./chunk-I4QIIVJ7.js";
import "./chunk-NGEE2U2J.js";
import { import {
getLineFunctionsWithOffset getLineFunctionsWithOffset
} from "./chunk-2HSIUWWJ.js"; } from "./chunk-2HSIUWWJ.js";
@ -3745,4 +3745,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=blockDiagram-VD42YOAC-6W666JF2.js.map //# sourceMappingURL=blockDiagram-VD42YOAC-KZTUA5HK.js.map

View File

@ -12,14 +12,14 @@ import "./chunk-FNEVJCCX.js";
import "./chunk-R33GOAXK.js"; import "./chunk-R33GOAXK.js";
import "./chunk-5SXTVVUG.js"; import "./chunk-5SXTVVUG.js";
import "./chunk-WHHJWK6B.js"; import "./chunk-WHHJWK6B.js";
import "./chunk-6SIVX7OU.js";
import {
setupViewPortForSVG
} from "./chunk-LHH5RO5K.js";
import { import {
selectSvgElement selectSvgElement
} from "./chunk-B5NQPFQG.js"; } from "./chunk-B5NQPFQG.js";
import "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js"; import "./chunk-NGEE2U2J.js";
import {
setupViewPortForSVG
} from "./chunk-LHH5RO5K.js";
import { import {
isLabelStyle, isLabelStyle,
styles2String styles2String
@ -566,4 +566,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=diagram-PSM6KHXK-3GNQQWOU.js.map //# sourceMappingURL=diagram-PSM6KHXK-OYEWFDFJ.js.map

View File

@ -12,10 +12,10 @@ import "./chunk-FNEVJCCX.js";
import "./chunk-R33GOAXK.js"; import "./chunk-R33GOAXK.js";
import "./chunk-5SXTVVUG.js"; import "./chunk-5SXTVVUG.js";
import "./chunk-WHHJWK6B.js"; import "./chunk-WHHJWK6B.js";
import "./chunk-6SIVX7OU.js";
import { import {
selectSvgElement selectSvgElement
} from "./chunk-B5NQPFQG.js"; } from "./chunk-B5NQPFQG.js";
import "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js"; import "./chunk-NGEE2U2J.js";
import { import {
cleanAndMerge cleanAndMerge
@ -337,4 +337,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=diagram-QEK2KX5R-QLL2LDZJ.js.map //# sourceMappingURL=diagram-QEK2KX5R-KMPAAIQN.js.map

View File

@ -12,10 +12,10 @@ import "./chunk-FNEVJCCX.js";
import "./chunk-R33GOAXK.js"; import "./chunk-R33GOAXK.js";
import "./chunk-5SXTVVUG.js"; import "./chunk-5SXTVVUG.js";
import "./chunk-WHHJWK6B.js"; import "./chunk-WHHJWK6B.js";
import "./chunk-6SIVX7OU.js";
import { import {
selectSvgElement selectSvgElement
} from "./chunk-B5NQPFQG.js"; } from "./chunk-B5NQPFQG.js";
import "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js"; import "./chunk-NGEE2U2J.js";
import { import {
cleanAndMerge cleanAndMerge
@ -247,4 +247,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=diagram-S2PKOQOG-RM7ASWFZ.js.map //# sourceMappingURL=diagram-S2PKOQOG-D6F7ANDO.js.map

View File

@ -9,13 +9,13 @@ import "./chunk-FNEVJCCX.js";
import "./chunk-R33GOAXK.js"; import "./chunk-R33GOAXK.js";
import "./chunk-5SXTVVUG.js"; import "./chunk-5SXTVVUG.js";
import "./chunk-WHHJWK6B.js"; import "./chunk-WHHJWK6B.js";
import "./chunk-6SIVX7OU.js";
import { import {
package_default package_default
} from "./chunk-BSULYXPT.js"; } from "./chunk-BSULYXPT.js";
import { import {
selectSvgElement selectSvgElement
} from "./chunk-B5NQPFQG.js"; } from "./chunk-B5NQPFQG.js";
import "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js"; import "./chunk-NGEE2U2J.js";
import { import {
configureSvgSize configureSvgSize
@ -57,4 +57,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=infoDiagram-F6ZHWCRC-HMHRPPWW.js.map //# sourceMappingURL=infoDiagram-F6ZHWCRC-L22DC2WZ.js.map

View File

@ -1,9 +1,9 @@
import {
getIconStyles
} from "./chunk-I4QIIVJ7.js";
import { import {
selectSvgElement selectSvgElement
} from "./chunk-B5NQPFQG.js"; } from "./chunk-B5NQPFQG.js";
import {
getIconStyles
} from "./chunk-I4QIIVJ7.js";
import { import {
JSON_SCHEMA, JSON_SCHEMA,
load load
@ -1122,4 +1122,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=kanban-definition-3W4ZIXB7-GUMHX2OD.js.map //# sourceMappingURL=kanban-definition-3W4ZIXB7-H4KIKSB7.js.map

View File

@ -522,7 +522,7 @@ var detector7 = __name((txt) => {
return /^\s*info/.test(txt); return /^\s*info/.test(txt);
}, "detector"); }, "detector");
var loader7 = __name(async () => { var loader7 = __name(async () => {
const { diagram: diagram2 } = await import("./infoDiagram-F6ZHWCRC-HMHRPPWW.js"); const { diagram: diagram2 } = await import("./infoDiagram-F6ZHWCRC-L22DC2WZ.js");
return { id: id7, diagram: diagram2 }; return { id: id7, diagram: diagram2 };
}, "loader"); }, "loader");
var info = { var info = {
@ -535,7 +535,7 @@ var detector8 = __name((txt) => {
return /^\s*pie/.test(txt); return /^\s*pie/.test(txt);
}, "detector"); }, "detector");
var loader8 = __name(async () => { var loader8 = __name(async () => {
const { diagram: diagram2 } = await import("./pieDiagram-ADFJNKIX-HTPFO6AD.js"); const { diagram: diagram2 } = await import("./pieDiagram-ADFJNKIX-QYG3H4AZ.js");
return { id: id8, diagram: diagram2 }; return { id: id8, diagram: diagram2 };
}, "loader"); }, "loader");
var pie = { var pie = {
@ -784,7 +784,7 @@ var detector21 = __name((txt) => {
return /^\s*kanban/.test(txt); return /^\s*kanban/.test(txt);
}, "detector"); }, "detector");
var loader21 = __name(async () => { var loader21 = __name(async () => {
const { diagram: diagram2 } = await import("./kanban-definition-3W4ZIXB7-GUMHX2OD.js"); const { diagram: diagram2 } = await import("./kanban-definition-3W4ZIXB7-H4KIKSB7.js");
return { id: id21, diagram: diagram2 }; return { id: id21, diagram: diagram2 };
}, "loader"); }, "loader");
var plugin19 = { var plugin19 = {
@ -812,7 +812,7 @@ var detector23 = __name((txt) => {
return /^\s*packet(-beta)?/.test(txt); return /^\s*packet(-beta)?/.test(txt);
}, "detector"); }, "detector");
var loader23 = __name(async () => { var loader23 = __name(async () => {
const { diagram: diagram2 } = await import("./diagram-S2PKOQOG-RM7ASWFZ.js"); const { diagram: diagram2 } = await import("./diagram-S2PKOQOG-D6F7ANDO.js");
return { id: id23, diagram: diagram2 }; return { id: id23, diagram: diagram2 };
}, "loader"); }, "loader");
var packet = { var packet = {
@ -825,7 +825,7 @@ var detector24 = __name((txt) => {
return /^\s*radar-beta/.test(txt); return /^\s*radar-beta/.test(txt);
}, "detector"); }, "detector");
var loader24 = __name(async () => { var loader24 = __name(async () => {
const { diagram: diagram2 } = await import("./diagram-QEK2KX5R-QLL2LDZJ.js"); const { diagram: diagram2 } = await import("./diagram-QEK2KX5R-KMPAAIQN.js");
return { id: id24, diagram: diagram2 }; return { id: id24, diagram: diagram2 };
}, "loader"); }, "loader");
var radar = { var radar = {
@ -838,7 +838,7 @@ var detector25 = __name((txt) => {
return /^\s*block(-beta)?/.test(txt); return /^\s*block(-beta)?/.test(txt);
}, "detector"); }, "detector");
var loader25 = __name(async () => { var loader25 = __name(async () => {
const { diagram: diagram2 } = await import("./blockDiagram-VD42YOAC-6W666JF2.js"); const { diagram: diagram2 } = await import("./blockDiagram-VD42YOAC-KZTUA5HK.js");
return { id: id25, diagram: diagram2 }; return { id: id25, diagram: diagram2 };
}, "loader"); }, "loader");
var plugin21 = { var plugin21 = {
@ -852,7 +852,7 @@ var detector26 = __name((txt) => {
return /^\s*architecture/.test(txt); return /^\s*architecture/.test(txt);
}, "detector"); }, "detector");
var loader26 = __name(async () => { var loader26 = __name(async () => {
const { diagram: diagram2 } = await import("./architectureDiagram-VXUJARFQ-7JNJRGGM.js"); const { diagram: diagram2 } = await import("./architectureDiagram-VXUJARFQ-WEBFVMSU.js");
return { id: id26, diagram: diagram2 }; return { id: id26, diagram: diagram2 };
}, "loader"); }, "loader");
var architecture = { var architecture = {
@ -866,7 +866,7 @@ var detector27 = __name((txt) => {
return /^\s*treemap/.test(txt); return /^\s*treemap/.test(txt);
}, "detector"); }, "detector");
var loader27 = __name(async () => { var loader27 = __name(async () => {
const { diagram: diagram2 } = await import("./diagram-PSM6KHXK-3GNQQWOU.js"); const { diagram: diagram2 } = await import("./diagram-PSM6KHXK-OYEWFDFJ.js");
return { id: id27, diagram: diagram2 }; return { id: id27, diagram: diagram2 };
}, "loader"); }, "loader");
var treemap = { var treemap = {

View File

@ -12,10 +12,10 @@ import "./chunk-FNEVJCCX.js";
import "./chunk-R33GOAXK.js"; import "./chunk-R33GOAXK.js";
import "./chunk-5SXTVVUG.js"; import "./chunk-5SXTVVUG.js";
import "./chunk-WHHJWK6B.js"; import "./chunk-WHHJWK6B.js";
import "./chunk-6SIVX7OU.js";
import { import {
selectSvgElement selectSvgElement
} from "./chunk-B5NQPFQG.js"; } from "./chunk-B5NQPFQG.js";
import "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js"; import "./chunk-NGEE2U2J.js";
import { import {
cleanAndMerge, cleanAndMerge,
@ -225,4 +225,4 @@ var diagram = {
export { export {
diagram diagram
}; };
//# sourceMappingURL=pieDiagram-ADFJNKIX-HTPFO6AD.js.map //# sourceMappingURL=pieDiagram-ADFJNKIX-QYG3H4AZ.js.map

View File

@ -10,9 +10,9 @@ import {
Graph Graph
} from "./chunk-MEGNL3BT.js"; } from "./chunk-MEGNL3BT.js";
import "./chunk-6SIVX7OU.js"; import "./chunk-6SIVX7OU.js";
import "./chunk-NGEE2U2J.js";
import "./chunk-PLWNSIKB.js"; import "./chunk-PLWNSIKB.js";
import "./chunk-LHH5RO5K.js"; import "./chunk-LHH5RO5K.js";
import "./chunk-NGEE2U2J.js";
import "./chunk-SOVT3CA7.js"; import "./chunk-SOVT3CA7.js";
import "./chunk-ZCTBDDTS.js"; import "./chunk-ZCTBDDTS.js";
import "./chunk-2HSIUWWJ.js"; import "./chunk-2HSIUWWJ.js";

View File

@ -1,8 +1,8 @@
{ {
"hash": "0356a024", "hash": "c91a5572",
"configHash": "9e47cd39", "configHash": "9e47cd39",
"lockfileHash": "77f35274", "lockfileHash": "610c0484",
"browserHash": "24be409e", "browserHash": "db821900",
"optimized": {}, "optimized": {},
"chunks": {} "chunks": {}
} }

View File

@ -0,0 +1,3 @@
{
"type": "module"
}

16
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@angular/build": "^20.3.0", "@angular/build": "^20.3.0",
"@angular/cdk": "^20.2.4",
"@angular/cli": "^20.3.0", "@angular/cli": "^20.3.0",
"@angular/common": "^20.3.0", "@angular/common": "^20.3.0",
"@angular/compiler": "^20.3.0", "@angular/compiler": "^20.3.0",
@ -514,6 +515,21 @@
"url": "https://github.com/sponsors/SuperchupuDev" "url": "https://github.com/sponsors/SuperchupuDev"
} }
}, },
"node_modules/@angular/cdk": {
"version": "20.2.5",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.5.tgz",
"integrity": "sha512-1cpR/5jeKXLR1D+PsEvRn0QhSWD3/AjtbugJF5nlx/7L90YXhNFCmNAxAkdFKSn4YIDoPwMHgvOpS7yb51wohQ==",
"license": "MIT",
"dependencies": {
"parse5": "^8.0.0",
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": "^20.0.0 || ^21.0.0",
"@angular/core": "^20.0.0 || ^21.0.0",
"rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/@angular/cli": { "node_modules/@angular/cli": {
"version": "20.3.2", "version": "20.3.2",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.2.tgz", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.2.tgz",

View File

@ -12,12 +12,14 @@
"dependencies": { "dependencies": {
"@angular/build": "^20.3.0", "@angular/build": "^20.3.0",
"@angular/cli": "^20.3.0", "@angular/cli": "^20.3.0",
"@angular/cdk": "^20.2.4",
"@angular/common": "^20.3.0", "@angular/common": "^20.3.0",
"@angular/compiler": "^20.3.0", "@angular/compiler": "^20.3.0",
"@angular/compiler-cli": "^20.3.0", "@angular/compiler-cli": "^20.3.0",
"@angular/core": "^20.3.0", "@angular/core": "^20.3.0",
"@angular/forms": "^20.3.1", "@angular/forms": "^20.3.1",
"@angular/platform-browser": "^20.3.0", "@angular/platform-browser": "^20.3.0",
"@angular/localize": "^20.3.0",
"@types/markdown-it": "^14.0.1", "@types/markdown-it": "^14.0.1",
"angular-calendar": "^0.32.0", "angular-calendar": "^0.32.0",
"chokidar": "^4.0.3", "chokidar": "^4.0.3",

View File

@ -1,5 +1,14 @@
<!-- ObsiViewer - Application optimisée pour mobile et desktop --> <!-- ObsiViewer - Application optimisée pour mobile et desktop -->
<main class="relative flex min-h-screen flex-col bg-obs-l-bg-main text-obs-l-text-main dark:bg-obs-d-bg-main dark:text-obs-d-text-main lg:flex-row lg:h-screen lg:overflow-hidden"> <main class="relative flex min-h-screen flex-col bg-obs-l-bg-main text-obs-l-text-main dark:bg-obs-d-bg-main dark:text-obs-d-text-main lg:flex-row lg:h-screen lg:overflow-hidden">
@if (isRawViewOpen()) {
<app-raw-view-overlay
[content]="rawNoteContent()"
[filename]="rawNoteFilename()"
[wrap]="isRawViewWrapped()"
(close)="closeRawView()"
(toggleWrap)="toggleRawWrap()"
></app-raw-view-overlay>
}
<!-- Navigation latérale desktop --> <!-- Navigation latérale desktop -->
<nav class="hidden w-14 flex-col items-center gap-4 border-r border-obs-l-border bg-obs-l-bg-main py-4 dark:border-obs-d-border dark:bg-obs-d-bg-main lg:flex"> <nav class="hidden w-14 flex-col items-center gap-4 border-r border-obs-l-border bg-obs-l-bg-main py-4 dark:border-obs-d-border dark:bg-obs-d-bg-main lg:flex">
<button <button
@ -318,6 +327,38 @@
</div> </div>
</div> </div>
<div class="hidden items-center gap-2 lg:flex"> <div class="hidden items-center gap-2 lg:flex">
<button
type="button"
class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary disabled:opacity-40 disabled:pointer-events-none"
(click)="toggleRawView()"
[disabled]="!selectedNote()"
aria-label="Afficher le markdown brut"
aria-keyshortcuts="Alt+R"
title="Vue brute (Alt+R)"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="h-5 w-5">
<path d="M8.5 8 5 12l3.5 4" />
<path d="M15.5 8 19 12l-3.5 4" />
<path d="M12.5 6 11 18" />
</svg>
<span class="sr-only">Alt+R</span>
</button>
<button
type="button"
class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary disabled:opacity-40 disabled:pointer-events-none"
(click)="downloadCurrentNote()"
[disabled]="!selectedNote()"
aria-label="Télécharger le fichier markdown"
aria-keyshortcuts="Alt+D"
title="Télécharger (Alt+D)"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="h-5 w-5">
<path d="M12 3v12" />
<path d="M7 11l5 5 5-5" />
<path d="M5 19h14" />
</svg>
<span class="sr-only">Alt+D</span>
</button>
<button <button
(click)="toggleTheme()" (click)="toggleTheme()"
class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary" class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary"
@ -345,6 +386,38 @@
</div> </div>
<div class="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between lg:gap-6"> <div class="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between lg:gap-6">
<div class="flex items-center gap-2 lg:hidden"> <div class="flex items-center gap-2 lg:hidden">
<button
type="button"
class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary disabled:opacity-40 disabled:pointer-events-none"
(click)="toggleRawView()"
[disabled]="!selectedNote()"
aria-label="Afficher le markdown brut"
aria-keyshortcuts="Alt+R"
title="Vue brute (Alt+R)"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="h-5 w-5">
<path d="M8.5 8 5 12l3.5 4" />
<path d="M15.5 8 19 12l-3.5 4" />
<path d="M12.5 6 11 18" />
</svg>
<span class="sr-only">Raccourci Alt+R</span>
</button>
<button
type="button"
class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary disabled:opacity-40 disabled:pointer-events-none"
(click)="downloadCurrentNote()"
[disabled]="!selectedNote()"
aria-label="Télécharger le fichier markdown"
aria-keyshortcuts="Alt+D"
title="Télécharger (Alt+D)"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="h-5 w-5">
<path d="M12 3v12" />
<path d="M7 11l5 5 5-5" />
<path d="M5 19h14" />
</svg>
<span class="sr-only">Raccourci Alt+D</span>
</button>
<button <button
(click)="toggleTheme()" (click)="toggleTheme()"
class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary" class="rounded-lg p-2 text-obs-l-text-muted transition hover:bg-obs-l-bg-secondary dark:text-obs-d-text-muted dark:hover:bg-obs-d-bg-secondary"

View File

@ -1,9 +1,11 @@
import { Component, ChangeDetectionStrategy, inject, signal, computed, effect, ElementRef, OnDestroy } from '@angular/core'; import { Component, ChangeDetectionStrategy, HostListener, inject, signal, computed, effect, ElementRef, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
// Services // Services
import { VaultService } from './services/vault.service'; import { VaultService } from './services/vault.service';
import { MarkdownService } from './services/markdown.service'; import { MarkdownService } from './services/markdown.service';
import { MarkdownViewerService } from './services/markdown-viewer.service';
import { DownloadService } from './core/services/download.service';
// Components // Components
import { FileExplorerComponent } from './components/file-explorer/file-explorer.component'; import { FileExplorerComponent } from './components/file-explorer/file-explorer.component';
@ -11,6 +13,7 @@ import { NoteViewerComponent, WikiLinkActivation } from './components/note-viewe
import { GraphViewComponent } from './components/graph-view/graph-view.component'; import { GraphViewComponent } from './components/graph-view/graph-view.component';
import { TagsViewComponent } from './components/tags-view/tags-view.component'; import { TagsViewComponent } from './components/tags-view/tags-view.component';
import { MarkdownCalendarComponent } from './components/markdown-calendar/markdown-calendar.component'; import { MarkdownCalendarComponent } from './components/markdown-calendar/markdown-calendar.component';
import { RawViewOverlayComponent } from './shared/overlays/raw-view-overlay.component';
// Types // Types
import { FileMetadata, Note, TagInfo, VaultNode } from './types'; import { FileMetadata, Note, TagInfo, VaultNode } from './types';
@ -31,6 +34,7 @@ interface TocEntry {
GraphViewComponent, GraphViewComponent,
TagsViewComponent, TagsViewComponent,
MarkdownCalendarComponent, MarkdownCalendarComponent,
RawViewOverlayComponent,
], ],
templateUrl: './app.component.simple.html', templateUrl: './app.component.simple.html',
styleUrls: ['./app.component.css'], styleUrls: ['./app.component.css'],
@ -39,6 +43,8 @@ interface TocEntry {
export class AppComponent implements OnDestroy { export class AppComponent implements OnDestroy {
private vaultService = inject(VaultService); private vaultService = inject(VaultService);
private markdownService = inject(MarkdownService); private markdownService = inject(MarkdownService);
private markdownViewerService = inject(MarkdownViewerService);
private downloadService = inject(DownloadService);
private elementRef = inject(ElementRef); private elementRef = inject(ElementRef);
// --- State Signals --- // --- State Signals ---
@ -51,10 +57,13 @@ export class AppComponent implements OnDestroy {
tableOfContents = signal<TocEntry[]>([]); tableOfContents = signal<TocEntry[]>([]);
leftSidebarWidth = signal<number>(288); leftSidebarWidth = signal<number>(288);
rightSidebarWidth = signal<number>(288); rightSidebarWidth = signal<number>(288);
isRawViewOpen = signal<boolean>(false);
isRawViewWrapped = signal<boolean>(true);
readonly LEFT_MIN_WIDTH = 220; readonly LEFT_MIN_WIDTH = 220;
readonly LEFT_MAX_WIDTH = 520; readonly LEFT_MAX_WIDTH = 520;
readonly RIGHT_MIN_WIDTH = 220; readonly RIGHT_MIN_WIDTH = 220;
readonly RIGHT_MAX_WIDTH = 520; readonly RIGHT_MAX_WIDTH = 520;
private rawViewTriggerElement: HTMLElement | null = null;
private viewportWidth = signal<number>(typeof window !== 'undefined' ? window.innerWidth : 0); private viewportWidth = signal<number>(typeof window !== 'undefined' ? window.innerWidth : 0);
private resizeHandler = () => { private resizeHandler = () => {
@ -98,6 +107,23 @@ export class AppComponent implements OnDestroy {
return this.markdownService.render(note.content, allNotes, note); return this.markdownService.render(note.content, allNotes, note);
}); });
rawNoteContent = computed<string>(() => {
const note = this.selectedNote();
if (!note) {
return '';
}
return note.rawContent ?? note.content ?? '';
});
rawNoteFilename = computed<string>(() => {
const note = this.selectedNote();
if (!note) {
return this.buildFallbackFilename();
}
const name = note.fileName?.trim();
return name && name.length > 0 ? name : this.buildFallbackFilename();
});
selectedNoteBreadcrumb = computed<string[]>(() => { selectedNoteBreadcrumb = computed<string[]>(() => {
const note = this.selectedNote(); const note = this.selectedNote();
if (!note) { if (!note) {
@ -195,14 +221,22 @@ export class AppComponent implements OnDestroy {
// Effect to generate Table of Contents when the note changes // Effect to generate Table of Contents when the note changes
effect(() => { effect(() => {
const note = this.selectedNote();
this.markdownViewerService.setCurrentNote(note ?? null);
const html = this.renderedNoteContent(); const html = this.renderedNoteContent();
if (html && this.selectedNote()) { if (html && note) {
this.generateToc(html); this.generateToc(html);
} else { } else {
this.tableOfContents.set([]); this.tableOfContents.set([]);
} }
}); });
effect(() => {
if (!this.selectedNote()) {
this.isRawViewOpen.set(false);
}
});
effect(() => { effect(() => {
const pending = this.pendingWikiNavigation(); const pending = this.pendingWikiNavigation();
const activeNoteId = this.selectedNoteId(); const activeNoteId = this.selectedNoteId();
@ -408,6 +442,7 @@ export class AppComponent implements OnDestroy {
this.vaultService.ensureFolderOpen(note.originalPath); this.vaultService.ensureFolderOpen(note.originalPath);
this.selectedNoteId.set(note.id); this.selectedNoteId.set(note.id);
this.markdownViewerService.setCurrentNote(note);
if (!this.isDesktopView() && this.activeView() === 'search') { if (!this.isDesktopView() && this.activeView() === 'search') {
this.isSidebarOpen.set(false); this.isSidebarOpen.set(false);
@ -421,6 +456,88 @@ export class AppComponent implements OnDestroy {
} }
} }
toggleRawView(): void {
if (!this.selectedNote()) {
return;
}
if (this.isRawViewOpen()) {
this.closeRawView();
} else {
this.openRawView();
}
}
openRawView(): void {
if (!this.selectedNote()) {
return;
}
if (typeof document !== 'undefined') {
this.rawViewTriggerElement = document.activeElement as HTMLElement | null;
}
this.isRawViewOpen.set(true);
}
closeRawView(): void {
this.isRawViewOpen.set(false);
const target = this.rawViewTriggerElement;
this.rawViewTriggerElement = null;
if (target && typeof target.focus === 'function') {
queueMicrotask(() => target.focus());
}
}
toggleRawWrap(): void {
this.isRawViewWrapped.update(value => !value);
}
downloadCurrentNote(): void {
const note = this.selectedNote();
if (!note) {
return;
}
const filename = this.rawNoteFilename();
const content = this.rawNoteContent();
if (!content) {
console.warn('[ObsiViewer] Aucun contenu à télécharger.');
return;
}
this.downloadService.downloadText(content, filename);
}
@HostListener('window:keydown', ['$event'])
handleGlobalKeydown(event: KeyboardEvent): void {
if (!event.altKey || event.repeat) {
return;
}
const key = event.key.toLowerCase();
if (key === 'r') {
if (!this.selectedNote()) {
return;
}
event.preventDefault();
this.toggleRawView();
}
if (key === 'd') {
if (!this.selectedNote()) {
return;
}
event.preventDefault();
this.downloadCurrentNote();
}
}
private buildFallbackFilename(): string {
const now = new Date();
const pad = (value: number) => value.toString().padStart(2, '0');
const year = now.getFullYear();
const month = pad(now.getMonth() + 1);
const day = pad(now.getDate());
const hours = pad(now.getHours());
const minutes = pad(now.getMinutes());
return `note-${year}${month}${day}-${hours}${minutes}.md`;
}
handleWikiLink(link: WikiLinkActivation): void { handleWikiLink(link: WikiLinkActivation): void {
const target = link.target?.trim(); const target = link.target?.trim();
if (!target) { if (!target) {

View File

@ -0,0 +1,127 @@
import { test } from 'node:test';
import { strict as assert } from 'node:assert/strict';
import { DownloadService } from './download.service.js';
const makeFakeDocument = () => {
const appendCalls: unknown[] = [];
const removeCalls: unknown[] = [];
const anchor = {
href: '',
download: '',
rel: '',
style: {} as Record<string, unknown>,
clickCount: 0,
click() {
this.clickCount += 1;
},
};
const documentMock = {
createElement(tag: string) {
if (tag !== 'a') {
throw new Error(`Unexpected element request: ${tag}`);
}
return anchor;
},
body: {
appendChild(node: unknown) {
appendCalls.push(node);
},
removeChild(node: unknown) {
removeCalls.push(node);
},
},
} as unknown as Document;
return { documentMock, anchor, appendCalls, removeCalls };
};
test('DownloadService downloads normalized UTF-8 content', async () => {
const service = new DownloadService();
const originalDocument = globalThis.document;
const NativeURL = globalThis.URL;
const { documentMock, anchor, appendCalls, removeCalls } = makeFakeDocument();
let lastBlob: Blob | null = null;
const revoked: string[] = [];
const urlMock = Object.assign(
function MockURL(url: string | URL, base?: string | URL) {
return new NativeURL(url as string, base as string);
},
{
prototype: NativeURL.prototype,
canParse: () => true,
parse: (url: string | URL, base?: string | URL) => new NativeURL(url as string, base as string),
createObjectURL(blob: Blob) {
lastBlob = blob;
return 'blob:test-url';
},
revokeObjectURL(url: string) {
revoked.push(url);
},
}
) as unknown as typeof URL;
globalThis.document = documentMock;
globalThis.URL = urlMock;
try {
service.downloadText('line1\r\nline2', 'note.md');
assert.equal(anchor.download, 'note.md');
assert.equal(anchor.rel, 'noopener');
assert.equal(anchor.clickCount, 1);
assert.equal(appendCalls.length, 1);
assert.equal(removeCalls.length, 1);
assert.equal(revoked.length, 1);
assert.ok(lastBlob, 'Blob should be created');
const blobContent = await lastBlob!.text();
assert.equal(blobContent, 'line1\nline2');
} finally {
globalThis.document = originalDocument;
globalThis.URL = NativeURL;
}
});
test('DownloadService warns when content is empty', () => {
const service = new DownloadService();
const originalDocument = globalThis.document;
const NativeURL = globalThis.URL;
const originalWarn = console.warn;
const { documentMock } = makeFakeDocument();
const urlMock = Object.assign(
function MockURL(url: string | URL, base?: string | URL) {
return new NativeURL(url as string, base as string);
},
{
prototype: NativeURL.prototype,
canParse: () => true,
parse: (url: string | URL, base?: string | URL) => new NativeURL(url as string, base as string),
createObjectURL() {
return 'blob:noop';
},
revokeObjectURL() {
// noop
},
}
) as unknown as typeof URL;
globalThis.document = documentMock;
globalThis.URL = urlMock;
let warned = false;
console.warn = () => {
warned = true;
};
try {
service.downloadText('', 'empty.md');
assert.equal(warned, true);
} finally {
console.warn = originalWarn;
globalThis.document = originalDocument;
globalThis.URL = NativeURL;
}
});

View File

@ -0,0 +1,29 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DownloadService {
downloadText(content: string, filename: string, mime = 'text/markdown;charset=utf-8'): void {
if (!content) {
console.warn('[DownloadService] Empty content provided for download.');
}
const normalized = content.replace(/\r\n/g, '\n');
const blob = new Blob([normalized], { type: mime });
const url = URL.createObjectURL(blob);
try {
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.rel = 'noopener';
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} finally {
setTimeout(() => URL.revokeObjectURL(url), 0);
}
}
}

View File

@ -0,0 +1,60 @@
import { test } from 'node:test';
import { strict as assert } from 'node:assert/strict';
import { firstValueFrom, skip, take } from 'rxjs';
import { MarkdownViewerService } from './markdown-viewer.service.js';
import type { Note } from '../../types.js';
test('MarkdownViewerService exposes current note streams', async () => {
const service = new MarkdownViewerService();
const note: Note = {
id: 'note-1',
title: 'Test note',
content: 'rendered content',
rawContent: 'raw markdown',
tags: [],
frontmatter: {},
backlinks: [],
mtime: Date.now(),
fileName: 'note-1.md',
filePath: '/note-1.md',
originalPath: 'note-1',
createdAt: undefined,
updatedAt: undefined,
};
service.setCurrentNote(note);
const observedNote = await firstValueFrom(service.getCurrentNote$().pipe(skip(1), take(1)));
const observedRaw = await firstValueFrom(service.getCurrentRaw$().pipe(skip(1), take(1)));
const observedFilename = await firstValueFrom(service.getCurrentFilename$().pipe(skip(1), take(1)));
assert.equal(observedNote?.id, note.id);
assert.equal(observedRaw, note.rawContent);
assert.equal(observedFilename, note.fileName);
});
test('MarkdownViewerService falls back to content when rawContent missing', async () => {
const service = new MarkdownViewerService();
const note: Note = {
id: 'note-2',
title: 'Another note',
content: 'fallback content',
rawContent: undefined as unknown as string,
tags: [],
frontmatter: {},
backlinks: [],
mtime: Date.now(),
fileName: 'note-2.md',
filePath: '/note-2.md',
originalPath: 'note-2',
createdAt: undefined,
updatedAt: undefined,
};
service.setCurrentNote(note);
const observedRaw = await firstValueFrom(service.getCurrentRaw$().pipe(skip(1), take(1)));
assert.equal(observedRaw, note.content);
});

View File

@ -0,0 +1,42 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { Note } from '../../types';
@Injectable({
providedIn: 'root'
})
export class MarkdownViewerService {
private readonly currentNoteSubject = new BehaviorSubject<Note | null>(null);
private readonly currentRawSubject = new BehaviorSubject<string>('');
private readonly currentFilenameSubject = new BehaviorSubject<string | null>(null);
getCurrentNote$(): Observable<Note | null> {
return this.currentNoteSubject.asObservable();
}
getCurrentRaw$(): Observable<string> {
return this.currentRawSubject.asObservable();
}
getCurrentFilename$(): Observable<string | null> {
return this.currentFilenameSubject.asObservable();
}
setCurrentNote(note: Note | null): void {
if (!note) {
this.clear();
return;
}
this.currentNoteSubject.next(note);
const raw = typeof note.rawContent === 'string' ? note.rawContent : note.content;
this.currentRawSubject.next(raw ?? '');
this.currentFilenameSubject.next(note.fileName ?? null);
}
clear(): void {
this.currentNoteSubject.next(null);
this.currentRawSubject.next('');
this.currentFilenameSubject.next(null);
}
}

View File

@ -0,0 +1 @@
export { MarkdownViewerService } from '../core/services/markdown-viewer.service';

View File

@ -237,7 +237,8 @@ export class VaultService implements OnDestroy {
let detectedHomeVaultName: string | null = null; let detectedHomeVaultName: string | null = null;
for (const apiNote of notes) { for (const apiNote of notes) {
const { frontmatter, body } = this.parseFrontmatter(apiNote.content); const normalizedRaw = apiNote.content.replace(/\r\n/g, '\n');
const { frontmatter, body } = this.parseFrontmatter(normalizedRaw);
const derivedTitle = this.extractTitle(body, apiNote.id); const derivedTitle = this.extractTitle(body, apiNote.id);
const noteTitle = frontmatter.title || apiNote.title || derivedTitle; const noteTitle = frontmatter.title || apiNote.title || derivedTitle;
@ -265,6 +266,7 @@ export class VaultService implements OnDestroy {
id: apiNote.id, id: apiNote.id,
title: noteTitle, title: noteTitle,
content: body, content: body,
rawContent: normalizedRaw,
tags: Array.from(tagSet), tags: Array.from(tagSet),
frontmatter, frontmatter,
backlinks: [], backlinks: [],

View File

@ -0,0 +1,62 @@
<div class="raw-overlay__backdrop" (click)="onBackdropClick()">
<div
class="raw-overlay__panel"
cdkTrapFocus
[cdkTrapFocusAutoCapture]="true"
(click)="onPanelClick($event)"
role="dialog"
aria-modal="true"
[attr.aria-labelledby]="headingId"
>
<header class="raw-overlay__header">
<div class="raw-overlay__title-group">
<h2 class="raw-overlay__title" [id]="headingId">Vue brute</h2>
<p class="raw-overlay__subtitle" *ngIf="filename">{{ filename }}</p>
</div>
<div class="raw-overlay__actions">
<button
type="button"
class="raw-overlay__action"
(click)="copyAll()"
aria-label="Copier tout"
>
Copier tout
</button>
<button
type="button"
class="raw-overlay__action"
(click)="onToggleWrap()"
[attr.aria-pressed]="wrap"
[attr.aria-label]="wrapButtonAriaLabel"
>
@if (wrap) {
<span>Retour auto désactivé</span>
} @else {
<span>Retour auto activé</span>
}
</button>
<button
type="button"
class="raw-overlay__action raw-overlay__action--primary"
(click)="close.emit()"
aria-label="Fermer la vue brute"
>
Fermer
</button>
</div>
</header>
<div class="raw-overlay__feedback" *ngIf="feedback() as message" role="status" aria-live="polite">
{{ message }}
</div>
<section
class="raw-overlay__content"
[class.raw-overlay__content--pre-wrap]="wrap"
tabindex="0"
aria-label="Zone de contenu markdown brut"
>
<pre>{{ content }}</pre>
</section>
</div>
</div>

View File

@ -0,0 +1,187 @@
@use 'sass:color';
:host {
--raw-overlay-bg: #f7fdfb;
--raw-overlay-border: rgba(14, 116, 144, 0.18);
--raw-overlay-text: #0f172a;
--raw-overlay-accent: rgba(14, 116, 144, 0.14);
--raw-overlay-accent-strong: rgba(14, 116, 144, 0.22);
--raw-overlay-action-text: #0f766e;
--raw-overlay-action-border: rgba(13, 148, 136, 0.45);
--raw-overlay-action-bg: rgba(13, 148, 136, 0.12);
--raw-overlay-action-bg-hover: rgba(13, 148, 136, 0.2);
--raw-overlay-action-border-hover: rgba(13, 148, 136, 0.6);
--raw-overlay-primary-bg: rgba(21, 128, 61, 0.18);
--raw-overlay-primary-border: rgba(21, 128, 61, 0.55);
--raw-overlay-primary-bg-hover: rgba(21, 128, 61, 0.28);
--raw-overlay-primary-text: #166534;
--raw-overlay-primary-border-hover: rgba(21, 128, 61, 0.7);
}
:host-context(.dark) {
--raw-overlay-bg: rgba(32, 33, 35, 0.96); /* #202123 */
--raw-overlay-border: rgba(99, 102, 106, 0.35);
--raw-overlay-text: #e5e7eb;
--raw-overlay-accent: rgba(45, 46, 48, 0.88); /* #2D2E30 */
--raw-overlay-accent-strong: rgba(61, 62, 65, 0.92);
--raw-overlay-action-text: #34d399;
--raw-overlay-action-border: rgba(52, 211, 153, 0.35);
--raw-overlay-action-bg: rgba(12, 84, 68, 0.32);
--raw-overlay-action-bg-hover: rgba(16, 185, 129, 0.36);
--raw-overlay-action-border-hover: rgba(52, 211, 153, 0.55);
--raw-overlay-primary-bg: rgba(22, 163, 74, 0.32);
--raw-overlay-primary-border: rgba(22, 163, 74, 0.55);
--raw-overlay-primary-bg-hover: rgba(22, 163, 74, 0.42);
--raw-overlay-primary-text: #bbf7d0;
--raw-overlay-primary-border-hover: rgba(22, 163, 74, 0.75);
}
.raw-overlay__backdrop {
position: fixed;
inset: 0;
z-index: 60;
display: flex;
justify-content: center;
align-items: flex-start;
padding: clamp(1rem, 2vw, 2rem);
background-color: rgba(15, 23, 42, 0.55);
backdrop-filter: blur(6px);
}
.raw-overlay__panel {
width: min(960px, calc(100vw - clamp(2rem, 4vw, 4rem)));
max-height: calc(100vh - clamp(2rem, 4vw, 4rem));
display: flex;
flex-direction: column;
border-radius: 1.25rem;
border: 1px solid var(--raw-overlay-border);
background: var(--raw-overlay-bg);
color: var(--raw-overlay-text);
box-shadow: 0 28px 52px -16px rgba(15, 23, 42, 0.55);
overflow: hidden;
}
.raw-overlay__header {
display: flex;
flex-wrap: wrap;
gap: 1rem;
align-items: center;
padding: 1.5rem clamp(1.25rem, 2vw, 2rem);
border-bottom: 1px solid rgba(148, 163, 184, 0.12);
}
.raw-overlay__title-group {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.raw-overlay__title {
margin: 0;
font-size: clamp(1.25rem, 2vw, 1.5rem);
font-weight: 700;
}
.raw-overlay__subtitle {
margin: 0;
font-size: 0.875rem;
opacity: 0.7;
}
.raw-overlay__actions {
display: inline-flex;
flex-wrap: wrap;
gap: 0.65rem;
}
.raw-overlay__action {
appearance: none;
border: 1px solid var(--raw-overlay-action-border);
border-radius: 9999px;
padding: 0.45rem 1.1rem;
background: var(--raw-overlay-action-bg);
color: var(--raw-overlay-action-text);
font-size: 0.875rem;
font-weight: 600;
letter-spacing: 0.02em;
transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.raw-overlay__action:hover,
.raw-overlay__action:focus-visible {
border-color: var(--raw-overlay-action-border-hover);
background: var(--raw-overlay-action-bg-hover);
color: var(--raw-overlay-action-text);
transform: translateY(-1px);
}
.raw-overlay__action--primary {
background: var(--raw-overlay-primary-bg);
border-color: var(--raw-overlay-primary-border);
color: var(--raw-overlay-primary-text);
}
.raw-overlay__action--primary:hover,
.raw-overlay__action--primary:focus-visible {
background: var(--raw-overlay-primary-bg-hover);
border-color: var(--raw-overlay-primary-border-hover);
}
.raw-overlay__feedback {
margin: 0.75rem clamp(1.25rem, 2vw, 2rem) 0;
padding: 0.6rem 1rem;
border-radius: 0.75rem;
background: rgba(21, 128, 61, 0.18);
color: rgba(22, 163, 74, 0.9);
font-size: 0.85rem;
font-weight: 600;
}
:host-context(.dark) .raw-overlay__feedback {
background: rgba(34, 197, 94, 0.25);
color: rgba(190, 242, 100, 0.95);
}
.raw-overlay__content {
flex: 1;
margin: clamp(1rem, 2vw, 1.5rem) clamp(1.25rem, 2vw, 2rem) clamp(1.5rem, 3vw, 2rem);
padding: clamp(1rem, 2vw, 1.5rem);
border-radius: 1rem;
background: var(--raw-overlay-accent);
border: 1px solid var(--raw-overlay-border);
overflow: auto;
font-family: ui-monospace, SFMono-Regular, SFMono, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
font-size: 0.95rem;
line-height: 1.45;
white-space: pre;
color: inherit;
}
.raw-overlay__content pre {
margin: 0;
}
.raw-overlay__content--pre-wrap {
white-space: pre-wrap;
word-break: break-word;
}
:host-context(.dark) .raw-overlay__content {
background: var(--raw-overlay-accent);
border-color: var(--raw-overlay-accent-strong);
}
@media (max-width: 768px) {
.raw-overlay__panel {
border-radius: 1rem;
}
.raw-overlay__actions {
width: 100%;
justify-content: flex-start;
}
.raw-overlay__content {
max-height: calc(100vh - 14rem);
}
}

View File

@ -0,0 +1,75 @@
import { test } from 'node:test';
import { strict as assert } from 'node:assert/strict';
import { RawViewOverlayComponent } from './raw-view-overlay.component.js';
test('wrap button aria label reflects current state', () => {
const component = new RawViewOverlayComponent();
component.wrap = true;
assert.equal(component.wrapButtonAriaLabel, 'Désactiver le retour automatique à la ligne');
component.wrap = false;
assert.equal(component.wrapButtonAriaLabel, 'Activer le retour automatique à la ligne');
});
test('toggle wrap emits through output', () => {
const component = new RawViewOverlayComponent();
let emitted = false;
component.toggleWrap.subscribe(() => {
emitted = true;
});
component.onToggleWrap();
assert.equal(emitted, true);
});
test('close event emits on backdrop click and Esc key', () => {
const component = new RawViewOverlayComponent();
let closeCount = 0;
component.close.subscribe(() => {
closeCount += 1;
});
component.onBackdropClick();
component.handleKeydown(new KeyboardEvent('keydown', { key: 'Escape' }));
assert.equal(closeCount, 2);
});
test('copyAll uses clipboard when available', async () => {
const component = new RawViewOverlayComponent();
component.content = 'Example content';
const originalNavigator = globalThis.navigator;
let captured = '';
const mockNavigator = Object.assign(
Object.create(originalNavigator ? Object.getPrototypeOf(originalNavigator) : {}),
originalNavigator ?? {},
{
clipboard: {
writeText: async (text: string) => {
captured = text;
},
},
},
) as Navigator;
Object.defineProperty(globalThis, 'navigator', {
configurable: true,
value: mockNavigator,
});
try {
await component.copyAll();
assert.equal(captured, 'Example content');
assert.equal(component.feedback(), component.copySuccessMessage);
} finally {
if (originalNavigator) {
Object.defineProperty(globalThis, 'navigator', {
configurable: true,
value: originalNavigator,
});
} else {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
delete (globalThis as any).navigator;
}
}
});

View File

@ -0,0 +1,101 @@
import { CommonModule } from '@angular/common';
import { CdkTrapFocus } from '@angular/cdk/a11y';
import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, OnDestroy, Output, signal } from '@angular/core';
@Component({
selector: 'app-raw-view-overlay',
standalone: true,
imports: [CommonModule, CdkTrapFocus],
templateUrl: './raw-view-overlay.component.html',
styleUrls: ['./raw-view-overlay.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RawViewOverlayComponent implements OnDestroy {
@Input({ required: true }) content = '';
@Input() filename: string | null = null;
@Input() wrap = true;
@Output() close = new EventEmitter<void>();
@Output() toggleWrap = new EventEmitter<void>();
readonly feedback = signal<string | null>(null);
private feedbackTimer: ReturnType<typeof setTimeout> | null = null;
readonly headingId = 'raw-view-overlay-title';
readonly copySuccessMessage = 'Copié dans le presse-papiers';
readonly copyErrorMessage = 'Copie impossible';
private readonly wrapDisableLabel = 'Désactiver le retour automatique à la ligne';
private readonly wrapEnableLabel = 'Activer le retour automatique à la ligne';
get wrapButtonAriaLabel(): string {
return this.wrap ? this.wrapDisableLabel : this.wrapEnableLabel;
}
@HostListener('document:keydown', ['$event'])
handleKeydown(event: KeyboardEvent): void {
if (event.key === 'Escape') {
event.preventDefault();
this.close.emit();
}
}
onBackdropClick(): void {
this.close.emit();
}
onPanelClick(event: MouseEvent): void {
event.stopPropagation();
}
onToggleWrap(): void {
this.toggleWrap.emit();
}
async copyAll(): Promise<void> {
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(this.content);
} else {
this.fallbackCopy(this.content);
}
this.showFeedback(this.copySuccessMessage);
} catch (error) {
console.error('[RawViewOverlay] Unable to copy content', error);
this.showFeedback(this.copyErrorMessage);
}
}
ngOnDestroy(): void {
if (this.feedbackTimer) {
clearTimeout(this.feedbackTimer);
this.feedbackTimer = null;
}
}
private fallbackCopy(text: string): void {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
textarea.style.pointerEvents = 'none';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
try {
document.execCommand('copy');
} finally {
document.body.removeChild(textarea);
}
}
private showFeedback(message: string): void {
this.feedback.set(message);
if (this.feedbackTimer) {
clearTimeout(this.feedbackTimer);
}
this.feedbackTimer = setTimeout(() => {
this.feedback.set(null);
this.feedbackTimer = null;
}, 2400);
}
}

View File

@ -163,6 +163,18 @@
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
&:root { &:root {
--external-link: #6366f1; --external-link: #6366f1;
--external-link-hover: #4338ca; --external-link-hover: #4338ca;

View File

@ -4,6 +4,7 @@ export interface Note {
id: string; id: string;
title: string; title: string;
content: string; content: string;
rawContent: string;
tags: string[]; tags: string[];
frontmatter: { [key: string]: any }; frontmatter: { [key: string]: any };
backlinks: string[]; backlinks: string[];