feat: show users top languages

feat: language icons
This commit is contained in:
Ferdinand Mütsch 2022-10-05 23:36:57 +02:00
parent 7a07c9d4fc
commit 1989a69926
10 changed files with 77 additions and 15 deletions

View File

@ -12,11 +12,12 @@ server:
public_url: http://localhost:3000 # required for links (e.g. password reset) in e-mail public_url: http://localhost:3000 # required for links (e.g. password reset) in e-mail
app: app:
aggregation_time: '02:15' # time at which to run daily aggregation batch jobs 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>') leaderboard_generation_time: '06:00;18:00' # time at which to run daily aggregation batch jobs
inactive_days: 7 # time of previous days within a user must have logged in to be considered active report_time_weekly: 'fri,18:00' # time at which to fan out weekly reports (format: '<weekday)>,<daytime>')
import_batch_size: 50 # maximum number of heartbeats to insert into the database within one transaction inactive_days: 7 # time of previous days within a user must have logged in to be considered active
heartbeat_max_age: '4320h' # maximum acceptable age of a heartbeat (see https://pkg.go.dev/time#ParseDuration) 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: custom_languages:
vue: Vue vue: Vue
jsx: JSX jsx: JSX

View File

@ -1,6 +1,9 @@
package view package view
import "github.com/muety/wakapi/models" import (
"github.com/muety/wakapi/models"
"strings"
)
type LeaderboardViewModel struct { type LeaderboardViewModel struct {
User *models.User User *models.User
@ -39,3 +42,30 @@ func (s *LeaderboardViewModel) ColorModifier(item *models.LeaderboardItem, princ
} }
return "default" 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 ""
}

View File

@ -56,6 +56,9 @@ func DefaultTemplateFuncs() template.FuncMap {
"htmlSafe": func(html string) template.HTML { "htmlSafe": func(html string) template.HTML {
return template.HTML(html) return template.HTML(html)
}, },
"urlSafe": func(s string) template.URL {
return template.URL(s)
},
"avatarUrlTemplate": func() string { "avatarUrlTemplate": func() string {
return config.Get().App.AvatarURLTemplate return config.Get().App.AvatarURLTemplate
}, },

View File

@ -53,7 +53,23 @@ let icons = [
'ion:rocket', 'ion:rocket',
'heroicons-solid:server', 'heroicons-solid:server',
'eva:checkmark-circle-2-fill', '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')) 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.

View File

@ -69,6 +69,7 @@
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; 100 % free and open-source</li> <li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; 100 % free and open-source</li>
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Built by developers for developers</li> <li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Built by developers for developers</li>
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Fancy statistics and plots</li> <li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Fancy statistics and plots</li>
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Public leaderboards</li>
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Cool badges for readmes</li> <li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Cool badges for readmes</li>
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Weekly e-mail reports</li> <li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Weekly e-mail reports</li>
<li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Intuitive REST API</li> <li><span class="iconify inline text-green-700" data-icon="eva:checkmark-circle-2-fill"></span> &nbsp; Intuitive REST API</li>

View File

@ -37,7 +37,12 @@
<div class="flex space-x-2 mb-4"> <div class="flex space-x-2 mb-4">
{{ range $i, $key := (strslice .TopKeys 0 20) }} {{ range $i, $key := (strslice .TopKeys 0 20) }}
<div class="inline-block"> <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>&nbsp;</span>
{{ end }}
<span>{{ $key }}</span>
</a>
</div> </div>
{{ end }} {{ end }}
</div> </div>
@ -47,19 +52,24 @@
<ol> <ol>
{{ range $i, $item := .Items }} {{ range $i, $item := .Items }}
<li class="px-4 py-2 my-2 rounded-md border-2 leaderboard-{{ ($.ColorModifier $item $.User) }} flex justify-between"> <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="w-1/12 mr-1"><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="flex w-3/12 mx-1 justify-start items-center space-x-4 align-middle">
{{ if avatarUrlTemplate }} {{ if avatarUrlTemplate }}
<img src="{{ $item.User.AvatarURL avatarUrlTemplate }}" width="24px" class="rounded-full border-green-700" alt="User Profile Avatar"/> <img src="{{ $item.User.AvatarURL avatarUrlTemplate }}" width="24px" class="rounded-full border-green-700" alt="User Profile Avatar"/>
{{ else }} {{ 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> <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 }} {{ end }}
<strong>@{{ $item.UserID }}</strong> <strong class="text-ellipsis truncate">@{{ $item.UserID }}</strong>
</div> </div>
<span class="w-4/12 text-sm text-ellipsis overflow-hidden whitespace-nowrap leading-6 align-middle"> <span class="w-5/12 mx-1 truncate leading-6 align-middle">
{{ join (index $.UserLanguages $item.UserID) ", " }} {{ 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) }},&nbsp;{{ end }}</span>
{{ end }}
</span> </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> </li>
{{ end }} {{ end }}
</ol> </ol>