Skip to content

Commit 50b951b

Browse files
add publicTypeIndex.html
1 parent a337c57 commit 50b951b

File tree

1 file changed

+343
-0
lines changed

1 file changed

+343
-0
lines changed

publicTypeIndex.html

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Type Index Viewer</title>
7+
8+
<!-- Preact -->
9+
<script src="https://unpkg.com/preact@10.15.1/dist/preact.min.js"></script>
10+
<script src="https://unpkg.com/preact@10.15.1/hooks/dist/hooks.umd.js"></script>
11+
12+
<!-- Tailwind CSS -->
13+
<script src="https://cdn.tailwindcss.com"></script>
14+
<script>
15+
tailwind.config = {
16+
theme: {
17+
extend: {
18+
colors: {
19+
primary: {
20+
50: '#f5f7ff',
21+
100: '#ebf0fe',
22+
200: '#d6e0fd',
23+
300: '#b3c7fc',
24+
400: '#8aa6f9',
25+
500: '#6684f6',
26+
600: '#4c64eb',
27+
700: '#3e4fd8',
28+
800: '#3642b0',
29+
900: '#303c8c'
30+
},
31+
secondary: {
32+
50: '#f5fdf9',
33+
100: '#ecfaf3',
34+
200: '#d0f5e6',
35+
300: '#a7ebd1',
36+
400: '#6ddab3',
37+
500: '#41c79a',
38+
600: '#2aa47f',
39+
700: '#238468',
40+
800: '#1f6954',
41+
900: '#1b5646'
42+
},
43+
accent: {
44+
50: '#fdf6f5',
45+
100: '#fbecea',
46+
200: '#f8d5d1',
47+
300: '#f3b3ac',
48+
400: '#ea8277',
49+
500: '#e05d4f',
50+
600: '#cf3c2d',
51+
700: '#ac3126',
52+
800: '#8c2c24',
53+
900: '#732a23'
54+
}
55+
}
56+
}
57+
}
58+
}
59+
</script>
60+
61+
<style type="text/css">
62+
body {
63+
background-color: #f9f7f7;
64+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
65+
Helvetica, Arial, sans-serif;
66+
}
67+
68+
.card-hover {
69+
transition: all 0.3s ease;
70+
}
71+
72+
.card-hover:hover {
73+
transform: translateY(-5px);
74+
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1),
75+
0 10px 10px -5px rgba(0, 0, 0, 0.04);
76+
}
77+
</style>
78+
</head>
79+
<body>
80+
<div id="app"></div>
81+
82+
<script type="module">
83+
const { h, render } = preact
84+
const { useState, useEffect } = preactHooks
85+
86+
const App = () => {
87+
const [typeIndex, setTypeIndex] = useState([])
88+
const [loading, setLoading] = useState(true)
89+
const [error, setError] = useState(null)
90+
91+
useEffect(() => {
92+
// Fetch the type index data
93+
fetch('./publicTypeIndex.json')
94+
.then(response => {
95+
if (!response.ok) {
96+
throw new Error('Failed to load type index')
97+
}
98+
return response.json()
99+
})
100+
.then(data => {
101+
setTypeIndex(data)
102+
setLoading(false)
103+
})
104+
.catch(err => {
105+
console.error('Error loading type index:', err)
106+
setError(err.message)
107+
setLoading(false)
108+
109+
// Use the example data as fallback
110+
const exampleData = [
111+
{
112+
type: 'TypeRegistration',
113+
forClass: 'Tracker',
114+
instance: '/public/todo/todo.json'
115+
},
116+
{
117+
type: 'TypeRegistration',
118+
forClass: 'Tracker',
119+
instance: '/public/todo/later.json'
120+
},
121+
{
122+
type: 'TypeRegistration',
123+
forClass: 'Tracker',
124+
instance: '/public/todo/someday.json'
125+
},
126+
{
127+
type: 'TypeRegistration',
128+
forClass: 'Tracker',
129+
instance: '/public/todo/chores.json'
130+
},
131+
{
132+
type: 'TypeRegistration',
133+
forClass: 'BookmarkCollection',
134+
instance: '/public/bookmark/bookmark.json'
135+
},
136+
{
137+
type: 'TypeRegistration',
138+
forClass: 'BookmarkCollection',
139+
instance: '/public/bookmark/toread.json'
140+
},
141+
{
142+
type: 'TypeRegistration',
143+
forClass: 'BookmarkCollection',
144+
instance: '/public/bookmark/work.json'
145+
},
146+
{
147+
type: 'TypeRegistration',
148+
forClass: 'Wallet',
149+
instance: '/public/wallet/index.json'
150+
}
151+
]
152+
setTypeIndex(exampleData)
153+
})
154+
}, [])
155+
156+
// Group the type index by forClass
157+
const groupedByClass = typeIndex.reduce((acc, item) => {
158+
const { forClass } = item
159+
if (!acc[forClass]) {
160+
acc[forClass] = []
161+
}
162+
acc[forClass].push(item)
163+
return acc
164+
}, {})
165+
166+
// Get icon for each type
167+
const getIconForType = type => {
168+
switch (type) {
169+
case 'Tracker':
170+
return `
171+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
172+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />
173+
</svg>
174+
`
175+
case 'BookmarkCollection':
176+
return `
177+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
178+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z" />
179+
</svg>
180+
`
181+
case 'Wallet':
182+
return `
183+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
184+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
185+
</svg>
186+
`
187+
default:
188+
return `
189+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
190+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
191+
</svg>
192+
`
193+
}
194+
}
195+
196+
// Get color for each type
197+
const getColorForType = type => {
198+
switch (type) {
199+
case 'Tracker':
200+
return 'primary'
201+
case 'BookmarkCollection':
202+
return 'secondary'
203+
case 'Wallet':
204+
return 'accent'
205+
default:
206+
return 'primary'
207+
}
208+
}
209+
210+
// Get a friendly name from the instance path
211+
const getFriendlyName = instance => {
212+
// Extract the filename without extension
213+
const parts = instance.split('/')
214+
const filename = parts[parts.length - 1]
215+
const nameWithoutExt = filename.replace('.json', '')
216+
217+
// Convert to title case and replace hyphens/underscores with spaces
218+
return nameWithoutExt
219+
.replace(/[-_]/g, ' ')
220+
.replace(/\b\w/g, l => l.toUpperCase())
221+
}
222+
223+
if (loading) {
224+
return h(
225+
'div',
226+
{ class: 'flex items-center justify-center min-h-screen' },
227+
h(
228+
'div',
229+
{ class: 'text-center' },
230+
h('div', {
231+
class:
232+
'animate-spin rounded-full h-12 w-12 border-b-2 border-primary-500 mx-auto'
233+
}),
234+
h(
235+
'p',
236+
{ class: 'mt-4 text-lg text-gray-600' },
237+
'Loading type index...'
238+
)
239+
)
240+
)
241+
}
242+
243+
return h(
244+
'div',
245+
{ class: 'container mx-auto px-4 py-8 max-w-6xl' },
246+
h(
247+
'header',
248+
{ class: 'mb-12 text-center' },
249+
h(
250+
'h1',
251+
{ class: 'text-4xl font-bold text-gray-800 mb-4' },
252+
'Type Index Viewer'
253+
),
254+
h(
255+
'p',
256+
{ class: 'text-lg text-gray-600 max-w-2xl mx-auto' },
257+
'Click on any item to open the corresponding application with the selected instance.'
258+
),
259+
error &&
260+
h(
261+
'div',
262+
{ class: 'mt-4 p-4 bg-red-100 text-red-800 rounded-lg' },
263+
h('p', {}, `Error: ${error}`),
264+
h(
265+
'p',
266+
{ class: 'text-sm mt-2' },
267+
'Using example data as fallback.'
268+
)
269+
)
270+
),
271+
272+
Object.entries(groupedByClass).map(([className, items]) => {
273+
const colorClass = getColorForType(className)
274+
275+
return h(
276+
'section',
277+
{ class: 'mb-12' },
278+
h(
279+
'div',
280+
{ class: `mb-6 flex items-center` },
281+
h('div', {
282+
class: `w-10 h-10 rounded-full flex items-center justify-center mr-3 bg-${colorClass}-100 text-${colorClass}-600`,
283+
dangerouslySetInnerHTML: { __html: getIconForType(className) }
284+
}),
285+
h(
286+
'h2',
287+
{ class: 'text-2xl font-bold text-gray-800' },
288+
className
289+
)
290+
),
291+
h(
292+
'div',
293+
{
294+
class: 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6'
295+
},
296+
items.map(item => {
297+
const appUrl = `?uri=${encodeURIComponent(item.instance)}`
298+
const friendlyName = getFriendlyName(item.instance)
299+
300+
return h(
301+
'a',
302+
{
303+
href: appUrl,
304+
class: `card-hover block p-6 rounded-lg bg-white shadow-md border border-${colorClass}-100 hover:border-${colorClass}-300`
305+
},
306+
h(
307+
'div',
308+
{ class: 'flex items-start' },
309+
h('div', {
310+
class: `w-8 h-8 rounded-full flex items-center justify-center mr-3 bg-${colorClass}-100 text-${colorClass}-600`,
311+
dangerouslySetInnerHTML: {
312+
__html: getIconForType(className)
313+
}
314+
}),
315+
h(
316+
'div',
317+
{ class: 'flex-1' },
318+
h(
319+
'h3',
320+
{
321+
class: `text-lg font-semibold text-${colorClass}-700 mb-1`
322+
},
323+
friendlyName
324+
),
325+
h(
326+
'p',
327+
{ class: 'text-sm text-gray-500 break-all' },
328+
item.instance
329+
)
330+
)
331+
)
332+
)
333+
})
334+
)
335+
)
336+
})
337+
)
338+
}
339+
340+
render(h(App), document.getElementById('app'))
341+
</script>
342+
</body>
343+
</html>

0 commit comments

Comments
 (0)