@docmd/live 0.4.2 → 0.4.3
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/docmd-live.js +2 -2
- package/package.json +5 -4
- package/src/browser-entry.js +102 -0
- package/src/docmd-live-preview.css +33 -0
- package/src/docmd-live.css +275 -0
- package/src/index.html +189 -0
- package/src/shims.js +1 -0
package/dist/docmd-live.js
CHANGED
|
@@ -30258,7 +30258,7 @@ try {
|
|
|
30258
30258
|
<div class="footer-content">
|
|
30259
30259
|
<div class="user-footer"><%- footerHtml || '' %></div>
|
|
30260
30260
|
<div class="branding-footer">
|
|
30261
|
-
Build with <a href="https://docmd.io" target="_blank" rel="noopener">docmd.</a>
|
|
30261
|
+
Build with <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"></path><path d="M12 5 9.04 7.96a2.17 2.17 0 0 0 0 3.08c.82.82 2.13.85 3 .07l2.07-1.9a2.82 2.82 0 0 1 3.79 0l2.96 2.66"></path><path d="m18 15-2-2"></path><path d="m15 18-2-2"></path></svg> <a href="https://docmd.io" target="_blank" rel="noopener">docmd.</a>
|
|
30262
30262
|
</div>
|
|
30263
30263
|
</div>
|
|
30264
30264
|
</footer>
|
|
@@ -30648,7 +30648,7 @@ if (shouldShowToc && !frontmatter?.toc || frontmatter?.toc !== 'false') {
|
|
|
30648
30648
|
} catch (e) {
|
|
30649
30649
|
console.error('Theme init failed', e);
|
|
30650
30650
|
}
|
|
30651
|
-
})();`}});var VX=w((gde,Jv)=>{u();var{createMarkdownProcessor:FX,processContent:UX}=kg(),{renderTemplate:GX}=Qv(),wr=Xv();function HX(e,t={}){let r={siteTitle:"Live Preview",theme:{defaultMode:"light",name:"default",codeHighlight:!0},...t},o=FX(r),i=UX(e,o,r);if(!i)return"<p>Error parsing markdown</p>";let a="./assets",s=[`<link rel="stylesheet" href="${a}/css/docmd-main.css">`];if(r.theme.codeHighlight!==!1){let g=r.theme.defaultMode==="dark"?"dark":"light";s.push(`<link rel="stylesheet" href="${a}/css/docmd-highlight-${g}.css">`)}r.theme.name&&r.theme.name!=="default"&&s.push(`<link rel="stylesheet" href="${a}/css/docmd-theme-${r.theme.name}.css">`),s.push(`<link rel="stylesheet" href="${a}/css/docmd-live-preview.css">`);let l=[`<script src="${a}/js/docmd-main.js"><\/script>`],c="";wr["partials/theme-init.js"]&&(c=`<script>${wr["partials/theme-init.js"]}<\/script>`);let d={content:i.htmlContent,frontmatter:i.frontmatter,headings:i.headings,config:r,siteTitle:r.siteTitle,pageTitle:i.frontmatter.title||"Untitled",description:i.frontmatter.description||"",defaultMode:r.theme.defaultMode,navigationHtml:"",relativePathToRoot:"./",outputPath:"index.html",currentPagePath:"/index",prevPage:null,nextPage:null,pluginHeadScriptsHtml:s.join(`
|
|
30651
|
+
})();`}});var VX=w((gde,Jv)=>{u();var{createMarkdownProcessor:FX,processContent:UX}=kg(),{renderTemplate:GX}=Qv(),wr=Xv();function HX(e,t={}){let r={siteTitle:"Live Preview",theme:{defaultMode:"light",name:"default",codeHighlight:!0},...t},o=FX(r),i=UX(e,o,r);if(!i)return"<p>Error parsing markdown</p>";let a="./assets",s=[`<link rel="stylesheet" href="${a}/css/docmd-main.css">`];if(r.theme.codeHighlight!==!1){let g=r.theme.defaultMode==="dark"?"dark":"light";s.push(`<link rel="stylesheet" href="${a}/css/docmd-highlight-${g}.css">`)}r.theme.name&&r.theme.name!=="default"&&s.push(`<link rel="stylesheet" href="${a}/css/docmd-theme-${r.theme.name}.css">`),s.push(`<link rel="stylesheet" href="${a}/css/docmd-live-preview.css">`);let l=[`<script src="${a}/js/docmd-main.js"><\/script>`],c="";wr["partials/theme-init.js"]&&(c=`<script>${wr["partials/theme-init.js"]}<\/script>`);let d={content:i.htmlContent,frontmatter:i.frontmatter,headings:i.headings,config:r,buildHash:"live",siteTitle:r.siteTitle,pageTitle:i.frontmatter.title||"Untitled",description:i.frontmatter.description||"",defaultMode:r.theme.defaultMode,navigationHtml:"",relativePathToRoot:"./",outputPath:"index.html",currentPagePath:"/index",prevPage:null,nextPage:null,pluginHeadScriptsHtml:s.join(`
|
|
30652
30652
|
`),pluginBodyScriptsHtml:l.join(`
|
|
30653
30653
|
`),themeInitScript:c,faviconLinkHtml:"",logo:r.logo,sidebarConfig:{collapsible:!1},theme:r.theme,customCssFiles:[],customJsFiles:[],sponsor:{},footer:"",footerHtml:"",isActivePage:!0,editUrl:null,editLinkText:""},p=i.frontmatter.noStyle?"no-style.ejs":"layout.ejs",h=wr[p];return h?GX(h,d,{includer:g=>{let m=g.endsWith(".ejs")?g:g+".ejs";return wr[m]?{template:wr[m]}:null}}):`Template ${p} not found`}Jv.exports={compile:HX}});return VX();})();
|
|
30654
30654
|
/*! Bundled license information:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docmd/live",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Browser-based editor engine for docmd",
|
|
5
5
|
"bin": {
|
|
6
6
|
"docmd-live": "bin/docmd-live.js"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"bin",
|
|
13
|
+
"src",
|
|
13
14
|
"dist",
|
|
14
15
|
"index.js",
|
|
15
16
|
"src/build.js"
|
|
@@ -18,9 +19,9 @@
|
|
|
18
19
|
"esbuild": "^0.27.3",
|
|
19
20
|
"buffer": "^6.0.3",
|
|
20
21
|
"serve": "^14.2.1",
|
|
21
|
-
"@docmd/parser": "^0.4.
|
|
22
|
-
"@docmd/ui": "^0.4.
|
|
23
|
-
"@docmd/themes": "^0.4.
|
|
22
|
+
"@docmd/parser": "^0.4.3",
|
|
23
|
+
"@docmd/ui": "^0.4.3",
|
|
24
|
+
"@docmd/themes": "^0.4.3"
|
|
24
25
|
},
|
|
25
26
|
"keywords": [
|
|
26
27
|
"docmd",
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const { createMarkdownProcessor, processContent } = require('@docmd/parser/src/markdown-processor');
|
|
2
|
+
const { renderTemplate } = require('@docmd/parser/src/html-renderer');
|
|
3
|
+
const templates = require('virtual:docmd-templates');
|
|
4
|
+
|
|
5
|
+
// Expose the compile function to the window.docmd global
|
|
6
|
+
function compile(markdown, config = {}) {
|
|
7
|
+
const defaults = {
|
|
8
|
+
siteTitle: 'Live Preview',
|
|
9
|
+
theme: { defaultMode: 'light', name: 'default', codeHighlight: true },
|
|
10
|
+
...config
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// 1. Process Markdown
|
|
14
|
+
const md = createMarkdownProcessor(defaults);
|
|
15
|
+
const result = processContent(markdown, md, defaults);
|
|
16
|
+
|
|
17
|
+
if (!result) return '<p>Error parsing markdown</p>';
|
|
18
|
+
|
|
19
|
+
// Since we are in the browser, we assume assets are served at ./assets/
|
|
20
|
+
const assetsRoot = './assets';
|
|
21
|
+
|
|
22
|
+
// 1. CSS Injection
|
|
23
|
+
const cssTags = [
|
|
24
|
+
`<link rel="stylesheet" href="${assetsRoot}/css/docmd-main.css">`
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
if (defaults.theme.codeHighlight !== false) {
|
|
28
|
+
const mode = defaults.theme.defaultMode === 'dark' ? 'dark' : 'light';
|
|
29
|
+
cssTags.push(`<link rel="stylesheet" href="${assetsRoot}/css/docmd-highlight-${mode}.css">`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (defaults.theme.name && defaults.theme.name !== 'default') {
|
|
33
|
+
cssTags.push(`<link rel="stylesheet" href="${assetsRoot}/css/docmd-theme-${defaults.theme.name}.css">`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
cssTags.push(`<link rel="stylesheet" href="${assetsRoot}/css/docmd-live-preview.css">`);
|
|
37
|
+
|
|
38
|
+
// 2. JS Injection
|
|
39
|
+
const jsTags = [
|
|
40
|
+
`<script src="${assetsRoot}/js/docmd-main.js"></script>`
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// 3. Theme Init Script
|
|
44
|
+
let themeInitScript = '';
|
|
45
|
+
if (templates['partials/theme-init.js']) {
|
|
46
|
+
themeInitScript = `<script>${templates['partials/theme-init.js']}</script>`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 4. Prepare Data
|
|
50
|
+
const pageData = {
|
|
51
|
+
content: result.htmlContent,
|
|
52
|
+
frontmatter: result.frontmatter,
|
|
53
|
+
headings: result.headings,
|
|
54
|
+
config: defaults,
|
|
55
|
+
buildHash: 'live',
|
|
56
|
+
siteTitle: defaults.siteTitle,
|
|
57
|
+
pageTitle: result.frontmatter.title || 'Untitled',
|
|
58
|
+
description: result.frontmatter.description || '',
|
|
59
|
+
defaultMode: defaults.theme.defaultMode,
|
|
60
|
+
|
|
61
|
+
// Navigation Stub
|
|
62
|
+
navigationHtml: '',
|
|
63
|
+
relativePathToRoot: './',
|
|
64
|
+
outputPath: 'index.html',
|
|
65
|
+
currentPagePath: '/index',
|
|
66
|
+
prevPage: null,
|
|
67
|
+
nextPage: null,
|
|
68
|
+
|
|
69
|
+
// Inject the constructed assets
|
|
70
|
+
pluginHeadScriptsHtml: cssTags.join('\n'),
|
|
71
|
+
pluginBodyScriptsHtml: jsTags.join('\n'),
|
|
72
|
+
themeInitScript: themeInitScript,
|
|
73
|
+
|
|
74
|
+
// Helpers
|
|
75
|
+
faviconLinkHtml: '',
|
|
76
|
+
logo: defaults.logo,
|
|
77
|
+
sidebarConfig: { collapsible: false },
|
|
78
|
+
theme: defaults.theme,
|
|
79
|
+
customCssFiles: [], customJsFiles: [],
|
|
80
|
+
sponsor: {}, footer: '', footerHtml: '',
|
|
81
|
+
isActivePage: true,
|
|
82
|
+
editUrl: null, editLinkText: ''
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// 5. Render
|
|
86
|
+
const templateName = result.frontmatter.noStyle ? 'no-style.ejs' : 'layout.ejs';
|
|
87
|
+
const templateStr = templates[templateName];
|
|
88
|
+
|
|
89
|
+
if (!templateStr) return `Template ${templateName} not found`;
|
|
90
|
+
|
|
91
|
+
const options = {
|
|
92
|
+
includer: (originalPath) => {
|
|
93
|
+
let name = originalPath.endsWith('.ejs') ? originalPath : originalPath + '.ejs';
|
|
94
|
+
if (templates[name]) return { template: templates[name] };
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return renderTemplate(templateStr, pageData, options);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = { compile };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Styles specific to the Live Editor Preview Iframe
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* Always hide TOC and Footer Actions in preview to save space */
|
|
6
|
+
.toc-sidebar,
|
|
7
|
+
.page-footer-actions {
|
|
8
|
+
display: none !important;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* Ensure the main content takes full width since TOC is gone */
|
|
12
|
+
.content-layout {
|
|
13
|
+
display: block !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Hide Sidebar specifically on mobile in the preview */
|
|
17
|
+
/* (In Split View on mobile, space is very limited) */
|
|
18
|
+
@media (max-width: 768px) {
|
|
19
|
+
.sidebar {
|
|
20
|
+
display: none !important;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.main-content-wrapper {
|
|
24
|
+
margin-left: 0 !important;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Adjust header to look better without sidebar on mobile */
|
|
29
|
+
@media (max-width: 768px) {
|
|
30
|
+
.sidebar-toggle-button {
|
|
31
|
+
display: none !important;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/* Source file from the docmd project — https://github.com/docmd-io/docmd */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--header-height: 50px;
|
|
5
|
+
--border-color: #e0e0e0;
|
|
6
|
+
--bg-color: #f9fafb;
|
|
7
|
+
--primary-color: #007bff;
|
|
8
|
+
--resizer-width: 8px
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
height: 100vh;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
17
|
+
overflow: hidden
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.top-bar {
|
|
21
|
+
height: var(--header-height);
|
|
22
|
+
background: #fff;
|
|
23
|
+
border-bottom: 1px solid var(--border-color);
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: space-between;
|
|
27
|
+
padding: 0 1rem;
|
|
28
|
+
flex-shrink: 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.logo {
|
|
32
|
+
font-weight: 700;
|
|
33
|
+
font-size: 1.1rem;
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: 12px
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.logo span {
|
|
40
|
+
background: var(--primary-color);
|
|
41
|
+
color: #fff;
|
|
42
|
+
padding: 2px 6px;
|
|
43
|
+
border-radius: 4px;
|
|
44
|
+
font-size: .75rem;
|
|
45
|
+
text-transform: uppercase
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.back-link {
|
|
49
|
+
display: flex;
|
|
50
|
+
width: 24px;
|
|
51
|
+
height: 24px;
|
|
52
|
+
background-color: #f0f0f0;
|
|
53
|
+
border-radius: 100%;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
color: #666;
|
|
57
|
+
transition: color 0.2s, transform .2s;
|
|
58
|
+
text-decoration: none;
|
|
59
|
+
padding: 4px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.back-link:hover {
|
|
63
|
+
color: var(--primary-color);
|
|
64
|
+
background: #f0f0f0;
|
|
65
|
+
transform: translateX(-2px)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.logo .docmd-logo {
|
|
69
|
+
color: inherit;
|
|
70
|
+
text-decoration: none;
|
|
71
|
+
transition: .5s;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.logo .docmd-logo:hover {
|
|
75
|
+
color: var(--primary-color);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.view-switcher {
|
|
79
|
+
display: flex;
|
|
80
|
+
background: #f0f0f0;
|
|
81
|
+
padding: 3px;
|
|
82
|
+
border-radius: 8px;
|
|
83
|
+
gap: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.view-btn {
|
|
87
|
+
border: none;
|
|
88
|
+
background: transparent;
|
|
89
|
+
padding: 6px 12px;
|
|
90
|
+
border-radius: 6px;
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
font-size: 0.85rem;
|
|
93
|
+
color: #666;
|
|
94
|
+
font-weight: 500;
|
|
95
|
+
transition: background 0.15s, color 0.15s;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.view-btn:hover {
|
|
99
|
+
color: #333;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.view-btn.active {
|
|
103
|
+
background: #fff;
|
|
104
|
+
color: #000;
|
|
105
|
+
box-shadow: 0 1px 3px #0000001a;
|
|
106
|
+
font-weight: 600;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.workspace {
|
|
110
|
+
flex: 1;
|
|
111
|
+
display: flex;
|
|
112
|
+
position: relative;
|
|
113
|
+
overflow: hidden
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.pane {
|
|
117
|
+
height: 100%;
|
|
118
|
+
display: flex;
|
|
119
|
+
flex-direction: column;
|
|
120
|
+
min-width: 300px;
|
|
121
|
+
background: #fff
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.pane-header {
|
|
125
|
+
padding: 8px 16px;
|
|
126
|
+
font-size: .75rem;
|
|
127
|
+
font-weight: 600;
|
|
128
|
+
text-transform: uppercase;
|
|
129
|
+
color: #888;
|
|
130
|
+
background: var(--bg-color);
|
|
131
|
+
border-bottom: 1px solid var(--border-color);
|
|
132
|
+
flex-shrink: 0
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.editor-pane {
|
|
136
|
+
width: 50%
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
textarea#input {
|
|
140
|
+
flex: 1;
|
|
141
|
+
border: none;
|
|
142
|
+
resize: none;
|
|
143
|
+
padding: 20px;
|
|
144
|
+
font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
|
|
145
|
+
font-size: 14px;
|
|
146
|
+
line-height: 1.6;
|
|
147
|
+
outline: none;
|
|
148
|
+
background: var(--bg-color)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.preview-pane {
|
|
152
|
+
flex: 1;
|
|
153
|
+
background: #fff
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
iframe#preview {
|
|
157
|
+
width: 100%;
|
|
158
|
+
height: 100%;
|
|
159
|
+
border: none;
|
|
160
|
+
display: block
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.resizer {
|
|
164
|
+
width: var(--resizer-width);
|
|
165
|
+
background: var(--bg-color);
|
|
166
|
+
border-left: 1px solid var(--border-color);
|
|
167
|
+
border-right: 1px solid var(--border-color);
|
|
168
|
+
cursor: col-resize;
|
|
169
|
+
display: flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
justify-content: center;
|
|
172
|
+
transition: background .2s;
|
|
173
|
+
z-index: 10
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.resizer:hover,
|
|
177
|
+
.resizer.resizing {
|
|
178
|
+
background: #e0e0e0
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.resizer::after {
|
|
182
|
+
content: "||";
|
|
183
|
+
color: #aaa;
|
|
184
|
+
font-size: 10px;
|
|
185
|
+
letter-spacing: 1px
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
body.mode-single .resizer {
|
|
189
|
+
display: none
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
body.mode-single .pane {
|
|
193
|
+
width: 100% !important;
|
|
194
|
+
min-width: 0
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
body.mode-single .editor-pane {
|
|
198
|
+
display: none
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
body.mode-single .preview-pane {
|
|
202
|
+
display: none
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
body.mode-single.show-editor .editor-pane {
|
|
206
|
+
display: flex
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
body.mode-single.show-preview .preview-pane {
|
|
210
|
+
display: flex
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@media (max-width: 768px) {
|
|
214
|
+
.desktop-only {
|
|
215
|
+
display: none !important
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.resizer {
|
|
219
|
+
display: none !important
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.pane {
|
|
223
|
+
width: 100% !important
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.editor-pane {
|
|
227
|
+
display: none
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.preview-pane {
|
|
231
|
+
display: none
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
body.mobile-tab-editor .editor-pane {
|
|
235
|
+
display: flex
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
body.mobile-tab-preview .preview-pane {
|
|
239
|
+
display: flex
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.mobile-tabs {
|
|
243
|
+
display: flex !important;
|
|
244
|
+
position: fixed;
|
|
245
|
+
bottom: 0;
|
|
246
|
+
left: 0;
|
|
247
|
+
right: 0;
|
|
248
|
+
height: 50px;
|
|
249
|
+
background: #fff;
|
|
250
|
+
border-top: 1px solid var(--border-color);
|
|
251
|
+
z-index: 100
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.mobile-tab-btn {
|
|
255
|
+
flex: 1;
|
|
256
|
+
border: none;
|
|
257
|
+
background: transparent;
|
|
258
|
+
font-weight: 600;
|
|
259
|
+
color: #888;
|
|
260
|
+
cursor: pointer
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.mobile-tab-btn.active {
|
|
264
|
+
color: var(--primary-color);
|
|
265
|
+
border-top: 2px solid var(--primary-color)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.workspace {
|
|
269
|
+
padding-bottom: 50px
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.mobile-tabs {
|
|
274
|
+
display: none
|
|
275
|
+
}
|
package/src/index.html
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
<!-- Source file from the docmd project — https://github.com/docmd-io/docmd -->
|
|
2
|
+
|
|
3
|
+
<!DOCTYPE html>
|
|
4
|
+
<html lang="en">
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="UTF-8">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<title>Docmd Live Editor</title>
|
|
9
|
+
<meta name="description" content="Real-time Markdown preview and editor powered by docmd.">
|
|
10
|
+
|
|
11
|
+
<link rel="stylesheet" href="docmd-live.css">
|
|
12
|
+
<script src="docmd-live.js"></script>
|
|
13
|
+
|
|
14
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-VCMQ0MCSHN"></script>
|
|
15
|
+
<script>
|
|
16
|
+
window.dataLayer = window.dataLayer || [];
|
|
17
|
+
function gtag() { dataLayer.push(arguments); }
|
|
18
|
+
gtag('js', new Date());
|
|
19
|
+
gtag('config', 'G-VCMQ0MCSHN');
|
|
20
|
+
</script>
|
|
21
|
+
</head>
|
|
22
|
+
|
|
23
|
+
<body class="mode-split">
|
|
24
|
+
|
|
25
|
+
<!-- Top Bar -->
|
|
26
|
+
<div class="top-bar">
|
|
27
|
+
<div class="logo">
|
|
28
|
+
<!--<a href="/" class="back-link" id="back-btn" title="Previous Page" aria-label="Back to previous page">
|
|
29
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
|
|
30
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
31
|
+
<path d="m12 19-7-7 7-7" />
|
|
32
|
+
<path d="M19 12H5" />
|
|
33
|
+
</svg>
|
|
34
|
+
</a>-->
|
|
35
|
+
<a href="https://docmd.io" class="docmd-logo" title="Back to home" aria-label="Back to homepage"><svg width="24" height="24" id="icon-feather" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"></path><line x1="16" y1="8" x2="2" y2="22"></line><line x1="17.5" y1="15" x2="9" y2="15"></line></svg></a> docmd <span>Live</span>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<!-- Unified 3-Way Switcher -->
|
|
39
|
+
<div class="view-switcher desktop-only">
|
|
40
|
+
<button class="view-btn active" onclick="setMode('split')" data-mode="split">Split</button>
|
|
41
|
+
<button class="view-btn" onclick="setMode('editor')" data-mode="editor">Editor</button>
|
|
42
|
+
<button class="view-btn" onclick="setMode('preview')" data-mode="preview">Preview</button>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<!-- Workspace -->
|
|
47
|
+
<div class="workspace" id="workspace">
|
|
48
|
+
<!-- Editor -->
|
|
49
|
+
<div class="pane editor-pane" id="editorPane">
|
|
50
|
+
<div class="pane-header">Markdown</div>
|
|
51
|
+
<textarea id="input" spellcheck="false">
|
|
52
|
+
---
|
|
53
|
+
title: My Documentation
|
|
54
|
+
description: Start editing to see changes instantly.
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
# Hello World
|
|
58
|
+
|
|
59
|
+
This is a **live** preview.
|
|
60
|
+
|
|
61
|
+
::: callout tip
|
|
62
|
+
Try resizing the window or switching to mobile view!
|
|
63
|
+
:::
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
1. Responsive Design
|
|
67
|
+
2. Split or Tabbed view
|
|
68
|
+
3. Instant Rendering
|
|
69
|
+
</textarea>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<!-- Resizer Handle -->
|
|
73
|
+
<div class="resizer" id="resizer"></div>
|
|
74
|
+
|
|
75
|
+
<!-- Preview -->
|
|
76
|
+
<div class="pane preview-pane" id="previewPane">
|
|
77
|
+
<div class="pane-header">Preview</div>
|
|
78
|
+
<iframe id="preview"></iframe>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<!-- Mobile Bottom Tabs (Keep for small screens) -->
|
|
83
|
+
<div class="mobile-tabs">
|
|
84
|
+
<button class="mobile-tab-btn active" onclick="setMode('editor')" id="mob-edit">Editor</button>
|
|
85
|
+
<button class="mobile-tab-btn" onclick="setMode('preview')" id="mob-prev">Preview</button>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<script>
|
|
89
|
+
// --- Core Logic ---
|
|
90
|
+
const input = document.getElementById('input');
|
|
91
|
+
const preview = document.getElementById('preview');
|
|
92
|
+
const backBtn = document.getElementById('back-btn');
|
|
93
|
+
|
|
94
|
+
function render() {
|
|
95
|
+
try {
|
|
96
|
+
let html = docmd.compile(input.value, {
|
|
97
|
+
siteTitle: 'My Project',
|
|
98
|
+
search: false,
|
|
99
|
+
theme: { name: 'sky', defaultMode: 'light' },
|
|
100
|
+
sidebar: { collapsible: false }
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Injections
|
|
104
|
+
html = html.replace('<head>', '<head><base target="_blank">');
|
|
105
|
+
const customStyle = `
|
|
106
|
+
<style>
|
|
107
|
+
.sidebar-header { display: none !important; }
|
|
108
|
+
.sidebar-nav { margin-top: 1rem; }
|
|
109
|
+
</style>
|
|
110
|
+
`;
|
|
111
|
+
html = html.replace('</body>', `${customStyle}</body>`);
|
|
112
|
+
|
|
113
|
+
const doc = preview.contentWindow.document;
|
|
114
|
+
doc.open();
|
|
115
|
+
doc.write(html);
|
|
116
|
+
doc.close();
|
|
117
|
+
} catch (e) { console.error(e); }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let timer;
|
|
121
|
+
input.addEventListener('input', () => {
|
|
122
|
+
clearTimeout(timer);
|
|
123
|
+
timer = setTimeout(render, 300);
|
|
124
|
+
});
|
|
125
|
+
render();
|
|
126
|
+
|
|
127
|
+
// --- Resizer Logic ---
|
|
128
|
+
const resizer = document.getElementById('resizer');
|
|
129
|
+
const editorPane = document.getElementById('editorPane');
|
|
130
|
+
const workspace = document.getElementById('workspace');
|
|
131
|
+
let isResizing = false;
|
|
132
|
+
|
|
133
|
+
resizer.addEventListener('mousedown', (e) => {
|
|
134
|
+
isResizing = true;
|
|
135
|
+
resizer.classList.add('resizing');
|
|
136
|
+
preview.style.pointerEvents = 'none';
|
|
137
|
+
document.body.style.cursor = 'col-resize';
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
document.addEventListener('mousemove', (e) => {
|
|
141
|
+
if (!isResizing) return;
|
|
142
|
+
const containerWidth = workspace.offsetWidth;
|
|
143
|
+
const newEditorWidth = (e.clientX / containerWidth) * 100;
|
|
144
|
+
if (newEditorWidth > 15 && newEditorWidth < 85) {
|
|
145
|
+
editorPane.style.width = newEditorWidth + '%';
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
document.addEventListener('mouseup', () => {
|
|
150
|
+
if (isResizing) {
|
|
151
|
+
isResizing = false;
|
|
152
|
+
resizer.classList.remove('resizing');
|
|
153
|
+
preview.style.pointerEvents = 'auto';
|
|
154
|
+
document.body.style.cursor = 'default';
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// --- Unified View Logic ---
|
|
159
|
+
function setMode(mode) {
|
|
160
|
+
// 1. Update UI Buttons (Desktop)
|
|
161
|
+
document.querySelectorAll('.view-switcher .view-btn').forEach(btn => {
|
|
162
|
+
btn.classList.toggle('active', btn.dataset.mode === mode);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// 2. Update Mobile Buttons
|
|
166
|
+
const mobMode = mode === 'split' ? 'editor' : mode; // Map split to editor on mobile
|
|
167
|
+
document.getElementById('mob-edit').classList.toggle('active', mobMode === 'editor');
|
|
168
|
+
document.getElementById('mob-prev').classList.toggle('active', mobMode === 'preview');
|
|
169
|
+
|
|
170
|
+
// 3. Update Layout Classes
|
|
171
|
+
// Reset
|
|
172
|
+
document.body.classList.remove('mode-split', 'mode-single', 'show-editor', 'show-preview');
|
|
173
|
+
|
|
174
|
+
if (mode === 'split') {
|
|
175
|
+
document.body.classList.add('mode-split');
|
|
176
|
+
} else {
|
|
177
|
+
document.body.classList.add('mode-single');
|
|
178
|
+
document.body.classList.add('show-' + mode);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// --- Back Button ---
|
|
183
|
+
/*
|
|
184
|
+
if (window.history.length <= 1) backBtn.style.display = 'none';
|
|
185
|
+
else backBtn.addEventListener('click', (e) => { e.preventDefault(); window.history.back(); });
|
|
186
|
+
*/
|
|
187
|
+
</script>
|
|
188
|
+
</body>
|
|
189
|
+
</html>
|
package/src/shims.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { Buffer } from 'buffer'; globalThis.Buffer = Buffer;
|