aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/css/dumbymap.css155
-rw-r--r--src/dumbymap.mjs80
2 files changed, 120 insertions, 115 deletions
diff --git a/src/css/dumbymap.css b/src/css/dumbymap.css
index a3f1fb9..40397c1 100644
--- a/src/css/dumbymap.css
+++ b/src/css/dumbymap.css
@@ -91,7 +91,7 @@
91 } 91 }
92 92
93 [data-focus="true"] { 93 [data-focus="true"] {
94 z-index: 9999; 94 z-index: 1;
95 } 95 }
96 } 96 }
97 97
@@ -101,6 +101,12 @@
101 overflow-y: scroll; 101 overflow-y: scroll;
102 width: 100%; 102 width: 100%;
103 103
104 .dumby-block {
105 border-left: #f0f0f0 0.5em solid;
106 padding-left: 0.5em;
107 margin-left: -0.5em;
108 }
109
104 pre { 110 pre {
105 width: 100%; 111 width: 100%;
106 112
@@ -130,26 +136,6 @@
130 } 136 }
131} 137}
132 138
133.draggable-block {
134 pointer-events: auto;
135 background-color: white;
136 margin-bottom: 3rem;
137
138 .draggable {
139 display: none;
140 }
141}
142
143/* Left border to indicate there is a block */
144.DumbyMap[data-layout]:not([data-layout="overlay"]) {
145 .draggable-block{
146 width: calc(100% + 0.5em);
147 border-left: #f0f0f0 0.5em solid;
148 padding-left: 0.5em;
149 margin-left: -0.5em;
150 }
151}
152
153.DumbyMap[data-layout]:not([data-layout="none"]) { 139.DumbyMap[data-layout]:not([data-layout="none"]) {
154 margin: 0 auto; 140 margin: 0 auto;
155 height: 100vh; 141 height: 100vh;
@@ -174,88 +160,97 @@
174 flex: 50%; 160 flex: 50%;
175 display: block; 161 display: block;
176 height: 100vh; 162 height: 100vh;
163 z-index: -1;
177 } 164 }
178} 165}
179 166
180.DumbyMap[data-layout="overlay"] { 167.DumbyMap[data-layout="overlay"] {
181 .Showcase, 168 .SemanticHtml,
182 .SemanticHtml { 169 .Showcase {
183 position: fixed; 170 display: block;
171 position: absolute;
172 left: 0;
173 top: 0;
174 padding: 0;
175 margin: 0;
184 height: 100%; 176 height: 100%;
185 width: 100%; 177 width: 100%;
186 } 178 }
187 179
188 .Showcase { 180 .Showcase {
189 display: block; 181 z-index: 0;
190 } 182 }
191 183
192 .SemanticHtml { 184 .SemanticHtml {
193 font-size: 12px;
194 pointer-events: none; 185 pointer-events: none;
195 z-index: 1; 186 z-index: 1;
187 }
188}
196 189
197 > .draggable-block { 190.draggable-block {
198 box-sizing: content-box; 191 background-color: white;
199 position: absolute; 192 margin-bottom: 3rem;
200 width: fit-content; 193 font-size: 12px;
201 max-height: 50vh; 194 pointer-events: auto;
202 max-width: 25vw; 195 box-sizing: content-box;
203 overflow: scroll; 196 position: absolute;
204 border: solid gray; 197 width: fit-content;
205 border-radius: 0.5rem; 198 max-height: 50vh;
206 padding-top: 0.5rem; 199 max-width: 25vw;
207 padding-bottom: 0; 200 overflow: scroll;
208 resize: both; 201 border: solid gray;
209 202 border-radius: 0.5rem;
210 &[style*="height"], 203 padding-top: 0.5rem;
211 &[style*="width"] { 204 padding-bottom: 0;
212 max-height: unset; 205 resize: both;
213 max-width: unset; 206
214 } 207 &[style*="height"],
208 &[style*="width"] {
209 max-height: unset;
210 max-width: unset;
211 }
215 212
216 .map-container { 213 .dumby-block {
217 min-width: 200px; 214 border: none;
218 } 215 padding: 0;
216 }
219 217
220 > :not(.draggable) { 218 .map-container {
221 margin-inline: 0.5rem; 219 min-width: 200px;
222 } 220 }
223 221
224 .draggable { 222 > :not(.draggable) {
225 display: block; 223 margin-inline: 0.5rem;
226 top: 0; 224 }
227 left: 0;
228 position: sticky;
229 background: linear-gradient(0deg, rgb(255 255 255 / 0%), rgb(255 255 255 / 100%) 60%);
230 margin-bottom: -18px;
231 transform: translate(0, -16px);
232 width: 100%;
233 padding-inline: 0;
234 padding-bottom: 2em;
235 text-align: center;
236 z-index: 9999;
237 transition: all 0.3s ease-in-out;
238
239 &:hover {
240 background: #e1e1e1;
241 padding-block: 1em 0.5em;
242
243 & ~ * {
244 opacity: 0.7;
245 color: gray;
246 }
247 }
248 }
249 }
250 225
251 > :not(.draggable-block) { 226 .draggable {
252 display: none; 227 display: block;
228 top: 0;
229 left: 0;
230 position: sticky;
231 background: linear-gradient(0deg, rgb(255 255 255 / 0%), rgb(255 255 255 / 100%) 60%);
232 margin-bottom: -18px;
233 transform: translate(0, -16px);
234 width: 100%;
235 padding-inline: 0;
236 padding-bottom: 2em;
237 text-align: center;
238 z-index: 9999;
239 transition: all 0.3s ease-in-out;
240
241 &:hover {
242 background: #e1e1e1;
243 padding-block: 1em 0.5em;
244
245 & ~ * {
246 opacity: 0.7;
247 color: gray;
248 }
253 } 249 }
254
255 } 250 }
256
257} 251}
258 252
253
259.bold-options { 254.bold-options {
260 font-weight: bold; 255 font-weight: bold;
261} 256}
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs
index 6e4c00e..bdb7ee8 100644
--- a/src/dumbymap.mjs
+++ b/src/dumbymap.mjs
@@ -86,28 +86,28 @@ export const markdown2HTML = (container, mdContent) => {
86 .use(MarkdownItFrontMatter) 86 .use(MarkdownItFrontMatter)
87 .use(MarkdownItTocDoneRight) 87 .use(MarkdownItTocDoneRight)
88 88
89 // FIXME A better way to generate draggable code block 89 // FIXME A better way to generate blocks
90 md.renderer.rules.draggable_block_open = () => '<div>' 90 md.renderer.rules.dumby_block_open = () => '<div>'
91 md.renderer.rules.draggable_block_close = () => '</div>' 91 md.renderer.rules.dumby_block_close = () => '</div>'
92 92
93 md.core.ruler.before('block', 'draggable_block', (state) => { 93 md.core.ruler.before('block', 'dumby_block', (state) => {
94 state.tokens.push(new state.Token('draggable_block_open', '', 1)) 94 state.tokens.push(new state.Token('dumby_block_open', '', 1))
95 }) 95 })
96 96
97 // Add close tag for block with more than 2 empty lines 97 // Add close tag for block with more than 2 empty lines
98 md.block.ruler.before('table', 'draggable_block', (state, startLine) => { 98 md.block.ruler.before('table', 'dumby_block', (state, startLine) => {
99 if ( 99 if (
100 state.src[state.bMarks[startLine - 1]] === '\n' && 100 state.src[state.bMarks[startLine - 1]] === '\n' &&
101 state.src[state.bMarks[startLine - 2]] === '\n' && 101 state.src[state.bMarks[startLine - 2]] === '\n' &&
102 state.tokens.at(-1).type !== 'list_item_open' // Quick hack for not adding tag after "::marker" for <li> 102 state.tokens.at(-1).type !== 'list_item_open' // Quick hack for not adding tag after "::marker" for <li>
103 ) { 103 ) {
104 state.push('draggable_block_close', '', -1); 104 state.push('dumby_block_close', '', -1);
105 state.push('draggable_block_open', '', 1); 105 state.push('dumby_block_open', '', 1);
106 } 106 }
107 }) 107 })
108 108
109 md.core.ruler.after('block', 'draggable_block', (state) => { 109 md.core.ruler.after('block', 'dumby_block', (state) => {
110 state.tokens.push(new state.Token('draggable_block_close', '', -1)) 110 state.tokens.push(new state.Token('dumby_block_close', '', -1))
111 }) 111 })
112 112
113 const contentWithToc = '${toc}\n\n\n' + mdContent 113 const contentWithToc = '${toc}\n\n\n' + mdContent
@@ -115,7 +115,7 @@ export const markdown2HTML = (container, mdContent) => {
115 115
116 // TODO Do this in markdown-it 116 // TODO Do this in markdown-it
117 htmlHolder.querySelectorAll('* > div:not(:has(nav))') 117 htmlHolder.querySelectorAll('* > div:not(:has(nav))')
118 .forEach(b => b.classList.add('draggable-block')) 118 .forEach(b => b.classList.add('dumby-block'))
119 119
120 return container 120 return container
121 //}}} 121 //}}}
@@ -200,33 +200,48 @@ export const generateMaps = async (container, callback) => {
200 childRect.bottom < parentRect.bottom - offset 200 childRect.bottom < parentRect.bottom - offset
201 } 201 }
202 //}}} 202 //}}}
203 // Draggable Blocks{{{ 203 // Draggable Blocks {{{
204 // Add draggable part for blocks 204 // Add draggable part for blocks
205 htmlHolder.blocks = Array.from(htmlHolder.querySelectorAll('.draggable-block')) 205
206 htmlHolder.blocks.forEach(block => { 206 const dumbyBlocks = Array.from(htmlHolder.querySelectorAll('.dumby-block'))
207 const intoDraggableContainer = (block) => {
208 // Create draggable block
209 const draggableContainer = document.createElement('div')
210 draggableContainer.classList.add('draggable-block')
211
207 // Add draggable part 212 // Add draggable part
208 const draggablePart = document.createElement('div'); 213 const draggablePart = document.createElement('div');
209 draggablePart.classList.add('draggable') 214 draggablePart.classList.add('draggable')
210 draggablePart.textContent = '☰' 215 draggablePart.textContent = '☰'
211 draggablePart.title = 'Use middle-click to remove block' 216 draggablePart.title = 'Use middle-click to remove block'
212 block.insertBefore(draggablePart, block.firstChild) 217 // Hide block with middle click
213 block.draggablePart = draggablePart
214
215 draggablePart.onmouseup = (e) => { 218 draggablePart.onmouseup = (e) => {
216 if (e.button === 1) { 219 if (e.button === 1) {
217 block.style.display = "none"; 220 draggableContainer.style.display = "none";
218 } 221 }
219 } 222 }
220 }) 223 draggableContainer.appendChild(draggablePart)
221 224
225 draggableContainer.appendChild(block)
226 htmlHolder.appendChild(draggableContainer)
227 return draggableContainer
228 }
229
230 const resumeFromDraggableContainer = (block) => {
231 const draggableContainer = block.closest('.draggable-block')
232 if (!draggableContainer) return
233 htmlHolder.appendChild(block)
234 draggableContainer.draggableInstance.remove()
235 draggableContainer.remove()
236 }
222 // }}} 237 // }}}
223 // CSS observer {{{ 238 // CSS observer {{{
239 // Focus Map {{{
224 // Set focusArea 240 // Set focusArea
225 const showcase = document.createElement('div') 241 const showcase = document.createElement('div')
226 container.appendChild(showcase) 242 container.appendChild(showcase)
227 showcase.classList.add('Showcase') 243 showcase.classList.add('Showcase')
228 244
229 // Focus Map {{{
230 const toShowcaseWithThrottle = throttle(animateRectTransition, 300) 245 const toShowcaseWithThrottle = throttle(animateRectTransition, 300)
231 const fromShowCaseWithThrottle = throttle(animateRectTransition, 300) 246 const fromShowCaseWithThrottle = throttle(animateRectTransition, 300)
232 247
@@ -331,7 +346,7 @@ export const generateMaps = async (container, callback) => {
331 focusMap?.setAttribute('data-focus', 'true') 346 focusMap?.setAttribute('data-focus', 'true')
332 347
333 // Check empty block with map-container in showcase 348 // Check empty block with map-container in showcase
334 htmlHolder.blocks.forEach(b => { 349 dumbyBlocks.forEach(b => {
335 const contentChildren = Array.from(b.querySelectorAll(':scope > :not(.draggable)')) ?? [] 350 const contentChildren = Array.from(b.querySelectorAll(':scope > :not(.draggable)')) ?? []
336 if (contentChildren.length === 1 351 if (contentChildren.length === 1
337 && elementsWithMapConfig.includes(contentChildren[0]) 352 && elementsWithMapConfig.includes(contentChildren[0])
@@ -344,32 +359,27 @@ export const generateMaps = async (container, callback) => {
344 }) 359 })
345 360
346 if (layout === 'overlay') { 361 if (layout === 'overlay') {
362 const draggableContainers = dumbyBlocks.map(intoDraggableContainer)
363
364 // Set initial position side by side
347 let [x, y] = [0, 0]; 365 let [x, y] = [0, 0];
348 htmlHolder.blocks.forEach(block => { 366 draggableContainers.forEach((c) => {
367
349 // Add draggable instance 368 // Add draggable instance
350 block.draggableInstance = new PlainDraggable(block, { 369 c.draggableInstance = new PlainDraggable(c, {
351 handle: block.draggablePart, 370 handle: c.querySelector('.draggable') ?? c,
352 snap: { x: { step: 20 }, y: { step: 20 } }, 371 snap: { x: { step: 20 }, y: { step: 20 } },
353 left: x, 372 left: x,
354 top: y, 373 top: y,
355 }) 374 })
356 375 x += parseInt(window.getComputedStyle(c).width) + 30
357 // Set initial position side by side
358 x += parseInt(window.getComputedStyle(block).width) + 50
359 if (x > window.innerWidth) { 376 if (x > window.innerWidth) {
360 y += 200 377 y += 200
361 x = x % window.innerWidth 378 x = x % window.innerWidth
362 } 379 }
363 }) 380 })
364 } else { 381 } else {
365 htmlHolder.blocks.forEach(block => { 382 dumbyBlocks.forEach(resumeFromDraggableContainer)
366 block.removeAttribute('style')
367 try {
368 block.draggableInstance.remove()
369 } catch (_) {
370 null
371 }
372 })
373 } 383 }
374 }); 384 });
375 layoutObserver.observe(container, { 385 layoutObserver.observe(container, {