Update index.html
Browse files- index.html +64 -33
index.html
CHANGED
@@ -16,29 +16,48 @@
|
|
16 |
<script type="text/javascript">
|
17 |
const { useState, useEffect } = React;
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
function parseRankTeam(
|
23 |
-
const name =
|
24 |
const m = name.match(/^(\d+)-(\d+)-/);
|
25 |
return m ? { rank: +m[1], team: +m[2] } : { rank: null, team: null };
|
26 |
}
|
27 |
|
28 |
function App() {
|
|
|
29 |
const [videos, setVideos] = useState([]);
|
30 |
const [teamDatasets, setTeamDatasets] = useState({});
|
31 |
|
32 |
useEffect(() => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
async function fetchAssets() {
|
34 |
-
|
35 |
const tree = await (
|
36 |
await fetch(
|
37 |
"https://huggingface.co/api/datasets/maringetxway/all-winners/tree/main"
|
38 |
)
|
39 |
).json();
|
40 |
|
41 |
-
const
|
42 |
.filter((f) => f.path.endsWith(".mp4"))
|
43 |
.map((f) => {
|
44 |
const { rank, team } = parseRankTeam(f.path);
|
@@ -51,16 +70,16 @@
|
|
51 |
};
|
52 |
})
|
53 |
.sort((a, b) => a.rank - b.rank);
|
54 |
-
setVideos(
|
55 |
|
56 |
-
|
57 |
-
const
|
58 |
await fetch(
|
59 |
"https://huggingface.co/api/datasets?author=maringetxway"
|
60 |
)
|
61 |
).json();
|
62 |
const map = {};
|
63 |
-
|
64 |
const m = id.match(/maringetxway\/team[_-]?(\d+)/i);
|
65 |
if (m) {
|
66 |
const t = +m[1];
|
@@ -73,30 +92,39 @@
|
|
73 |
setTeamDatasets(map);
|
74 |
}
|
75 |
|
|
|
76 |
fetchAssets();
|
77 |
}, []);
|
78 |
|
79 |
return React.createElement(
|
80 |
"div",
|
81 |
{ className: "min-h-screen py-10 px-4 max-w-3xl mx-auto" },
|
82 |
-
/*
|
83 |
React.createElement(
|
84 |
"h1",
|
85 |
{
|
86 |
className:
|
87 |
-
"text-center text-4xl font-bold text-white mb-
|
88 |
},
|
89 |
"LeRobot Worldwide Hackathon – Winners"
|
90 |
),
|
91 |
-
|
92 |
React.createElement(
|
93 |
"p",
|
94 |
{
|
95 |
className:
|
96 |
-
"
|
97 |
},
|
98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
),
|
|
|
100 |
React.createElement(
|
101 |
"p",
|
102 |
{
|
@@ -108,7 +136,7 @@
|
|
108 |
/* Logos */
|
109 |
React.createElement(
|
110 |
"div",
|
111 |
-
{ className: "flex justify-center items-center gap-6 mb-
|
112 |
React.createElement("img", {
|
113 |
src: "seeedstudio.png",
|
114 |
alt: "Seeed Studio logo",
|
@@ -120,7 +148,23 @@
|
|
120 |
className: "h-12 w-auto",
|
121 |
})
|
122 |
),
|
123 |
-
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
...videos.map((video, idx) =>
|
125 |
React.createElement(
|
126 |
"section",
|
@@ -163,7 +207,7 @@
|
|
163 |
)
|
164 |
)
|
165 |
),
|
166 |
-
/* Sponsors
|
167 |
React.createElement(
|
168 |
"div",
|
169 |
{
|
@@ -171,17 +215,4 @@
|
|
171 |
"bg-white rounded-xl shadow-lg p-8 mt-20 flex justify-center",
|
172 |
},
|
173 |
React.createElement("img", {
|
174 |
-
src
|
175 |
-
alt: "Sponsors",
|
176 |
-
className: "max-w-full h-auto",
|
177 |
-
})
|
178 |
-
)
|
179 |
-
);
|
180 |
-
}
|
181 |
-
|
182 |
-
ReactDOM.createRoot(document.getElementById("root")).render(
|
183 |
-
React.createElement(App)
|
184 |
-
);
|
185 |
-
</script>
|
186 |
-
</body>
|
187 |
-
</html>
|
|
|
16 |
<script type="text/javascript">
|
17 |
const { useState, useEffect } = React;
|
18 |
|
19 |
+
const INTRO_VIDEO_DATASET = "imstevenpmwork/hackaton_closure/";
|
20 |
+
|
21 |
+
/* Extract rank & team from filename "<rank>-<team>-....mp4" */
|
22 |
+
function parseRankTeam(path) {
|
23 |
+
const name = path.split("/").pop();
|
24 |
const m = name.match(/^(\d+)-(\d+)-/);
|
25 |
return m ? { rank: +m[1], team: +m[2] } : { rank: null, team: null };
|
26 |
}
|
27 |
|
28 |
function App() {
|
29 |
+
const [introSrc, setIntroSrc] = useState(null);
|
30 |
const [videos, setVideos] = useState([]);
|
31 |
const [teamDatasets, setTeamDatasets] = useState({});
|
32 |
|
33 |
useEffect(() => {
|
34 |
+
async function fetchIntro() {
|
35 |
+
try {
|
36 |
+
// Use datasets‑server rows endpoint: grab first row, field "video"
|
37 |
+
const rowsRes = await fetch(
|
38 |
+
`https://datasets-server.huggingface.co/rows?dataset=${INTRO_VIDEO_DATASET}&config=default&split=train&offset=0&limit=1`
|
39 |
+
);
|
40 |
+
const rowsJson = await rowsRes.json();
|
41 |
+
const row = rowsJson.rows?.[0]?.row;
|
42 |
+
if (row) {
|
43 |
+
// assume the field storing the file path is called "video" or similar
|
44 |
+
const videoUrl = row.video || Object.values(row).find((v) => typeof v === "string" && v.endsWith(".mp4"));
|
45 |
+
if (videoUrl) setIntroSrc(videoUrl);
|
46 |
+
}
|
47 |
+
} catch (e) {
|
48 |
+
console.error("Could not load intro video", e);
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
async function fetchAssets() {
|
53 |
+
/* 1️⃣ ranked videos */
|
54 |
const tree = await (
|
55 |
await fetch(
|
56 |
"https://huggingface.co/api/datasets/maringetxway/all-winners/tree/main"
|
57 |
)
|
58 |
).json();
|
59 |
|
60 |
+
const vids = tree
|
61 |
.filter((f) => f.path.endsWith(".mp4"))
|
62 |
.map((f) => {
|
63 |
const { rank, team } = parseRankTeam(f.path);
|
|
|
70 |
};
|
71 |
})
|
72 |
.sort((a, b) => a.rank - b.rank);
|
73 |
+
setVideos(vids);
|
74 |
|
75 |
+
/* 2️⃣ datasets per team (links) */
|
76 |
+
const ds = await (
|
77 |
await fetch(
|
78 |
"https://huggingface.co/api/datasets?author=maringetxway"
|
79 |
)
|
80 |
).json();
|
81 |
const map = {};
|
82 |
+
ds.forEach(({ id }) => {
|
83 |
const m = id.match(/maringetxway\/team[_-]?(\d+)/i);
|
84 |
if (m) {
|
85 |
const t = +m[1];
|
|
|
92 |
setTeamDatasets(map);
|
93 |
}
|
94 |
|
95 |
+
fetchIntro();
|
96 |
fetchAssets();
|
97 |
}, []);
|
98 |
|
99 |
return React.createElement(
|
100 |
"div",
|
101 |
{ className: "min-h-screen py-10 px-4 max-w-3xl mx-auto" },
|
102 |
+
/* Title */
|
103 |
React.createElement(
|
104 |
"h1",
|
105 |
{
|
106 |
className:
|
107 |
+
"text-center text-4xl font-bold text-white mb-6 drop-shadow-lg",
|
108 |
},
|
109 |
"LeRobot Worldwide Hackathon – Winners"
|
110 |
),
|
111 |
+
/* Intro with mixed weight */
|
112 |
React.createElement(
|
113 |
"p",
|
114 |
{
|
115 |
className:
|
116 |
+
"text-white text-center whitespace-pre-line mb-6 leading-relaxed",
|
117 |
},
|
118 |
+
[
|
119 |
+
React.createElement(
|
120 |
+
"span",
|
121 |
+
{ key: "bold", className: "font-bold" },
|
122 |
+
"🏆 €15,000 in robotics hardware prizes in collaboration with Seeedstudio"
|
123 |
+
),
|
124 |
+
" to support prizes for 10 winning teams and help us celebrate open-source robotics on a global scale! "
|
125 |
+
]
|
126 |
),
|
127 |
+
/* Prize breakdown */
|
128 |
React.createElement(
|
129 |
"p",
|
130 |
{
|
|
|
136 |
/* Logos */
|
137 |
React.createElement(
|
138 |
"div",
|
139 |
+
{ className: "flex justify-center items-center gap-6 mb-10" },
|
140 |
React.createElement("img", {
|
141 |
src: "seeedstudio.png",
|
142 |
alt: "Seeed Studio logo",
|
|
|
148 |
className: "h-12 w-auto",
|
149 |
})
|
150 |
),
|
151 |
+
/* Stand‑alone intro video */
|
152 |
+
introSrc &&
|
153 |
+
React.createElement(
|
154 |
+
"section",
|
155 |
+
{ className: "mb-16" },
|
156 |
+
React.createElement(
|
157 |
+
"h2",
|
158 |
+
{ className: "sr-only" },
|
159 |
+
"Intro video"
|
160 |
+
),
|
161 |
+
React.createElement("video", {
|
162 |
+
src: introSrc,
|
163 |
+
controls: true,
|
164 |
+
className: "w-full rounded-xl shadow-2xl mb-10",
|
165 |
+
})
|
166 |
+
),
|
167 |
+
/* Ranked video list */
|
168 |
...videos.map((video, idx) =>
|
169 |
React.createElement(
|
170 |
"section",
|
|
|
207 |
)
|
208 |
)
|
209 |
),
|
210 |
+
/* Sponsors */
|
211 |
React.createElement(
|
212 |
"div",
|
213 |
{
|
|
|
215 |
"bg-white rounded-xl shadow-lg p-8 mt-20 flex justify-center",
|
216 |
},
|
217 |
React.createElement("img", {
|
218 |
+
src
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|