acecalisto3 commited on
Commit
2fb7dde
·
verified ·
1 Parent(s): c3c427f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +244 -53
index.html CHANGED
@@ -3,24 +3,31 @@
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width" />
 
6
  <title>Smolagents and tools gallery</title>
7
  <meta name="description" content="Discover all smolagents and tools created by the community." />
 
8
  <meta property="og:url" content="https://smolagents-tools-gallery.hf.space/" />
9
  <meta property="og:type" content="website" />
10
  <meta property="og:title" content="smolagents and tools gallery" />
11
  <meta property="og:description" content="Discover all smolagents and tools created by the community." />
12
  <meta property="og:image" content="https://huggingface-projects-diffusers-gallery.hf.space/Fo6vR6JX0AEjbw1.jpeg" />
 
13
  <meta name="twitter:card" content="player" />
14
  <meta property="twitter:url" content="https://davidberenstein1957-smolagents-and-tools.static.hf.space" />
15
  <meta name="twitter:description" content="Discover all smolagents and tools created by the community." />
 
16
  <meta name="twitter:site" content="@huggingface" />
17
  <meta name="twitter:title" content="smolagents and tools gallery" />
 
18
  <meta name="twitter:image" content="https://huggingface-projects-diffusers-gallery.hf.space/Fo6vR6JX0AEjbw1.jpeg" />
19
  <meta name="twitter:player" content="https://davidberenstein1957-smolagents-and-tools.static.hf.space" />
20
  <meta name="twitter:player:width" content="100%" />
21
  <meta name="twitter:player:height" content="600" />
 
22
  <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
23
  <script src="https://cdn.tailwindcss.com"></script>
 
24
  <style>
25
  iframe {
26
  display: block;
@@ -30,22 +37,25 @@
30
  pointer-events: none;
31
  margin-top: 48px; /* Match header height */
32
  }
33
- .grid-container {
 
34
  display: grid;
35
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
36
  grid-gap: 10px;
37
  margin-top: 3.5rem;
38
  }
39
- .grid-item {
 
40
  position: relative;
41
  overflow-y: hidden;
42
  border-radius: 10px;
43
  border: 1px solid rgb(55 65 81);
44
  }
45
- .grid-item:hover {
46
  filter: brightness(75%);
47
  }
48
- .grid-item a {
 
49
  position: absolute;
50
  top: 0;
51
  left: 0;
@@ -54,7 +64,8 @@
54
  display: block;
55
  z-index: 1;
56
  }
57
- .grid-item-header {
 
58
  position: absolute;
59
  top: 0;
60
  left: 0;
@@ -67,7 +78,8 @@
67
  align-items: center;
68
  width: 100%;
69
  }
70
- .grid-item-header h2 {
 
71
  width: 100%;
72
  overflow-wrap: break-word;
73
  word-wrap: break-word;
@@ -79,18 +91,51 @@
79
  -webkit-box-orient: vertical;
80
  line-height: 1.2;
81
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  </style>
 
83
  <script type="module">
84
  import Alpine from "https://cdn.skypack.dev/[email protected]";
85
  import Intersect from "https://cdn.skypack.dev/@alpinejs/intersect";
86
  Alpine.plugin(Intersect);
 
87
  Alpine.data("themesData", () => ({
88
  async init() {
89
  const data = await this.getThemes(this.page, this.sort, this.useTestData);
90
  this.themes = data.themes;
91
  this.totalPages = data.totalPages;
92
  },
93
- themes:,
94
  filter: "tool",
95
  sort: "likes",
96
  page: 1,
@@ -98,21 +143,28 @@
98
  useTestData: false,
99
  searchQuery: "",
100
  searchType: "keyword",
101
- hfToken: "", // New property for Hugging Face token
102
- userSpaces:, // New property to store user spaces
 
 
 
 
 
103
  buttonClass(attr, filter) {
104
  if (this[attr] === filter) {
105
  return "text-orange-600 bg-gradient-to-br from-orange-300 to-orange-100 px-2 md:px-3 py-1 rounded-full";
106
  }
107
  return "text-gray-800 hover:to-orange-300/100 hover:text-orange-600 dark:hover:bg-white";
108
  },
 
109
  async switchData() {
110
  this.page = 1;
111
- this.useTestData =!this.useTestData;
112
  const data = await this.getThemes(this.page, this.sort, this.useTestData);
113
  this.themes = data.themes;
114
  this.totalPages = data.totalPages;
115
  },
 
116
  async sortThemes(sort) {
117
  this.sort = sort;
118
  this.page = 1;
@@ -120,6 +172,7 @@
120
  this.themes = data.themes;
121
  this.totalPages = data.totalPages;
122
  },
 
123
  async filterType(filter) {
124
  this.filter = filter;
125
  this.page = 1;
@@ -131,34 +184,21 @@
131
  this.totalPages = data.totalPages;
132
  }
133
  },
 
134
  async searchThemes() {
135
  this.page = 1;
136
  const data = await this.getThemes(this.page, this.sort, this.useTestData);
137
  this.themes = data.themes;
138
  this.totalPages = data.totalPages;
139
  },
 
140
  async switchSearchType(type) {
141
  this.searchType = type;
142
  if (this.searchQuery) {
143
  await this.searchThemes();
144
  }
145
  },
146
- async getUserSpaces() {
147
- if (!this.hfToken) {
148
- alert("Please enter your Hugging Face token.");
149
- return;
150
- }
151
- try {
152
- const res = await fetch(`https://huggingface.co/api/spaces?token=${this.hfToken}`);
153
- if (!res.ok) {
154
- throw new Error(`Failed to fetch spaces: ${res.status} ${res.statusText}`);
155
- }
156
- const data = await res.json();
157
- this.userSpaces = data;
158
- } catch (error) {
159
- alert(`Error fetching spaces: ${error.message}`);
160
- }
161
- },
162
  async getThemes(page, sort, useTestData) {
163
  let data;
164
  if (useTestData) {
@@ -167,38 +207,46 @@
167
  );
168
  data = await res.json();
169
  } else {
170
- const searchFilters = this.filter === 'tool'? 'tool': 'smolagents';
171
  let searchUrl;
172
  if (this.searchQuery) {
173
  if (this.searchType === 'semantic') {
174
- searchUrl = `https://huggingface.co/api/spaces/semantic-search?limit=100&filter=${searchFilters}&q=${encodeURIComponent(this.searchQuery)}&expand=subdomain&expand=lastModified&expand=likes&expand=runtime`;
175
  } else {
176
- searchUrl = `https://huggingface.co/api/spaces?limit=100&filter=${searchFilters}&search=${encodeURIComponent(this.searchQuery)}&expand=subdomain&expand=lastModified&expand=likes&expand=runtime`;
177
  }
178
  } else {
179
- searchUrl = `https://huggingface.co/api/spaces?limit=100&filter=${encodeURIComponent(searchFilters)}&expand=subdomain&expand=lastModified&expand=likes&expand=runtime`;
180
  }
181
  const res = await fetch(searchUrl);
182
  data = await res.json();
 
183
  // Transform the API response to match the expected format
184
  data = data.filter(item => item.runtime?.stage === "RUNNING").map(item => ({
185
  id: item.id,
186
  subdomain: `https://${item.subdomain}.hf.space`,
187
  likes: item.likes,
188
- lastModified: item.lastModified
 
189
  }));
190
  }
 
191
  if (sort === 'likes') {
192
  data.sort((a, b) => (b.likes - a.likes));
193
  } else {
194
  data.sort((a, b) => (new Date(b.lastModified) - new Date(a.lastModified)));
195
  }
 
196
  const pageThemes = data.slice((page - 1) * 15, page * 15);
 
 
 
197
  return {
198
  themes: pageThemes,
199
  totalPages: Math.ceil(data.length / 15)
200
  };
201
  },
 
202
  async nextPage() {
203
  if (this.page < this.totalPages) {
204
  this.page += 1;
@@ -207,27 +255,150 @@
207
  this.totalPages = data.totalPages;
208
  }
209
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  }));
211
  Alpine.start();
212
  </script>
213
  </head>
 
214
  <body class="pb-10 pt-5 bg-white relative">
215
  <section x-data="themesData">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  <section class="container px-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-14 mx-auto relative">
217
  <div class="col-span-2 lg:col-span-1 flex flex-col gap-14 row-start">
218
  <div class="flex items-center gap-2">
219
  <img src="https://camo.githubusercontent.com/a8c1f1d12aa3114010c6e74b29d47fee91d8da10a915f065c38e6d0ea7f16568/68747470733a2f2f68756767696e67666163652e636f2f64617461736574732f68756767696e67666163652f646f63756d656e746174696f6e2d696d616765732f7265736f6c76652f6d61696e2f736d6f6c6167656e74732f6d6173636f742e706e67" alt="Smolagents mascot" class="w-14 h-14 flex-shrink-0">
220
  <h1 class="text-xl font-semibold text-gray-800 break-words">smolagents and tools gallery</h1>
221
  </div>
222
- <div class="flex items-center gap-2">
223
- <input
224
- type="text"
225
- x-model="hfToken"
226
- placeholder="Enter your Hugging Face Token"
227
- class="px-3 py-1 border rounded-lg"
228
- >
229
- <button @click="getUserSpaces()" class="px-3 py-1 bg-blue-500 text-white rounded-lg">Import Spaces</button>
230
- </div>
231
  </div>
232
  <div class="col-span-2 md:col-span-3 flex items-center gap-14 flex flex-wrap lg-auto lg:ml-auto text-sm">
233
  <div class="flex flex-col gap-2">
@@ -243,26 +414,46 @@
243
  </div>
244
  <div class="flex gap-2">
245
  <span class="md:px-3 py-1 text-gray-800">type</span>
246
- <button:class="buttonClass('filter', 'tool')" @click="filterType('tool')">Tools</button>
247
- <button:class="buttonClass('filter', 'agent')" @click="filterType('agent')">Agents</button>
 
 
 
 
 
 
 
 
 
 
248
  </div>
249
  <div class="flex gap-2">
250
  <span class="md:px-3 py-1 text-gray-800">sort by</span>
251
- <button:class="buttonClass('sort', 'likes')" @click="sortThemes('likes')">Most Likes</button>
252
- <button:class="buttonClass('sort', 'recent')" @click="sortThemes('recent')">Recent</button>
 
 
 
 
 
 
 
 
 
 
253
  </div>
254
  </div>
255
  </section>
256
- <div class="container px-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2 mx-auto my-8 relative">
257
- <template x-for="theme in themes":key="theme.id">
258
- <div class="grid-item">
259
- <div class="grid-item-header">
260
- <h2 class="text-sm font-medium text-white" x-text="theme.id"></h2>
261
- </div>
262
- <iframe:src="`${theme.subdomain}?_=${new Date().getTime()}`":alt="theme.id" scrolling="no" frameborder="0" loading="lazy"></iframe>
263
- <a:href="`https://huggingface.co/spaces/${theme.id}`" target="_blank"></a>
264
  </div>
265
- </template>
 
 
 
266
  </div>
267
  <div class="h-12 relative" x-intersect="nextPage" data-iframe-height></div>
268
  </section>
 
3
  <head>
4
  <meta charset="utf-8" />
5
  <meta name="viewport" content="width=device-width" />
6
+
7
  <title>Smolagents and tools gallery</title>
8
  <meta name="description" content="Discover all smolagents and tools created by the community." />
9
+
10
  <meta property="og:url" content="https://smolagents-tools-gallery.hf.space/" />
11
  <meta property="og:type" content="website" />
12
  <meta property="og:title" content="smolagents and tools gallery" />
13
  <meta property="og:description" content="Discover all smolagents and tools created by the community." />
14
  <meta property="og:image" content="https://huggingface-projects-diffusers-gallery.hf.space/Fo6vR6JX0AEjbw1.jpeg" />
15
+
16
  <meta name="twitter:card" content="player" />
17
  <meta property="twitter:url" content="https://davidberenstein1957-smolagents-and-tools.static.hf.space" />
18
  <meta name="twitter:description" content="Discover all smolagents and tools created by the community." />
19
+
20
  <meta name="twitter:site" content="@huggingface" />
21
  <meta name="twitter:title" content="smolagents and tools gallery" />
22
+
23
  <meta name="twitter:image" content="https://huggingface-projects-diffusers-gallery.hf.space/Fo6vR6JX0AEjbw1.jpeg" />
24
  <meta name="twitter:player" content="https://davidberenstein1957-smolagents-and-tools.static.hf.space" />
25
  <meta name="twitter:player:width" content="100%" />
26
  <meta name="twitter:player:height" content="600" />
27
+
28
  <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
29
  <script src="https://cdn.tailwindcss.com"></script>
30
+
31
  <style>
32
  iframe {
33
  display: block;
 
37
  pointer-events: none;
38
  margin-top: 48px; /* Match header height */
39
  }
40
+
41
+ .grid-container {
42
  display: grid;
43
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
44
  grid-gap: 10px;
45
  margin-top: 3.5rem;
46
  }
47
+
48
+ .grid-item {
49
  position: relative;
50
  overflow-y: hidden;
51
  border-radius: 10px;
52
  border: 1px solid rgb(55 65 81);
53
  }
54
+ .grid-item:hover {
55
  filter: brightness(75%);
56
  }
57
+
58
+ .grid-item a {
59
  position: absolute;
60
  top: 0;
61
  left: 0;
 
64
  display: block;
65
  z-index: 1;
66
  }
67
+
68
+ .grid-item-header {
69
  position: absolute;
70
  top: 0;
71
  left: 0;
 
78
  align-items: center;
79
  width: 100%;
80
  }
81
+
82
+ .grid-item-header h2 {
83
  width: 100%;
84
  overflow-wrap: break-word;
85
  word-wrap: break-word;
 
91
  -webkit-box-orient: vertical;
92
  line-height: 1.2;
93
  }
94
+
95
+ /* Modal styles */
96
+ .modal-overlay {
97
+ position: fixed;
98
+ top: 0;
99
+ left: 0;
100
+ right: 0;
101
+ bottom: 0;
102
+ background: rgba(0,0,0,0.5);
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: center;
106
+ z-index: 1000;
107
+ }
108
+ .modal-content {
109
+ background: white;
110
+ padding: 2rem;
111
+ border-radius: 8px;
112
+ max-width: 600px;
113
+ width: 90%;
114
+ max-height: 80vh;
115
+ overflow-y: auto;
116
+ }
117
+ .space-item {
118
+ display: flex;
119
+ align-items: center;
120
+ gap: 1rem;
121
+ padding: 0.5rem;
122
+ border-bottom: 1px solid #eee;
123
+ }
124
+ [x-cloak] { display: none !important; }
125
  </style>
126
+
127
  <script type="module">
128
  import Alpine from "https://cdn.skypack.dev/[email protected]";
129
  import Intersect from "https://cdn.skypack.dev/@alpinejs/intersect";
130
  Alpine.plugin(Intersect);
131
+
132
  Alpine.data("themesData", () => ({
133
  async init() {
134
  const data = await this.getThemes(this.page, this.sort, this.useTestData);
135
  this.themes = data.themes;
136
  this.totalPages = data.totalPages;
137
  },
138
+ themes: [],
139
  filter: "tool",
140
  sort: "likes",
141
  page: 1,
 
143
  useTestData: false,
144
  searchQuery: "",
145
  searchType: "keyword",
146
+ showImport: false,
147
+ hfToken: '',
148
+ authenticated: false,
149
+ userSpaces: [],
150
+ selectedSpaces: [],
151
+ spaceTypes: {},
152
+
153
  buttonClass(attr, filter) {
154
  if (this[attr] === filter) {
155
  return "text-orange-600 bg-gradient-to-br from-orange-300 to-orange-100 px-2 md:px-3 py-1 rounded-full";
156
  }
157
  return "text-gray-800 hover:to-orange-300/100 hover:text-orange-600 dark:hover:bg-white";
158
  },
159
+
160
  async switchData() {
161
  this.page = 1;
162
+ this.useTestData = !this.useTestData;
163
  const data = await this.getThemes(this.page, this.sort, this.useTestData);
164
  this.themes = data.themes;
165
  this.totalPages = data.totalPages;
166
  },
167
+
168
  async sortThemes(sort) {
169
  this.sort = sort;
170
  this.page = 1;
 
172
  this.themes = data.themes;
173
  this.totalPages = data.totalPages;
174
  },
175
+
176
  async filterType(filter) {
177
  this.filter = filter;
178
  this.page = 1;
 
184
  this.totalPages = data.totalPages;
185
  }
186
  },
187
+
188
  async searchThemes() {
189
  this.page = 1;
190
  const data = await this.getThemes(this.page, this.sort, this.useTestData);
191
  this.themes = data.themes;
192
  this.totalPages = data.totalPages;
193
  },
194
+
195
  async switchSearchType(type) {
196
  this.searchType = type;
197
  if (this.searchQuery) {
198
  await this.searchThemes();
199
  }
200
  },
201
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  async getThemes(page, sort, useTestData) {
203
  let data;
204
  if (useTestData) {
 
207
  );
208
  data = await res.json();
209
  } else {
210
+ const searchFilters = this.filter === 'tool' ? 'tool' : 'smolagents';
211
  let searchUrl;
212
  if (this.searchQuery) {
213
  if (this.searchType === 'semantic') {
214
+ searchUrl = `https://huggingface.co/api/spaces/semantic-search?limit=100&filter=${searchFilters}&q=${encodeURIComponent(this.searchQuery)}&expand[]=subdomain&expand[]=lastModified&expand[]=likes&expand[]=runtime`;
215
  } else {
216
+ searchUrl = `https://huggingface.co/api/spaces?limit=100&filter=${searchFilters}&search=${encodeURIComponent(this.searchQuery)}&expand[]=subdomain&expand[]=lastModified&expand[]=likes&expand[]=runtime`;
217
  }
218
  } else {
219
+ searchUrl = `https://huggingface.co/api/spaces?limit=100&filter=${encodeURIComponent(searchFilters)}&expand[]=subdomain&expand[]=lastModified&expand[]=likes&expand[]=runtime`;
220
  }
221
  const res = await fetch(searchUrl);
222
  data = await res.json();
223
+ console.log(data)
224
  // Transform the API response to match the expected format
225
  data = data.filter(item => item.runtime?.stage === "RUNNING").map(item => ({
226
  id: item.id,
227
  subdomain: `https://${item.subdomain}.hf.space`,
228
  likes: item.likes,
229
+ lastModified: item.lastModified,
230
+ type: this.filter // Add type based on current filter
231
  }));
232
  }
233
+
234
  if (sort === 'likes') {
235
  data.sort((a, b) => (b.likes - a.likes));
236
  } else {
237
  data.sort((a, b) => (new Date(b.lastModified) - new Date(a.lastModified)));
238
  }
239
+
240
  const pageThemes = data.slice((page - 1) * 15, page * 15);
241
+
242
+ console.log(pageThemes);
243
+
244
  return {
245
  themes: pageThemes,
246
  totalPages: Math.ceil(data.length / 15)
247
  };
248
  },
249
+
250
  async nextPage() {
251
  if (this.page < this.totalPages) {
252
  this.page += 1;
 
255
  this.totalPages = data.totalPages;
256
  }
257
  },
258
+
259
+ async authenticate() {
260
+ try {
261
+ const response = await fetch('https://huggingface.co/api/whoami', {
262
+ headers: { Authorization: `Bearer ${this.hfToken}` }
263
+ });
264
+
265
+ if (!response.ok) throw new Error('Authentication failed');
266
+ const userData = await response.json();
267
+
268
+ const spacesRes = await fetch(
269
+ `https://huggingface.co/api/spaces?user=${userData.name}`,
270
+ { headers: { Authorization: `Bearer ${this.hfToken}` } }
271
+ );
272
+
273
+ const spacesData = await spacesRes.json();
274
+ this.userSpaces = spacesData
275
+ .filter(space => space.runtime?.stage === "RUNNING")
276
+ .map(space => ({
277
+ id: space.id,
278
+ subdomain: `https://${space.subdomain}.hf.space`,
279
+ likes: space.likes,
280
+ lastModified: space.lastModified
281
+ }));
282
+
283
+ this.spaceTypes = Object.fromEntries(
284
+ this.userSpaces.map(space => [space.id, 'tool'])
285
+ );
286
+ this.authenticated = true;
287
+ } catch (error) {
288
+ alert('Authentication failed: ' + error.message);
289
+ }
290
+ },
291
+
292
+ importSpaces() {
293
+ const newThemes = this.selectedSpaces.map(id => {
294
+ const space = this.userSpaces.find(s => s.id === id);
295
+ return {
296
+ ...space,
297
+ type: this.spaceTypes[id]
298
+ };
299
+ });
300
+
301
+ this.themes = [...this.themes, ...newThemes];
302
+ this.showImport = false;
303
+ this.hfToken = '';
304
+ this.authenticated = false;
305
+ this.userSpaces = [];
306
+ this.selectedSpaces = [];
307
+ },
308
  }));
309
  Alpine.start();
310
  </script>
311
  </head>
312
+
313
  <body class="pb-10 pt-5 bg-white relative">
314
  <section x-data="themesData">
315
+ <!-- Add Import Button -->
316
+ <div class="container px-6 mx-auto mb-4">
317
+ <button
318
+ @click="showImport = true"
319
+ class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
320
+ >
321
+ Import Your Spaces
322
+ </button>
323
+ </div>
324
+
325
+ <!-- Import Modal -->
326
+ <div x-show="showImport" class="modal-overlay" x-cloak>
327
+ <div class="modal-content">
328
+ <template x-if="!authenticated">
329
+ <div class="space-y-4">
330
+ <h3 class="text-xl font-bold">Authenticate with Hugging Face</h3>
331
+ <input
332
+ type="password"
333
+ x-model="hfToken"
334
+ placeholder="Enter your HF access token"
335
+ class="w-full p-2 border rounded"
336
+ />
337
+ <div class="flex gap-2">
338
+ <button
339
+ @click="authenticate()"
340
+ class="px-4 py-2 bg-green-600 text-white rounded"
341
+ >
342
+ Authenticate
343
+ </button>
344
+ <button
345
+ @click="showImport = false"
346
+ class="px-4 py-2 bg-gray-600 text-white rounded"
347
+ >
348
+ Cancel
349
+ </button>
350
+ </div>
351
+ </div>
352
+ </template>
353
+
354
+ <template x-if="authenticated">
355
+ <div class="space-y-4">
356
+ <h3 class="text-xl font-bold">Select Spaces to Import</h3>
357
+ <div class="space-y-2">
358
+ <template x-for="space in userSpaces" :key="space.id">
359
+ <div class="space-item">
360
+ <input
361
+ type="checkbox"
362
+ x-model="selectedSpaces"
363
+ :value="space.id"
364
+ >
365
+ <span x-text="space.id"></span>
366
+ <select
367
+ x-model="spaceTypes[space.id]"
368
+ class="ml-auto px-2 py-1 border rounded"
369
+ >
370
+ <option value="tool">Tool</option>
371
+ <option value="agent">Agent</option>
372
+ </select>
373
+ </div>
374
+ </template>
375
+ </div>
376
+ <div class="flex gap-2">
377
+ <button
378
+ @click="importSpaces()"
379
+ class="px-4 py-2 bg-blue-600 text-white rounded"
380
+ >
381
+ Import Selected
382
+ </button>
383
+ <button
384
+ @click="showImport = false"
385
+ class="px-4 py-2 bg-gray-600 text-white rounded"
386
+ >
387
+ Cancel
388
+ </button>
389
+ </div>
390
+ </div>
391
+ </template>
392
+ </div>
393
+ </div>
394
+
395
+ <!-- Existing header and grid remain unchanged -->
396
  <section class="container px-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-14 mx-auto relative">
397
  <div class="col-span-2 lg:col-span-1 flex flex-col gap-14 row-start">
398
  <div class="flex items-center gap-2">
399
  <img src="https://camo.githubusercontent.com/a8c1f1d12aa3114010c6e74b29d47fee91d8da10a915f065c38e6d0ea7f16568/68747470733a2f2f68756767696e67666163652e636f2f64617461736574732f68756767696e67666163652f646f63756d656e746174696f6e2d696d616765732f7265736f6c76652f6d61696e2f736d6f6c6167656e74732f6d6173636f742e706e67" alt="Smolagents mascot" class="w-14 h-14 flex-shrink-0">
400
  <h1 class="text-xl font-semibold text-gray-800 break-words">smolagents and tools gallery</h1>
401
  </div>
 
 
 
 
 
 
 
 
 
402
  </div>
403
  <div class="col-span-2 md:col-span-3 flex items-center gap-14 flex flex-wrap lg-auto lg:ml-auto text-sm">
404
  <div class="flex flex-col gap-2">
 
414
  </div>
415
  <div class="flex gap-2">
416
  <span class="md:px-3 py-1 text-gray-800">type</span>
417
+ <button
418
+ :class="buttonClass('filter', 'tool')"
419
+ @click="filterType('tool')"
420
+ >
421
+ Tools
422
+ </button>
423
+ <button
424
+ :class="buttonClass('filter', 'agent')"
425
+ @click="filterType('agent')"
426
+ >
427
+ Agents
428
+ </button>
429
  </div>
430
  <div class="flex gap-2">
431
  <span class="md:px-3 py-1 text-gray-800">sort by</span>
432
+ <button
433
+ :class="buttonClass('sort', 'likes')"
434
+ @click="sortThemes('likes')"
435
+ >
436
+ Most Likes
437
+ </button>
438
+ <button
439
+ :class="buttonClass('sort', 'recent')"
440
+ @click="sortThemes('recent')"
441
+ >
442
+ Recent
443
+ </button>
444
  </div>
445
  </div>
446
  </section>
447
+ <div class="container px-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2 mx-auto my-8 relative">
448
+ <template x-for="theme in themes" :key="theme.id">
449
+ <div class="grid-item">
450
+ <div class="grid-item-header">
451
+ <h2 class="text-sm font-medium text-white" x-text="theme.id"></h2>
 
 
 
452
  </div>
453
+ <iframe :src="`${theme.subdomain}?_=${new Date().getTime()}`" :alt="theme.id" scrolling="no" frameborder="0" loading="lazy"></iframe>
454
+ <a :href="`https://huggingface.co/spaces/${theme.id}`" target="_blank"></a>
455
+ </div>
456
+ </template>
457
  </div>
458
  <div class="h-12 relative" x-intersect="nextPage" data-iframe-height></div>
459
  </section>