-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathclient-demo.html
More file actions
171 lines (141 loc) · 7.33 KB
/
client-demo.html
File metadata and controls
171 lines (141 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<meta charset="UTF-8">
<body style="margin: 0; padding: 0; font-family: sans-serif; background: #f5f5f5; height: 100vh; display: flex; flex-direction: column; overflow: hidden;">
<div style="text-align: center; padding: 12px 0; flex-shrink: 0;">
<h2 style="margin: 0;">Braid Blob Client Demo</h2>
<div style="color: #888; font-size: 14px; margin-top: 4px;">every cell pointing to /blob.png — drop into any, sync to all</div>
<div style="color: #888; font-size: 14px; margin-top: 2px;">we keep the latest version, and propagate content-type too</div>
</div>
<div id="grid-container" style="flex: 1; display: flex; align-items: center; justify-content: center; padding: 12px; box-sizing: border-box; min-height: 0;">
<div id="grid" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;"></div>
</div>
</body>
<script src="https://unpkg.com/braid-http@~1.3/braid-http-client.js"></script>
<script src="/client.js"></script>
<script>
var blob_url = `${location.origin}/blob.png`
var cells = []
var meta_height = 32 // approximate height for version/type text
var cell_padding = 12
var gap = 12
for (var i = 0; i < 9; i++) create_cell(i)
resize_grid()
window.addEventListener('resize', resize_grid)
function resize_grid() {
var container = document.getElementById('grid-container')
var grid = document.getElementById('grid')
var available_w = container.clientWidth - 24 // padding
var available_h = container.clientHeight - 24
// Calculate max cell size that fits 3x3 grid
// Each cell has: padding + image + padding + meta
// Grid has gaps between cells
var max_cell_w = (available_w - gap * 2) / 3
var max_cell_h = (available_h - gap * 2) / 3
// Image size = cell size - padding*2 - meta_height
var img_from_w = max_cell_w - cell_padding * 2
var img_from_h = max_cell_h - cell_padding * 2 - meta_height
var img_size = Math.floor(Math.min(img_from_w, img_from_h))
var cell_size = img_size + cell_padding * 2 + meta_height
grid.style.width = (cell_size * 3 + gap * 2) + 'px'
grid.style.height = (cell_size * 3 + gap * 2) + 'px'
grid.style.gridTemplateColumns = `repeat(3, ${cell_size}px)`
grid.style.gridTemplateRows = `repeat(3, ${cell_size}px)`
for (var c of cells) {
c.img_container.style.width = img_size + 'px'
c.img_container.style.height = img_size + 'px'
}
}
function create_cell(index) {
var grid = document.getElementById('grid')
var cell = document.createElement('div')
cell.style.cssText = 'background: white; border-radius: 8px; padding: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); position: relative; overflow: hidden; box-sizing: border-box;'
grid.appendChild(cell)
var img_container = document.createElement('div')
img_container.style.cssText = 'display: flex; align-items: center; justify-content: center; background: #fafafa; border-radius: 4px; margin-bottom: 8px; overflow: hidden; position: relative;'
cell.appendChild(img_container)
var img = document.createElement('img')
img.style.cssText = 'max-width: 100%; max-height: 100%; object-fit: contain;'
img_container.appendChild(img)
var status = document.createElement('div')
status.style.cssText = 'position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #999; font-size: 14px;'
status.textContent = 'Connecting...'
img_container.appendChild(status)
var meta = document.createElement('div')
meta.style.cssText = 'font-size: 11px; color: #666; line-height: 1.4;'
cell.appendChild(meta)
var version_el = document.createElement('div')
version_el.style.cssText = 'white-space: nowrap; overflow: hidden; text-overflow: ellipsis;'
version_el.innerHTML = '<span style="color: #999;">v:</span> -'
meta.appendChild(version_el)
var type_el = document.createElement('div')
type_el.style.cssText = 'white-space: nowrap; overflow: hidden; text-overflow: ellipsis;'
type_el.innerHTML = '<span style="color: #999;">type:</span> -'
meta.appendChild(type_el)
var drop_overlay = document.createElement('div')
drop_overlay.style.cssText = 'display: none; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 100, 200, 0.85); border-radius: 8px; justify-content: center; align-items: center; color: white; font-size: 14px; font-weight: 500;'
drop_overlay.textContent = 'Drop to upload'
cell.appendChild(drop_overlay)
var current_object_url = null
cells.push({ img_container })
var client = braid_blob_client(blob_url, {
peer: Math.random().toString(36).slice(2, 5),
on_update: (body, content_type, version) => {
status.style.display = 'none'
version_el.innerHTML = `<span style="color: #999;">v:</span> ${version || '-'}`
type_el.innerHTML = `<span style="color: #999;">type:</span> ${content_type || '-'}`
if (current_object_url) URL.revokeObjectURL(current_object_url)
var image_blob = new Blob([body], { type: content_type || 'image/png' })
current_object_url = URL.createObjectURL(image_blob)
img.src = current_object_url
},
on_error: () => {
status.textContent = 'Connecting...'
status.style.display = 'block'
},
on_delete: () => {
status.textContent = 'No image'
status.style.display = 'block'
img.src = ''
version_el.innerHTML = '<span style="color: #999;">v:</span> -'
type_el.innerHTML = '<span style="color: #999;">type:</span> -'
if (current_object_url) {
URL.revokeObjectURL(current_object_url)
current_object_url = null
}
}
})
// Drag and drop handling for this cell
var drag_counter = 0
cell.addEventListener('dragenter', (e) => {
e.preventDefault()
e.stopPropagation()
drag_counter++
if (drag_counter === 1) drop_overlay.style.display = 'flex'
})
cell.addEventListener('dragleave', (e) => {
e.preventDefault()
e.stopPropagation()
drag_counter--
if (drag_counter === 0) drop_overlay.style.display = 'none'
})
cell.addEventListener('dragover', (e) => {
e.preventDefault()
e.stopPropagation()
})
cell.addEventListener('drop', async (e) => {
e.preventDefault()
e.stopPropagation()
drag_counter = 0
drop_overlay.style.display = 'none'
var file = e.dataTransfer.files[0]
if (!file) return
try {
var body = await file.arrayBuffer()
await client.update(body, file.type || 'application/octet-stream')
} catch (err) {
status.textContent = 'Upload failed'
status.style.display = 'block'
console.error('Upload error:', err)
}
})
}
</script>