|
1 | 1 | <script lang="ts"> |
2 | | - import { BarChart3, Eye, FileText, FolderKanban, TrendingUp, Users } from "lucide-svelte"; |
3 | | - import { |
4 | | - getAnalytics, |
5 | | - getViewTrend, |
6 | | - getViewsByDayAndType, |
7 | | - } from "$lib/data/private/analytics.remote"; |
| 2 | + import { Eye, FileText, FolderKanban, TrendingUp, Users } from "lucide-svelte"; |
| 3 | + import { getAnalytics, getViewTrend } from "$lib/data/private/analytics.remote"; |
8 | 4 | import ViewTrendChart from "$lib/components/analytics/ViewTrendChart.svelte"; |
9 | | - import ViewsByTypeChart from "$lib/components/analytics/ViewsByTypeChart.svelte"; |
10 | 5 |
|
11 | 6 | const analytics = await getAnalytics(); |
12 | 7 | const viewTrend = await getViewTrend(30); |
13 | | - const viewsByType = await getViewsByDayAndType(30); |
14 | 8 | </script> |
15 | 9 |
|
16 | 10 | <svelte:head> |
|
22 | 16 | <h1 class="text-3xl font-bold">Analytics</h1> |
23 | 17 | </div> |
24 | 18 |
|
25 | | - <!-- View Trends Section --> |
26 | | - <div class="card bg-base-100 shadow-md"> |
27 | | - <div class="card-body"> |
28 | | - <div class="mb-4 flex items-center gap-2"> |
29 | | - <TrendingUp class="h-5 w-5" /> |
30 | | - <h2 class="card-title">View Trends (Last 30 Days)</h2> |
31 | | - </div> |
32 | | - <ViewTrendChart data={viewTrend} title="Total Views Over Time" /> |
33 | | - </div> |
34 | | - </div> |
35 | | - |
36 | | - <div class="card bg-base-100 shadow-md"> |
37 | | - <div class="card-body"> |
38 | | - <div class="mb-4 flex items-center gap-2"> |
39 | | - <BarChart3 class="h-5 w-5" /> |
40 | | - <h2 class="card-title">Views by Content Type</h2> |
41 | | - </div> |
42 | | - <ViewsByTypeChart data={viewsByType} title="Views by Type Over Time" /> |
43 | | - </div> |
44 | | - </div> |
45 | | - |
46 | 19 | <!-- Total Views Summary --> |
47 | 20 | <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4"> |
48 | 21 | <div class="card bg-base-100 shadow-md"> |
|
94 | 67 | </div> |
95 | 68 | </div> |
96 | 69 |
|
97 | | - <!-- Top Articles --> |
98 | | - <div class="card bg-base-100 shadow-md"> |
99 | | - <div class="card-body"> |
100 | | - <div class="mb-4 flex items-center gap-2"> |
101 | | - <BarChart3 class="h-5 w-5" /> |
102 | | - <h2 class="card-title">Top Articles</h2> |
103 | | - </div> |
104 | | - <div class="overflow-x-auto"> |
105 | | - <table class="table"> |
106 | | - <thead> |
107 | | - <tr> |
108 | | - <th>Rank</th> |
109 | | - <th>Title</th> |
110 | | - <th>Author</th> |
111 | | - <th>Views</th> |
112 | | - <th>Actions</th> |
113 | | - </tr> |
114 | | - </thead> |
115 | | - <tbody> |
116 | | - {#each analytics.topArticles as article, index (article.id)} |
117 | | - <tr class="hover"> |
118 | | - <td class="font-semibold">#{index + 1}</td> |
119 | | - <td> |
120 | | - <div class="max-w-md truncate">{article.title}</div> |
121 | | - </td> |
122 | | - <td> |
123 | | - {#if article.author} |
124 | | - <div class="flex items-center gap-2"> |
125 | | - {#if article.author.imageUrl} |
126 | | - <img |
127 | | - src={article.author.imageUrl} |
128 | | - alt={article.author.name} |
129 | | - class="aspect-square h-6 w-6 rounded-full object-cover" |
130 | | - /> |
131 | | - {/if} |
132 | | - <span>{article.author.name}</span> |
133 | | - </div> |
134 | | - {:else} |
135 | | - <span class="text-base-content/40">No author</span> |
136 | | - {/if} |
137 | | - </td> |
138 | | - <td> |
139 | | - <div class="flex items-center gap-1"> |
140 | | - <Eye class="h-4 w-4" /> |
141 | | - <span>{article.viewCount.toLocaleString()}</span> |
142 | | - </div> |
143 | | - </td> |
144 | | - <td> |
145 | | - <a href="/articles/{article.slug}" class="btn btn-ghost btn-sm" target="_blank"> |
146 | | - View |
147 | | - </a> |
148 | | - </td> |
149 | | - </tr> |
150 | | - {:else} |
151 | | - <tr> |
152 | | - <td colspan="5" class="text-center text-base-content/60">No articles yet</td> |
153 | | - </tr> |
154 | | - {/each} |
155 | | - </tbody> |
156 | | - </table> |
157 | | - </div> |
158 | | - </div> |
159 | | - </div> |
160 | | - |
161 | | - <!-- Top Projects --> |
162 | | - <div class="card bg-base-100 shadow-md"> |
163 | | - <div class="card-body"> |
164 | | - <div class="mb-4 flex items-center gap-2"> |
165 | | - <BarChart3 class="h-5 w-5" /> |
166 | | - <h2 class="card-title">Top Projects</h2> |
167 | | - </div> |
168 | | - <div class="overflow-x-auto"> |
169 | | - <table class="table"> |
170 | | - <thead> |
171 | | - <tr> |
172 | | - <th>Rank</th> |
173 | | - <th>Name</th> |
174 | | - <th>Category</th> |
175 | | - <th>Views</th> |
176 | | - <th>Actions</th> |
177 | | - </tr> |
178 | | - </thead> |
179 | | - <tbody> |
180 | | - {#each analytics.topProjects as project, index (project.id)} |
181 | | - <tr class="hover"> |
182 | | - <td class="font-semibold">#{index + 1}</td> |
183 | | - <td> |
184 | | - <div class="max-w-md truncate">{project.name}</div> |
185 | | - </td> |
186 | | - <td> |
187 | | - <span class="badge badge-outline">{project.category}</span> |
188 | | - </td> |
189 | | - <td> |
190 | | - <div class="flex items-center gap-1"> |
191 | | - <Eye class="h-4 w-4" /> |
192 | | - <span>{project.viewCount.toLocaleString()}</span> |
193 | | - </div> |
194 | | - </td> |
195 | | - <td> |
196 | | - <a href="/projects/{project.slug}" class="btn btn-ghost btn-sm" target="_blank"> |
197 | | - View |
198 | | - </a> |
199 | | - </td> |
200 | | - </tr> |
201 | | - {:else} |
202 | | - <tr> |
203 | | - <td colspan="5" class="text-center text-base-content/60">No projects yet</td> |
204 | | - </tr> |
205 | | - {/each} |
206 | | - </tbody> |
207 | | - </table> |
208 | | - </div> |
209 | | - </div> |
210 | | - </div> |
211 | | - |
212 | | - <!-- Top Members --> |
| 70 | + <!-- View Trends Section --> |
213 | 71 | <div class="card bg-base-100 shadow-md"> |
214 | 72 | <div class="card-body"> |
215 | 73 | <div class="mb-4 flex items-center gap-2"> |
216 | | - <BarChart3 class="h-5 w-5" /> |
217 | | - <h2 class="card-title">Top Member Pages</h2> |
218 | | - </div> |
219 | | - <div class="overflow-x-auto"> |
220 | | - <table class="table"> |
221 | | - <thead> |
222 | | - <tr> |
223 | | - <th>Rank</th> |
224 | | - <th>Name</th> |
225 | | - <th>Views</th> |
226 | | - <th>Actions</th> |
227 | | - </tr> |
228 | | - </thead> |
229 | | - <tbody> |
230 | | - {#each analytics.topMembers as member, index (member.id)} |
231 | | - <tr class="hover"> |
232 | | - <td class="font-semibold">#{index + 1}</td> |
233 | | - <td> |
234 | | - <div class="flex items-center gap-2"> |
235 | | - {#if member.imageUrl} |
236 | | - <img |
237 | | - src={member.imageUrl} |
238 | | - alt={member.name} |
239 | | - class="aspect-square h-8 w-8 rounded-full object-cover" |
240 | | - /> |
241 | | - {/if} |
242 | | - <span>{member.name}</span> |
243 | | - </div> |
244 | | - </td> |
245 | | - <td> |
246 | | - <div class="flex items-center gap-1"> |
247 | | - <Eye class="h-4 w-4" /> |
248 | | - <span>{member.viewCount.toLocaleString()}</span> |
249 | | - </div> |
250 | | - </td> |
251 | | - <td> |
252 | | - <a href="/members/{member.slug}" class="btn btn-ghost btn-sm" target="_blank"> |
253 | | - View |
254 | | - </a> |
255 | | - </td> |
256 | | - </tr> |
257 | | - {:else} |
258 | | - <tr> |
259 | | - <td colspan="4" class="text-center text-base-content/60">No members yet</td> |
260 | | - </tr> |
261 | | - {/each} |
262 | | - </tbody> |
263 | | - </table> |
| 74 | + <TrendingUp class="h-5 w-5" /> |
| 75 | + <h2 class="card-title">訪問数の推移(過去30日間)</h2> |
264 | 76 | </div> |
| 77 | + <ViewTrendChart data={viewTrend} title="全体の訪問数" /> |
265 | 78 | </div> |
266 | 79 | </div> |
267 | 80 | </div> |
0 commit comments