mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
feat: show users top languages
feat: language icons
This commit is contained in:
parent
7a07c9d4fc
commit
1989a69926
@ -12,11 +12,12 @@ server:
|
||||
public_url: http://localhost:3000 # required for links (e.g. password reset) in e-mail
|
||||
|
||||
app:
|
||||
aggregation_time: '02:15' # time at which to run daily aggregation batch jobs
|
||||
report_time_weekly: 'fri,18:00' # time at which to fan out weekly reports (format: '<weekday)>,<daytime>')
|
||||
inactive_days: 7 # time of previous days within a user must have logged in to be considered active
|
||||
import_batch_size: 50 # maximum number of heartbeats to insert into the database within one transaction
|
||||
heartbeat_max_age: '4320h' # maximum acceptable age of a heartbeat (see https://pkg.go.dev/time#ParseDuration)
|
||||
aggregation_time: '02:15' # time at which to run daily aggregation batch jobs
|
||||
leaderboard_generation_time: '06:00;18:00' # time at which to run daily aggregation batch jobs
|
||||
report_time_weekly: 'fri,18:00' # time at which to fan out weekly reports (format: '<weekday)>,<daytime>')
|
||||
inactive_days: 7 # time of previous days within a user must have logged in to be considered active
|
||||
import_batch_size: 50 # maximum number of heartbeats to insert into the database within one transaction
|
||||
heartbeat_max_age: '4320h' # maximum acceptable age of a heartbeat (see https://pkg.go.dev/time#ParseDuration)
|
||||
custom_languages:
|
||||
vue: Vue
|
||||
jsx: JSX
|
||||
|
@ -1,6 +1,9 @@
|
||||
package view
|
||||
|
||||
import "github.com/muety/wakapi/models"
|
||||
import (
|
||||
"github.com/muety/wakapi/models"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LeaderboardViewModel struct {
|
||||
User *models.User
|
||||
@ -39,3 +42,30 @@ func (s *LeaderboardViewModel) ColorModifier(item *models.LeaderboardItem, princ
|
||||
}
|
||||
return "default"
|
||||
}
|
||||
|
||||
func (s *LeaderboardViewModel) LangIcon(lang string) string {
|
||||
// https://icon-sets.iconify.design/mdi/
|
||||
langs := map[string]string{
|
||||
"c": "c",
|
||||
"c++": "cpp",
|
||||
"cpp": "cpp",
|
||||
"go": "go",
|
||||
"haskell": "haskell",
|
||||
"html": "html5",
|
||||
"java": "java",
|
||||
"javascript": "javascript",
|
||||
"kotlin": "kotlin",
|
||||
"lua": "lua",
|
||||
"php": "php",
|
||||
"python": "python",
|
||||
"r": "r",
|
||||
"ruby": "ruby",
|
||||
"rust": "rust",
|
||||
"swift": "swift",
|
||||
"typescript": "typescript",
|
||||
}
|
||||
if match, ok := langs[strings.ToLower(lang)]; ok {
|
||||
return "mdi:language-" + match
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -56,6 +56,9 @@ func DefaultTemplateFuncs() template.FuncMap {
|
||||
"htmlSafe": func(html string) template.HTML {
|
||||
return template.HTML(html)
|
||||
},
|
||||
"urlSafe": func(s string) template.URL {
|
||||
return template.URL(s)
|
||||
},
|
||||
"avatarUrlTemplate": func() string {
|
||||
return config.Get().App.AvatarURLTemplate
|
||||
},
|
||||
|
@ -53,7 +53,23 @@ let icons = [
|
||||
'ion:rocket',
|
||||
'heroicons-solid:server',
|
||||
'eva:checkmark-circle-2-fill',
|
||||
'fluent:key-24-filled'
|
||||
'fluent:key-24-filled',
|
||||
'mdi:language-c',
|
||||
'mdi:language-cpp',
|
||||
'mdi:language-go',
|
||||
'mdi:language-haskell',
|
||||
'mdi:language-html5',
|
||||
'mdi:language-java',
|
||||
'mdi:language-javascript',
|
||||
'mdi:language-kotlin',
|
||||
'mdi:language-lua',
|
||||
'mdi:language-php',
|
||||
'mdi:language-python',
|
||||
'mdi:language-r',
|
||||
'mdi:language-ruby',
|
||||
'mdi:language-rust',
|
||||
'mdi:language-swift',
|
||||
'mdi:language-typescript',
|
||||
]
|
||||
|
||||
const output = path.normalize(path.join(__dirname, '../static/assets/js/icons.dist.js'))
|
||||
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -69,6 +69,7 @@
|
||||
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> 100 % free and open-source</li>
|
||||
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> Built by developers for developers</li>
|
||||
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> Fancy statistics and plots</li>
|
||||
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> Public leaderboards</li>
|
||||
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> Cool badges for readmes</li>
|
||||
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> Weekly e-mail reports</li>
|
||||
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> Intuitive REST API</li>
|
||||
|
@ -37,7 +37,12 @@
|
||||
<div class="flex space-x-2 mb-4">
|
||||
{{ range $i, $key := (strslice .TopKeys 0 20) }}
|
||||
<div class="inline-block">
|
||||
<a href="leaderboard?by={{ $.By }}&key={{ $key }}" class="{{ if eq $.Key (lower $key) }} btn-primary {{ else }} btn-default {{ end }} btn-small cursor-pointer">{{ $key }}</a>
|
||||
<a href="leaderboard?by={{ $.By }}&key={{ $key }}" class="{{ if eq $.Key (lower $key) }} btn-primary {{ else }} btn-default {{ end }} btn-small cursor-pointer">
|
||||
{{ if and (eq (lower $.By) "language") ($.LangIcon $key) }}
|
||||
<span class="align-middle leading-none"><span class="iconify inline text-white text-base" data-icon="{{ ($.LangIcon $key) | urlSafe }}"></span> </span>
|
||||
{{ end }}
|
||||
<span>{{ $key }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
@ -47,19 +52,24 @@
|
||||
<ol>
|
||||
{{ range $i, $item := .Items }}
|
||||
<li class="px-4 py-2 my-2 rounded-md border-2 leaderboard-{{ ($.ColorModifier $item $.User) }} flex justify-between">
|
||||
<div class="w-1/12"><strong># {{ $item.Rank }}</strong></div>
|
||||
<div class="flex w-4/12 justify-start items-center space-x-4 text-ellipsis overflow-hidden whitespace-nowrap align-middle">
|
||||
<div class="w-1/12 mr-1"><strong># {{ $item.Rank }}</strong></div>
|
||||
<div class="flex w-3/12 mx-1 justify-start items-center space-x-4 align-middle">
|
||||
{{ if avatarUrlTemplate }}
|
||||
<img src="{{ $item.User.AvatarURL avatarUrlTemplate }}" width="24px" class="rounded-full border-green-700" alt="User Profile Avatar"/>
|
||||
{{ else }}
|
||||
<span class="iconify inline cursor-pointer text-gray-500 rounded-full border-green-700" style="width: 24px; height: 24px" data-icon="ic:round-person"></span>
|
||||
{{ end }}
|
||||
<strong>@{{ $item.UserID }}</strong>
|
||||
<strong class="text-ellipsis truncate">@{{ $item.UserID }}</strong>
|
||||
</div>
|
||||
<span class="w-4/12 text-sm text-ellipsis overflow-hidden whitespace-nowrap leading-6 align-middle">
|
||||
{{ join (index $.UserLanguages $item.UserID) ", " }}
|
||||
<span class="w-5/12 mx-1 truncate leading-6 align-middle">
|
||||
{{ range $i, $lang := (index $.UserLanguages $item.UserID) }}
|
||||
{{ if $.LangIcon $lang }}
|
||||
<span class="align-middle leading-none"><span class="iconify inline text-white text-base" data-icon="{{ ($.LangIcon $lang) | urlSafe }}"></span></span>
|
||||
{{ end }}
|
||||
<span class="text-sm leading-6">{{ $lang }}{{ if lt $i (add (len (index $.UserLanguages $item.UserID)) -1) }}, {{ end }}</span>
|
||||
{{ end }}
|
||||
</span>
|
||||
<div class="w-3/12 text-right"><span>{{ $item.Total | duration }}</span></div>
|
||||
<div class="w-3/12 ml-1 text-right"><span>{{ $item.Total | duration }}</span></div>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ol>
|
||||
|
Loading…
Reference in New Issue
Block a user