vimd 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +17 -75
- package/dist/core/folder-mode/assets/folder-mode.js +35 -5
- package/dist/core/parser/pandoc-parser.d.ts +5 -0
- package/dist/core/parser/pandoc-parser.d.ts.map +1 -1
- package/dist/core/parser/pandoc-parser.js +31 -2
- package/dist/core/single-file-server.d.ts +87 -0
- package/dist/core/single-file-server.d.ts.map +1 -0
- package/dist/core/single-file-server.js +295 -0
- package/dist/filters/latex-metadata.lua +135 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/templates/default.html +7 -3
- package/dist/templates/folder-mode.html +7 -3
- package/dist/templates/single-file.html +259 -0
- package/dist/themes/styles/academic.css +99 -0
- package/dist/themes/styles/dark.css +94 -0
- package/dist/themes/styles/github.css +94 -0
- package/dist/themes/styles/minimal.css +96 -0
- package/dist/themes/styles/technical.css +96 -0
- package/dist/utils/session-manager.d.ts.map +1 -1
- package/dist/utils/session-manager.js +4 -3
- package/filters/latex-metadata.lua +135 -0
- package/package.json +2 -1
- package/templates/default.html +7 -3
- package/templates/folder-mode.html +7 -3
- package/templates/single-file.html +259 -0
- package/dist/core/websocket-server.d.ts +0 -52
- package/dist/core/websocket-server.d.ts.map +0 -1
- package/dist/core/websocket-server.js +0 -221
- package/dist/templates/standalone.html +0 -57
- package/templates/standalone.html +0 -57
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
-- filters/latex-metadata.lua
|
|
2
|
+
-- Extract metadata from AGU journal format LaTeX and insert as HTML at document start
|
|
3
|
+
|
|
4
|
+
local extracted = {
|
|
5
|
+
title = nil,
|
|
6
|
+
authors = nil,
|
|
7
|
+
affiliations = {},
|
|
8
|
+
corresponding = nil,
|
|
9
|
+
keypoints = {},
|
|
10
|
+
abstract = nil
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
-- Convert \affil{n} to <sup>n</sup>
|
|
14
|
+
local function process_affil(text)
|
|
15
|
+
return text:gsub('\\affil{(%d+)}', '<sup>%1</sup>')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
-- Extract title and abstract from Meta (pandoc processes these as metadata)
|
|
19
|
+
function Meta(meta)
|
|
20
|
+
if meta.title then
|
|
21
|
+
extracted.title = pandoc.utils.stringify(meta.title)
|
|
22
|
+
end
|
|
23
|
+
if meta.abstract then
|
|
24
|
+
extracted.abstract = pandoc.utils.stringify(meta.abstract)
|
|
25
|
+
end
|
|
26
|
+
return meta
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
function RawBlock(el)
|
|
30
|
+
if el.format:match('latex') or el.format:match('tex') then
|
|
31
|
+
local text = el.text
|
|
32
|
+
|
|
33
|
+
-- Extract \authors{...}
|
|
34
|
+
local authors = text:match('\\authors%s*{(.+)}')
|
|
35
|
+
if authors then
|
|
36
|
+
extracted.authors = process_affil(authors)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
-- Extract \affiliation{n}{...}
|
|
40
|
+
local affil_num, affil_text = text:match('\\affiliation%s*{(%d+)}%s*{(.+)}')
|
|
41
|
+
if affil_num and affil_text then
|
|
42
|
+
extracted.affiliations[tonumber(affil_num)] = affil_text
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
-- Extract \correspondingauthor{name}{email}
|
|
46
|
+
local corr_name, corr_email = text:match('\\correspondingauthor%s*{([^}]+)}%s*{([^}]+)}')
|
|
47
|
+
if corr_name and corr_email then
|
|
48
|
+
extracted.corresponding = { name = corr_name, email = corr_email }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
-- Extract \begin{keypoints}...\end{keypoints}
|
|
52
|
+
local keypoints_content = text:match('\\begin{keypoints}(.-)\\end{keypoints}')
|
|
53
|
+
if keypoints_content then
|
|
54
|
+
-- Extract each \item content
|
|
55
|
+
for item in keypoints_content:gmatch('\\item%s*([^\n]+)') do
|
|
56
|
+
-- Trim whitespace
|
|
57
|
+
item = item:gsub('^%s*', ''):gsub('%s*$', '')
|
|
58
|
+
if item ~= '' then
|
|
59
|
+
table.insert(extracted.keypoints, item)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
return el
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
function Pandoc(doc)
|
|
68
|
+
local header_blocks = {}
|
|
69
|
+
|
|
70
|
+
-- 1. Title
|
|
71
|
+
if extracted.title then
|
|
72
|
+
table.insert(header_blocks, pandoc.RawBlock('html',
|
|
73
|
+
'<h1 class="vimd-title">' .. extracted.title .. '</h1>'))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
-- 2. Authors
|
|
77
|
+
if extracted.authors then
|
|
78
|
+
table.insert(header_blocks, pandoc.RawBlock('html',
|
|
79
|
+
'<div class="vimd-authors">' .. extracted.authors .. '</div>'))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
-- 3. Affiliations
|
|
83
|
+
if next(extracted.affiliations) then
|
|
84
|
+
local affil_html = '<div class="vimd-affiliations">'
|
|
85
|
+
-- Sort by affiliation number
|
|
86
|
+
local sorted_keys = {}
|
|
87
|
+
for k in pairs(extracted.affiliations) do
|
|
88
|
+
table.insert(sorted_keys, k)
|
|
89
|
+
end
|
|
90
|
+
table.sort(sorted_keys)
|
|
91
|
+
for _, i in ipairs(sorted_keys) do
|
|
92
|
+
local affil = extracted.affiliations[i]
|
|
93
|
+
affil_html = affil_html .. '<div class="vimd-affiliation"><sup>' .. i .. '</sup> ' .. affil .. '</div>'
|
|
94
|
+
end
|
|
95
|
+
affil_html = affil_html .. '</div>'
|
|
96
|
+
table.insert(header_blocks, pandoc.RawBlock('html', affil_html))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
-- 4. Corresponding author
|
|
100
|
+
if extracted.corresponding then
|
|
101
|
+
local corr_html = '<div class="vimd-corresponding">Corresponding author: '
|
|
102
|
+
.. extracted.corresponding.name .. ' (<a href="mailto:' .. extracted.corresponding.email .. '">'
|
|
103
|
+
.. extracted.corresponding.email .. '</a>)</div>'
|
|
104
|
+
table.insert(header_blocks, pandoc.RawBlock('html', corr_html))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
-- 5. Key Points
|
|
108
|
+
if #extracted.keypoints > 0 then
|
|
109
|
+
local kp_html = '<div class="vimd-keypoints"><h2>Key Points</h2><ul>'
|
|
110
|
+
for _, item in ipairs(extracted.keypoints) do
|
|
111
|
+
kp_html = kp_html .. '<li>' .. item .. '</li>'
|
|
112
|
+
end
|
|
113
|
+
kp_html = kp_html .. '</ul></div>'
|
|
114
|
+
table.insert(header_blocks, pandoc.RawBlock('html', kp_html))
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
-- 6. Abstract
|
|
118
|
+
if extracted.abstract then
|
|
119
|
+
table.insert(header_blocks, pandoc.RawBlock('html',
|
|
120
|
+
'<div class="vimd-abstract"><h2>Abstract</h2><p>' .. extracted.abstract .. '</p></div>'))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
-- Insert at document start (in reverse order to maintain order)
|
|
124
|
+
for i = #header_blocks, 1, -1 do
|
|
125
|
+
table.insert(doc.blocks, 1, header_blocks[i])
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
return doc
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
{ Meta = Meta },
|
|
133
|
+
{ RawBlock = RawBlock },
|
|
134
|
+
{ Pandoc = Pandoc }
|
|
135
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ export type { VimdConfig, ThemeInfo } from './config/types.js';
|
|
|
2
2
|
export { defineConfig } from './config/types.js';
|
|
3
3
|
export { MarkdownConverter } from './core/converter.js';
|
|
4
4
|
export { FileWatcher } from './core/watcher.js';
|
|
5
|
-
export { WebSocketServer } from './core/websocket-server.js';
|
|
6
5
|
export { PandocDetector } from './core/pandoc-detector.js';
|
|
7
6
|
export { ThemeManager } from './themes/index.js';
|
|
8
7
|
export { ConfigLoader } from './config/loader.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,6 @@ export { defineConfig } from './config/types.js';
|
|
|
4
4
|
// ==================== コア機能エクスポート ====================
|
|
5
5
|
export { MarkdownConverter } from './core/converter.js';
|
|
6
6
|
export { FileWatcher } from './core/watcher.js';
|
|
7
|
-
export { WebSocketServer } from './core/websocket-server.js';
|
|
8
7
|
export { PandocDetector } from './core/pandoc-detector.js';
|
|
9
8
|
// ==================== テーマ管理エクスポート ====================
|
|
10
9
|
export { ThemeManager } from './themes/index.js';
|
|
@@ -29,11 +29,15 @@
|
|
|
29
29
|
</style>
|
|
30
30
|
<script>
|
|
31
31
|
MathJax = {
|
|
32
|
-
loader: {load: ['[tex]/bussproofs', '[tex]/ams', '[tex]/physics']},
|
|
32
|
+
loader: {load: ['[tex]/bussproofs', '[tex]/ams', '[tex]/physics', '[tex]/boldsymbol']},
|
|
33
33
|
tex: {
|
|
34
|
-
packages: {'[+]': ['bussproofs', 'ams', 'physics']},
|
|
34
|
+
packages: {'[+]': ['bussproofs', 'ams', 'physics', 'boldsymbol']},
|
|
35
35
|
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
|
36
|
-
displayMath: [['$$', '$$'], ['\\[', '\\]']]
|
|
36
|
+
displayMath: [['$$', '$$'], ['\\[', '\\]']],
|
|
37
|
+
tags: 'ams',
|
|
38
|
+
macros: {
|
|
39
|
+
bm: ['\\boldsymbol{#1}', 1]
|
|
40
|
+
}
|
|
37
41
|
}
|
|
38
42
|
};
|
|
39
43
|
</script>
|
|
@@ -27,11 +27,15 @@
|
|
|
27
27
|
</style>
|
|
28
28
|
<script>
|
|
29
29
|
MathJax = {
|
|
30
|
-
loader: {load: ['[tex]/bussproofs', '[tex]/ams', '[tex]/physics']},
|
|
30
|
+
loader: {load: ['[tex]/bussproofs', '[tex]/ams', '[tex]/physics', '[tex]/boldsymbol']},
|
|
31
31
|
tex: {
|
|
32
|
-
packages: {'[+]': ['bussproofs', 'ams', 'physics']},
|
|
32
|
+
packages: {'[+]': ['bussproofs', 'ams', 'physics', 'boldsymbol']},
|
|
33
33
|
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
|
34
|
-
displayMath: [['$$', '$$'], ['\\[', '\\]']]
|
|
34
|
+
displayMath: [['$$', '$$'], ['\\[', '\\]']],
|
|
35
|
+
tags: 'ams',
|
|
36
|
+
macros: {
|
|
37
|
+
bm: ['\\boldsymbol{#1}', 1]
|
|
38
|
+
}
|
|
35
39
|
}
|
|
36
40
|
};
|
|
37
41
|
</script>
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="ja">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<meta name="generator" content="vimd">
|
|
7
|
+
<title>{{title}} - vimd</title>
|
|
8
|
+
<style>
|
|
9
|
+
{{theme_css}}
|
|
10
|
+
</style>
|
|
11
|
+
<style>
|
|
12
|
+
/* Single file mode styles */
|
|
13
|
+
* {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
html, body {
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
body {
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.vimd-single-container {
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100vh;
|
|
31
|
+
overflow-y: auto;
|
|
32
|
+
overflow-x: hidden;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.vimd-single-content {
|
|
36
|
+
padding: 32px;
|
|
37
|
+
max-width: 720px;
|
|
38
|
+
margin: 0 auto;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.vimd-single-content pre,
|
|
42
|
+
.vimd-single-content table {
|
|
43
|
+
overflow-x: auto;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Connection status indicator */
|
|
47
|
+
.vimd-connection-status {
|
|
48
|
+
position: fixed;
|
|
49
|
+
bottom: 16px;
|
|
50
|
+
right: 16px;
|
|
51
|
+
padding: 8px 12px;
|
|
52
|
+
background: rgba(0, 0, 0, 0.7);
|
|
53
|
+
color: #fff;
|
|
54
|
+
font-size: 12px;
|
|
55
|
+
border-radius: 4px;
|
|
56
|
+
opacity: 0;
|
|
57
|
+
transition: opacity 0.3s;
|
|
58
|
+
pointer-events: none;
|
|
59
|
+
z-index: 1000;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.vimd-connection-status.visible {
|
|
63
|
+
opacity: 1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.vimd-connection-status.error {
|
|
67
|
+
background: rgba(211, 47, 47, 0.9);
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
70
|
+
{{#if math_enabled}}
|
|
71
|
+
<style>
|
|
72
|
+
/* Block math centering */
|
|
73
|
+
.math-block {
|
|
74
|
+
display: block;
|
|
75
|
+
text-align: center;
|
|
76
|
+
margin: 1em 0;
|
|
77
|
+
}
|
|
78
|
+
mjx-container[display="true"] {
|
|
79
|
+
display: block !important;
|
|
80
|
+
text-align: center !important;
|
|
81
|
+
margin: 1em 0 !important;
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
84
|
+
<script>
|
|
85
|
+
MathJax = {
|
|
86
|
+
loader: {load: ['[tex]/bussproofs', '[tex]/ams', '[tex]/physics', '[tex]/boldsymbol']},
|
|
87
|
+
tex: {
|
|
88
|
+
packages: {'[+]': ['bussproofs', 'ams', 'physics', 'boldsymbol']},
|
|
89
|
+
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
|
90
|
+
displayMath: [['$$', '$$'], ['\\[', '\\]']],
|
|
91
|
+
tags: 'ams',
|
|
92
|
+
macros: {
|
|
93
|
+
bm: ['\\boldsymbol{#1}', 1]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
</script>
|
|
98
|
+
<script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
|
99
|
+
{{/if}}
|
|
100
|
+
</head>
|
|
101
|
+
<body>
|
|
102
|
+
<div class="vimd-single-container" id="container">
|
|
103
|
+
<article class="vimd-single-content markdown-body" id="content">
|
|
104
|
+
<!-- Content will be loaded via WebSocket -->
|
|
105
|
+
</article>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div class="vimd-connection-status" id="status"></div>
|
|
109
|
+
|
|
110
|
+
<script>
|
|
111
|
+
(function() {
|
|
112
|
+
'use strict';
|
|
113
|
+
|
|
114
|
+
var container = document.getElementById('container');
|
|
115
|
+
var content = document.getElementById('content');
|
|
116
|
+
var status = document.getElementById('status');
|
|
117
|
+
var ws = null;
|
|
118
|
+
var reconnectAttempts = 0;
|
|
119
|
+
var maxReconnectAttempts = 10;
|
|
120
|
+
var reconnectDelay = 1000;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Show connection status message
|
|
124
|
+
*/
|
|
125
|
+
function showStatus(message, isError) {
|
|
126
|
+
status.textContent = message;
|
|
127
|
+
status.classList.toggle('error', isError);
|
|
128
|
+
status.classList.add('visible');
|
|
129
|
+
|
|
130
|
+
// Hide after 3 seconds for non-error messages
|
|
131
|
+
if (!isError) {
|
|
132
|
+
setTimeout(function() {
|
|
133
|
+
status.classList.remove('visible');
|
|
134
|
+
}, 3000);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Hide connection status
|
|
140
|
+
*/
|
|
141
|
+
function hideStatus() {
|
|
142
|
+
status.classList.remove('visible');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Connect to WebSocket server
|
|
147
|
+
*/
|
|
148
|
+
function connect() {
|
|
149
|
+
var protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
150
|
+
ws = new WebSocket(protocol + '//' + location.host);
|
|
151
|
+
|
|
152
|
+
ws.onopen = function() {
|
|
153
|
+
console.log('[vimd] WebSocket connected');
|
|
154
|
+
reconnectAttempts = 0;
|
|
155
|
+
hideStatus();
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
ws.onmessage = function(event) {
|
|
159
|
+
try {
|
|
160
|
+
var msg = JSON.parse(event.data);
|
|
161
|
+
handleMessage(msg);
|
|
162
|
+
} catch (e) {
|
|
163
|
+
console.error('[vimd] Failed to parse message:', e);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
ws.onclose = function() {
|
|
168
|
+
console.log('[vimd] WebSocket disconnected');
|
|
169
|
+
|
|
170
|
+
if (reconnectAttempts < maxReconnectAttempts) {
|
|
171
|
+
reconnectAttempts++;
|
|
172
|
+
showStatus('Reconnecting... (' + reconnectAttempts + '/' + maxReconnectAttempts + ')', false);
|
|
173
|
+
setTimeout(connect, reconnectDelay);
|
|
174
|
+
} else {
|
|
175
|
+
showStatus('Connection lost. Please refresh the page.', true);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
ws.onerror = function(error) {
|
|
180
|
+
console.error('[vimd] WebSocket error:', error);
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Handle incoming WebSocket message
|
|
186
|
+
*/
|
|
187
|
+
function handleMessage(msg) {
|
|
188
|
+
switch (msg.type) {
|
|
189
|
+
case 'content':
|
|
190
|
+
updateContent(msg.data.html);
|
|
191
|
+
if (msg.data.title) {
|
|
192
|
+
document.title = msg.data.title + ' - vimd';
|
|
193
|
+
}
|
|
194
|
+
break;
|
|
195
|
+
|
|
196
|
+
case 'error':
|
|
197
|
+
showError(msg.data.message);
|
|
198
|
+
break;
|
|
199
|
+
|
|
200
|
+
default:
|
|
201
|
+
console.warn('[vimd] Unknown message type:', msg.type);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Update content with scroll position preservation
|
|
207
|
+
*/
|
|
208
|
+
function updateContent(html) {
|
|
209
|
+
// Save scroll position
|
|
210
|
+
var scrollTop = container.scrollTop;
|
|
211
|
+
|
|
212
|
+
// Update content
|
|
213
|
+
content.innerHTML = html;
|
|
214
|
+
|
|
215
|
+
// Re-render MathJax if available
|
|
216
|
+
if (window.MathJax && window.MathJax.typeset) {
|
|
217
|
+
// MathJax.typeset returns a promise in v3
|
|
218
|
+
var promise = window.MathJax.typeset([content]);
|
|
219
|
+
|
|
220
|
+
// Restore scroll position after MathJax completes
|
|
221
|
+
if (promise && promise.then) {
|
|
222
|
+
promise.then(function() {
|
|
223
|
+
container.scrollTop = scrollTop;
|
|
224
|
+
}).catch(function() {
|
|
225
|
+
// Restore scroll even if MathJax fails
|
|
226
|
+
container.scrollTop = scrollTop;
|
|
227
|
+
});
|
|
228
|
+
} else {
|
|
229
|
+
// Fallback: restore scroll immediately
|
|
230
|
+
container.scrollTop = scrollTop;
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
// No MathJax: restore scroll immediately
|
|
234
|
+
container.scrollTop = scrollTop;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Show error message
|
|
240
|
+
*/
|
|
241
|
+
function showError(message) {
|
|
242
|
+
content.innerHTML = '<div class="vimd-error"><h2>Error</h2><p>' + escapeHtml(message) + '</p></div>';
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Escape HTML special characters
|
|
247
|
+
*/
|
|
248
|
+
function escapeHtml(text) {
|
|
249
|
+
var div = document.createElement('div');
|
|
250
|
+
div.textContent = text;
|
|
251
|
+
return div.innerHTML;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Initialize connection
|
|
255
|
+
connect();
|
|
256
|
+
})();
|
|
257
|
+
</script>
|
|
258
|
+
</body>
|
|
259
|
+
</html>
|
|
@@ -643,6 +643,105 @@ body mark {
|
|
|
643
643
|
}
|
|
644
644
|
}
|
|
645
645
|
|
|
646
|
+
/* ============================================
|
|
647
|
+
LaTeX Metadata
|
|
648
|
+
============================================ */
|
|
649
|
+
.vimd-authors {
|
|
650
|
+
font-size: 1.1em;
|
|
651
|
+
margin-bottom: 0.5em;
|
|
652
|
+
color: #2c3e50;
|
|
653
|
+
text-align: center;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.vimd-authors sup {
|
|
657
|
+
color: #c0392b;
|
|
658
|
+
font-weight: bold;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.vimd-affiliations {
|
|
662
|
+
font-size: 0.9em;
|
|
663
|
+
color: #7f8c8d;
|
|
664
|
+
margin-bottom: 0.5em;
|
|
665
|
+
text-align: center;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.vimd-affiliation {
|
|
669
|
+
margin-bottom: 0.25em;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
.vimd-affiliation sup {
|
|
673
|
+
color: #c0392b;
|
|
674
|
+
font-weight: bold;
|
|
675
|
+
margin-right: 0.25em;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.vimd-corresponding {
|
|
679
|
+
font-size: 0.9em;
|
|
680
|
+
color: #7f8c8d;
|
|
681
|
+
font-style: italic;
|
|
682
|
+
margin-bottom: 1.5em;
|
|
683
|
+
padding-bottom: 1em;
|
|
684
|
+
border-bottom: 1px solid #ecf0f1;
|
|
685
|
+
text-align: center;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.vimd-corresponding a {
|
|
689
|
+
color: #2980b9;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/* LaTeX document title */
|
|
693
|
+
.vimd-title {
|
|
694
|
+
font-size: 1.8em;
|
|
695
|
+
font-weight: bold;
|
|
696
|
+
text-align: center;
|
|
697
|
+
margin-bottom: 0.5em;
|
|
698
|
+
color: #2c3e50;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/* Key Points box */
|
|
702
|
+
.vimd-keypoints {
|
|
703
|
+
background-color: #f8f9fa;
|
|
704
|
+
border: 1px solid #ecf0f1;
|
|
705
|
+
border-radius: 4px;
|
|
706
|
+
padding: 1em;
|
|
707
|
+
margin: 1em 0;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.vimd-keypoints h2 {
|
|
711
|
+
font-size: 1.1em;
|
|
712
|
+
margin-top: 0;
|
|
713
|
+
margin-bottom: 0.5em;
|
|
714
|
+
color: #2c3e50;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
.vimd-keypoints ul {
|
|
718
|
+
margin: 0;
|
|
719
|
+
padding-left: 1.5em;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.vimd-keypoints li {
|
|
723
|
+
margin-bottom: 0.3em;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/* Abstract section */
|
|
727
|
+
.vimd-abstract {
|
|
728
|
+
border-left: 4px solid #2980b9;
|
|
729
|
+
padding-left: 1em;
|
|
730
|
+
margin: 1em 0;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.vimd-abstract h2 {
|
|
734
|
+
font-size: 1.1em;
|
|
735
|
+
margin-top: 0;
|
|
736
|
+
margin-bottom: 0.5em;
|
|
737
|
+
color: #2c3e50;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.vimd-abstract p {
|
|
741
|
+
margin: 0;
|
|
742
|
+
text-align: justify;
|
|
743
|
+
}
|
|
744
|
+
|
|
646
745
|
/* ============================================
|
|
647
746
|
Responsive
|
|
648
747
|
============================================ */
|
|
@@ -516,6 +516,100 @@ body a:focus {
|
|
|
516
516
|
outline-offset: -2px;
|
|
517
517
|
}
|
|
518
518
|
|
|
519
|
+
/* LaTeX metadata styles */
|
|
520
|
+
.vimd-authors {
|
|
521
|
+
font-size: 1.1em;
|
|
522
|
+
margin-bottom: 0.5em;
|
|
523
|
+
color: #e6edf3;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.vimd-authors sup {
|
|
527
|
+
color: #58a6ff;
|
|
528
|
+
font-weight: bold;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.vimd-affiliations {
|
|
532
|
+
font-size: 0.9em;
|
|
533
|
+
color: #8b949e;
|
|
534
|
+
margin-bottom: 0.5em;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.vimd-affiliation {
|
|
538
|
+
margin-bottom: 0.25em;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.vimd-affiliation sup {
|
|
542
|
+
color: #58a6ff;
|
|
543
|
+
font-weight: bold;
|
|
544
|
+
margin-right: 0.25em;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.vimd-corresponding {
|
|
548
|
+
font-size: 0.9em;
|
|
549
|
+
color: #8b949e;
|
|
550
|
+
font-style: italic;
|
|
551
|
+
margin-bottom: 1.5em;
|
|
552
|
+
padding-bottom: 1em;
|
|
553
|
+
border-bottom: 1px solid #30363d;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.vimd-corresponding a {
|
|
557
|
+
color: #58a6ff;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/* LaTeX document title */
|
|
561
|
+
.vimd-title {
|
|
562
|
+
font-size: 1.8em;
|
|
563
|
+
font-weight: bold;
|
|
564
|
+
text-align: center;
|
|
565
|
+
margin-bottom: 0.5em;
|
|
566
|
+
color: #c9d1d9;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* Key Points box */
|
|
570
|
+
.vimd-keypoints {
|
|
571
|
+
background-color: #161b22;
|
|
572
|
+
border: 1px solid #30363d;
|
|
573
|
+
border-radius: 6px;
|
|
574
|
+
padding: 1em;
|
|
575
|
+
margin: 1em 0;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.vimd-keypoints h2 {
|
|
579
|
+
font-size: 1.1em;
|
|
580
|
+
margin-top: 0;
|
|
581
|
+
margin-bottom: 0.5em;
|
|
582
|
+
color: #c9d1d9;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.vimd-keypoints ul {
|
|
586
|
+
margin: 0;
|
|
587
|
+
padding-left: 1.5em;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.vimd-keypoints li {
|
|
591
|
+
margin-bottom: 0.3em;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/* Abstract section */
|
|
595
|
+
.vimd-abstract {
|
|
596
|
+
border-left: 4px solid #58a6ff;
|
|
597
|
+
padding-left: 1em;
|
|
598
|
+
margin: 1em 0;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.vimd-abstract h2 {
|
|
602
|
+
font-size: 1.1em;
|
|
603
|
+
margin-top: 0;
|
|
604
|
+
margin-bottom: 0.5em;
|
|
605
|
+
color: #c9d1d9;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.vimd-abstract p {
|
|
609
|
+
margin: 0;
|
|
610
|
+
text-align: justify;
|
|
611
|
+
}
|
|
612
|
+
|
|
519
613
|
/* Responsive */
|
|
520
614
|
@media (max-width: 768px) {
|
|
521
615
|
body {
|