git.s-ol.nu mmm / 5ec1fe2
add pinwall example s-ol 1 year, 10 months ago
12 changed file(s) with 190 addition(s) and 25 deletion(s). Raw diff Collapse all Expand all
188188 }
189189 {
190190 inp: 'table',
191 out: 'text/json',
192 cost: 2
193 transform: do
194 tojson = (obj) ->
195 switch type obj
196 when 'string'
197 string.format '%q', obj
198 when 'table'
199 if obj[1] or not next obj
200 "[#{table.concat [tojson c for c in *obj], ','}]"
201 else
202 "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}"
203 when 'number'
204 tostring obj
205 when 'boolean'
206 tostring obj
207 when 'nil'
208 'null'
209 else
210 error "unknown type '#{type obj}'"
211
212 (val) => tojson val
213 }
214 {
215 inp: 'table',
216191 out: 'mmm/dom',
217192 cost: 5
218193 transform: do
257232 table.insert editors, editor
258233
259234 add_converts 'code'
235 add_converts 'json'
260236 add_converts 'markdown'
261237 add_converts 'mermaid'
262238 add_converts 'twitter'
0 encode = (obj) ->
1 switch type obj
2 when 'string'
3 string.format '%q', obj
4 when 'table'
5 if obj[1] or not next obj
6 "[#{table.concat [encode c for c in *obj], ','}]"
7 else
8 "{#{table.concat ["#{encode k}: #{encode v}" for k,v in pairs obj], ', '}}"
9 when 'number'
10 tostring obj
11 when 'boolean'
12 tostring obj
13 when 'nil'
14 'null'
15 else
16 error "unknown type '#{type obj}'"
17
18 decode = if MODE == 'CLIENT'
19 import Array, Object, JSON from js.global
20
21 fix = (val) ->
22 switch type val
23 when 'userdata'
24 if Array\isArray val
25 [fix x for x in js.of val]
26 else
27 {(fix e[0]), (fix e[1]) for e in js.of Object\entries(val)}
28 else
29 val
30
31 encode
32 decode = (str) -> fix JSON\parse str
33 else if cjson = require 'cjson'
34 cjson.decode
35 else
36 warn 'only partial JSON support, please install cjson'
37
38
39 {
40 converts: {
41 {
42 inp: 'table',
43 out: 'text/json',
44 cost: 2
45 transform: (val) => encode val
46 }
47 if decode
48 {
49 inp: 'text/json'
50 out: 'table'
51 cost: 1
52 transform: (val) => decode val
53 }
54 }
55 }
22 markdown
33 empty
44 gallery
5 pinwall
0 {"x": 35.0, "y": 209.0, "w": 205.0, "h": 155.0}
0 {"x": 91.0, "y": 17.0, "w": 186.0, "h": 128.0}
0 This is a pinwall example.
1 Every box is a separate fileder.
2 The boxes can be rearranged and resized freely.
3 If the server is in read-write mode, the changes are saved persistently in real time.
0 import article, div from require 'mmm.dom'
1 import convert from require 'mmm.mmmfs.conversion'
2
3 update_info = (fileder, x, y, w, h) ->
4 info = (fileder\get 'pinwall_info: table') or x: 100, y: 100, w: 300, h: 300
5 info.x = x if x
6 info.y = y if y
7 info.w = w if w
8 info.h = h if h
9
10 json = convert 'table', 'text/json', info, fileder, 'pinwall_info'
11 fileder\set 'pinwall_info: text/json', json
12
13 CLIENT = MODE == 'CLIENT'
14
15 =>
16
17 pending = {}
18 observe = if CLIENT
19 map = {}
20 observer = js.new js.global.ResizeObserver, (_, entries) ->
21 for entry in js.of entries
22 if child = map[entry.target]
23 rect = entry.contentRect
24 pending[child] = -> update_info child, nil, nil, rect.width, rect.height
25
26 (node, child) ->
27 map[node] = child
28 observer\observe node
29
30 drag = nil
31
32 children = for child in *@children
33 info = (child\get 'pinwall_info: table') or x: 100, y: 100, w: 300, h: 300
34 wrapper = div {
35 style:
36 position: 'absolute'
37 padding: '10px'
38 resize: 'both'
39 overflow: 'hidden'
40 background: 'var(--gray-dark)'
41 border: '1px solid var(--gray-bright)'
42
43 left: "#{info.x}px"
44 top: "#{info.y}px"
45 width: "#{info.w}px"
46 height: "#{info.h}px"
47
48 -- handle for moving the child
49 div {
50 style:
51 top: '0'
52 left: '0'
53 right: '0'
54 height: '10px'
55 cursor: 'pointer'
56 position: 'absolute'
57
58 onmousedown: CLIENT and (_, e) ->
59 node = e.target.parentElement
60 drag = {
61 :child
62 :node
63
64 startX: tonumber node.style.left\match '(%d+)px'
65 startY: tonumber node.style.top\match '(%d+)px'
66 startMouseX: e.clientX
67 startMouseY: e.clientY
68 }
69 }
70
71 -- child content
72 div {
73 style:
74 width: '100%'
75 height: '100%'
76 background: 'var(--white)'
77
78 (child\gett 'mmm/dom')
79 }
80 }
81
82 -- listen for resize events
83 observe wrapper, child if CLIENT
84 wrapper
85
86 children.style = {
87 width: '1000px'
88 height: '500px'
89 }
90
91 if CLIENT
92 children.onmousemove = (_, e) ->
93 return unless drag
94
95 x = drag.startX + (e.clientX - drag.startMouseX)
96 y = drag.startY + (e.clientY - drag.startMouseY)
97 drag.node.style.left = "#{x}px"
98 drag.node.style.top = "#{y}px"
99
100 children.onmouseup = (_, e) ->
101 for k, func in pairs pending
102 func!
103 pending = {}
104
105 return unless drag
106
107 x = drag.startX + (e.clientX - drag.startMouseX)
108 y = drag.startY + (e.clientY - drag.startMouseY)
109 update_info drag.child, x, y
110 drag = nil
111
112 children.onmouseleave = (_, e) ->
113 return unless drag
114
115 drag.node.style.left = "#{drag.startX}px"
116 drag.node.style.top = "#{drag.startY}px"
117 drag = nil
118
119 article children
0 https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_480_1_5MG.mp4
0 {"x": 263.0, "y": 210.0, "w": 353.0, "h": 295.0}