73ee696fc3
This adds the marble avatar from [boring avatars](https://github.com/boringdesigners/boring-avatars) as an option for user avatars. Each user gets a different one (based on their id). Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/1060 Co-authored-by: konrad <k@knt.li> Co-committed-by: konrad <k@knt.li>
122 lines
4.1 KiB
Go
122 lines
4.1 KiB
Go
// Vikunja is a to-do list application to facilitate your life.
|
|
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public Licensee as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public Licensee for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public Licensee
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package marble
|
|
|
|
import (
|
|
"math"
|
|
"strconv"
|
|
|
|
"code.vikunja.io/api/pkg/user"
|
|
)
|
|
|
|
// Provider generates a random avatar based on https://github.com/boringdesigners/boring-avatars
|
|
type Provider struct {
|
|
}
|
|
|
|
const avatarSize = 80
|
|
|
|
var colors = []string{
|
|
"#A3A948",
|
|
"#EDB92E",
|
|
"#F85931",
|
|
"#CE1836",
|
|
"#009989",
|
|
}
|
|
|
|
type props struct {
|
|
Color string
|
|
TranslateX int
|
|
TranslateY int
|
|
Rotate int
|
|
Scale float64
|
|
}
|
|
|
|
func getUnit(number int, rang, index int) int {
|
|
value := number % rang
|
|
|
|
digit := math.Floor(math.Mod(float64(number)/math.Pow(10, float64(index)), 10))
|
|
|
|
if index > 0 && (math.Mod(digit, 2) == 0) {
|
|
return -value
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func getPropsForUser(u *user.User) []*props {
|
|
ps := []*props{}
|
|
for i := 0; i < 3; i++ {
|
|
f := float64(getUnit(int(u.ID)*(i+1), avatarSize/10, 0))
|
|
ps = append(ps, &props{
|
|
Color: colors[(int(u.ID)+i)%(len(colors)-1)],
|
|
TranslateX: getUnit(int(u.ID)*(i+1), avatarSize/10, 1),
|
|
TranslateY: getUnit(int(u.ID)*(i+1), avatarSize/10, 2),
|
|
Scale: 1.2 + f/10,
|
|
Rotate: getUnit(int(u.ID)*(i+1), 360, 1),
|
|
})
|
|
}
|
|
|
|
return ps
|
|
}
|
|
|
|
func (p *Provider) GetAvatar(u *user.User, size int64) (avatar []byte, mimeType string, err error) {
|
|
|
|
s := strconv.FormatInt(size, 10)
|
|
avatarSizeStr := strconv.Itoa(avatarSize)
|
|
avatarSizeHalf := strconv.Itoa(avatarSize / 2)
|
|
|
|
ps := getPropsForUser(u)
|
|
|
|
return []byte(`<svg
|
|
viewBox="0 0 ` + avatarSizeStr + ` ` + avatarSizeStr + `"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
width="` + s + `"
|
|
height="` + s + `"
|
|
>
|
|
<mask id="mask__marble" maskUnits="userSpaceOnUse" x="0" y="0" width="` + avatarSizeStr + `" height="` + avatarSizeStr + `">
|
|
<rect width="` + avatarSizeStr + `" height="` + avatarSizeStr + `" rx="` + strconv.Itoa(avatarSize*2) + `" fill="white" />
|
|
</mask>
|
|
<g mask="url(#mask__marble)">
|
|
<rect width="` + avatarSizeStr + `" height="` + avatarSizeStr + `" rx="2" fill="` + ps[0].Color + `" />
|
|
<path
|
|
filter="url(#prefix__filter0_f)"
|
|
d="M32.414 59.35L50.376 70.5H72.5v-71H33.728L26.5 13.381l19.057 27.08L32.414 59.35z"
|
|
fill="` + ps[1].Color + `"
|
|
transform="translate(` + strconv.Itoa(ps[1].TranslateX) + ` ` + strconv.Itoa(ps[1].TranslateY) + `) rotate(` + strconv.Itoa(ps[1].Rotate) + ` ` + avatarSizeHalf + ` ` + avatarSizeHalf + `) scale(` + strconv.FormatFloat(ps[2].Scale, 'f', 2, 64) + `)"
|
|
/>
|
|
<path
|
|
filter="url(#prefix__filter0_f)"
|
|
style="mix-blend-mode: overlay;"
|
|
d="M22.216 24L0 46.75l14.108 38.129L78 86l-3.081-59.276-22.378 4.005 12.972 20.186-23.35 27.395L22.215 24z"
|
|
fill="` + ps[2].Color + `"
|
|
transform="translate(` + strconv.Itoa(ps[2].TranslateX) + ` ` + strconv.Itoa(ps[2].TranslateY) + `) rotate(` + strconv.Itoa(ps[2].Rotate) + ` ` + avatarSizeHalf + ` ` + avatarSizeHalf + `) scale(` + strconv.FormatFloat(ps[2].Scale, 'f', 2, 64) + `)"
|
|
/>
|
|
</g>
|
|
<defs>
|
|
<filter
|
|
id="prefix__filter0_f"
|
|
filterUnits="userSpaceOnUse"
|
|
colorInterpolationFilters="sRGB"
|
|
>
|
|
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
|
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
|
<feGaussianBlur stdDeviation="7" result="effect1_foregroundBlur" />
|
|
</filter>
|
|
</defs>
|
|
</svg>`), "image/svg+xml", nil
|
|
}
|