main
erb 145 lines 8.15 KB
Raw
1 <% content_for :title, "Models" %>
2 <% content_for :description, "Browse open-weights models on siGit — full model cards, LFS-backed files, and ready-to-pull weights." %>
3
4 <div class="max-w-6xl mx-auto px-4 sm:px-6 py-8">
5
6 <div class="flex items-end justify-between gap-4 mb-6 flex-wrap">
7 <div>
8 <h1 class="text-2xl font-semibold text-gray-100 flex items-center gap-2">
9 <svg class="w-6 h-6 text-brand-500" viewBox="0 0 24 24" fill="none"
10 stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
11 <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/>
12 <path d="m3.27 6.96 8.73 5.05 8.73-5.05M12 22.08V12"/>
13 </svg>
14 Models
15 <span class="badge-gray text-sm align-middle"><%= number_with_delimiter(@models.size) %></span>
16 </h1>
17 <p class="text-sm text-gray-400 mt-1">Open-weights models hosted on siGit, ready to download and run.</p>
18 </div>
19 <% if signed_in? %>
20 <%= link_to new_repository_path(kind: "model"), class: "btn-primary text-xs py-2 px-4" do %>
21 <svg class="w-3.5 h-3.5" viewBox="0 0 16 16" fill="currentColor"><path d="M7.75 2a.75.75 0 0 1 .75.75V7h4.25a.75.75 0 0 1 0 1.5H8.5v4.25a.75.75 0 0 1-1.5 0V8.5H2.75a.75.75 0 0 1 0-1.5H7V2.75A.75.75 0 0 1 7.75 2Z"/></svg>
22 New model
23 <% end %>
24 <% end %>
25 </div>
26
27 <div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
28
29 <%# ── Filter sidebar ── %>
30 <aside class="lg:col-span-1 space-y-6">
31 <% if @facets[:pipeline_tags].any? %>
32 <div>
33 <h2 class="text-xs uppercase tracking-wider text-gray-500 font-semibold mb-2">Tasks</h2>
34 <ul class="space-y-0.5">
35 <% @facets[:pipeline_tags].each do |tag, count| %>
36 <li>
37 <%= link_to models_path(request.query_parameters.merge(pipeline_tag: (@pipeline_tag == tag ? nil : tag)).compact),
38 class: "flex items-center justify-between px-2 py-1 rounded text-sm #{@pipeline_tag == tag ? 'bg-brand-500/10 text-brand-400' : 'text-gray-400 hover:bg-surface-700'}" do %>
39 <span class="truncate"><%= pipeline_label(tag) %></span>
40 <span class="text-xs text-gray-500"><%= count %></span>
41 <% end %>
42 </li>
43 <% end %>
44 </ul>
45 </div>
46 <% end %>
47
48 <% if @facets[:libraries].any? %>
49 <div>
50 <h2 class="text-xs uppercase tracking-wider text-gray-500 font-semibold mb-2">Libraries</h2>
51 <ul class="space-y-0.5">
52 <% @facets[:libraries].each do |lib, count| %>
53 <li>
54 <%= link_to models_path(request.query_parameters.merge(library: (@library == lib ? nil : lib)).compact),
55 class: "flex items-center justify-between px-2 py-1 rounded text-sm #{@library == lib ? 'bg-brand-500/10 text-brand-400' : 'text-gray-400 hover:bg-surface-700'}" do %>
56 <span class="truncate"><%= lib %></span>
57 <span class="text-xs text-gray-500"><%= count %></span>
58 <% end %>
59 </li>
60 <% end %>
61 </ul>
62 </div>
63 <% end %>
64
65 <% if @pipeline_tag || @library || @query.present? %>
66 <%= link_to "Clear filters", models_path, class: "text-xs text-brand-500 hover:underline" %>
67 <% end %>
68 </aside>
69
70 <%# ── Results ── %>
71 <main class="lg:col-span-3">
72 <div class="flex items-center gap-3 mb-4">
73 <%= form_with url: models_path, method: :get, class: "flex-1" do %>
74 <% if @pipeline_tag %><%= hidden_field_tag :pipeline_tag, @pipeline_tag %><% end %>
75 <% if @library %><%= hidden_field_tag :library, @library %><% end %>
76 <%= hidden_field_tag :sort, @sort %>
77 <div class="relative">
78 <svg class="w-4 h-4 text-gray-500 absolute left-3 top-1/2 -translate-y-1/2" viewBox="0 0 16 16" fill="currentColor"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-1.06 1.06ZM11.5 7a4.5 4.5 0 1 0-9 0 4.5 4.5 0 0 0 9 0Z"/></svg>
79 <%= text_field_tag :q, @query, placeholder: "Search models by name or tag…",
80 class: "form-input pl-9", autocomplete: "off" %>
81 </div>
82 <% end %>
83 <%= form_with url: models_path, method: :get, class: "shrink-0", id: "sort-form" do %>
84 <% if @query.present? %><%= hidden_field_tag :q, @query %><% end %>
85 <% if @pipeline_tag %><%= hidden_field_tag :pipeline_tag, @pipeline_tag %><% end %>
86 <% if @library %><%= hidden_field_tag :library, @library %><% end %>
87 <%= select_tag :sort,
88 options_for_select([["Trending", "trending"], ["Most likes", "likes"], ["Most downloads", "downloads"], ["Recently updated", "recent"]], @sort),
89 class: "form-input py-2 pr-8 text-sm", onchange: "this.form.submit()" %>
90 <% end %>
91 </div>
92
93 <% if @models.any? %>
94 <div class="card divide-y divide-surface-600">
95 <% @models.each do |repo, card| %>
96 <%= link_to repository_path(repo.user.username, repo.name),
97 class: "block px-4 py-3 hover:bg-surface-600 transition-colors" do %>
98 <div class="flex items-center justify-between gap-3">
99 <div class="min-w-0">
100 <div class="flex items-center gap-2">
101 <svg class="w-4 h-4 text-brand-500 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
102 <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/>
103 <path d="m3.27 6.96 8.73 5.05 8.73-5.05M12 22.08V12"/>
104 </svg>
105 <span class="font-medium text-gray-100 truncate"><%= repo.full_name %></span>
106 <% if repo.is_private %><span class="badge-gray">Private</span><% end %>
107 </div>
108 <div class="flex items-center gap-2 mt-1 text-xs text-gray-500 flex-wrap">
109 <% if (label = pipeline_label(card.pipeline_tag)) %>
110 <span class="text-brand-400"><%= label %></span>
111 <span>&middot;</span>
112 <% end %>
113 <% if card.library_name.present? %>
114 <span><%= card.library_name %></span>
115 <span>&middot;</span>
116 <% end %>
117 <span>Updated <%= time_ago_in_words(repo.updated_at) %> ago</span>
118 </div>
119 </div>
120 <div class="flex items-center gap-4 text-xs text-gray-500 shrink-0">
121 <span class="flex items-center gap-1" title="Downloads">
122 <svg class="w-3.5 h-3.5" viewBox="0 0 16 16" fill="currentColor"><path d="M7.47 10.78a.75.75 0 0 0 1.06 0l3.75-3.75a.75.75 0 0 0-1.06-1.06L8.75 8.44V1.75a.75.75 0 0 0-1.5 0v6.69L4.78 5.97a.75.75 0 0 0-1.06 1.06ZM3.75 13a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5Z"/></svg>
123 <%= humanize_count(repo.downloads_count) %>
124 </span>
125 <span class="flex items-center gap-1" title="Likes">
126 <svg class="w-3.5 h-3.5" viewBox="0 0 16 16" fill="currentColor"><path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"/></svg>
127 <%= humanize_count(repo.stars_count) %>
128 </span>
129 </div>
130 </div>
131 <% end %>
132 <% end %>
133 </div>
134 <% else %>
135 <div class="card px-6 py-16 text-center">
136 <p class="text-sm text-gray-400 mb-1">No models found.</p>
137 <p class="text-xs text-gray-500">Try clearing filters or
138 <%= link_to "publish the first one", new_repository_path(kind: "model"), class: "text-brand-500 hover:underline" %>.
139 </p>
140 </div>
141 <% end %>
142 </main>
143
144 </div>
145 </div>