Compare commits
No commits in common. "f72c7a357b50e3b83b0ad72fba5762cf1e59ba68" and "8c8cbfd7ddcf8d050e16f0da3f878875d341530f" have entirely different histories.
f72c7a357b
...
8c8cbfd7dd
31 changed files with 7 additions and 585 deletions
|
@ -7,7 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/auth/authmiddleware"
|
"git.sapphic.engineer/roleypoly/v4/authmiddleware"
|
||||||
"git.sapphic.engineer/roleypoly/v4/discord"
|
"git.sapphic.engineer/roleypoly/v4/discord"
|
||||||
"git.sapphic.engineer/roleypoly/v4/interactions"
|
"git.sapphic.engineer/roleypoly/v4/interactions"
|
||||||
"git.sapphic.engineer/roleypoly/v4/roleypoly"
|
"git.sapphic.engineer/roleypoly/v4/roleypoly"
|
||||||
|
|
8
justfile
8
justfile
|
@ -12,14 +12,11 @@ run-container:
|
||||||
docker load -i result
|
docker load -i result
|
||||||
docker run -it --rm -p 8169:8169 localhost/roleypoly/roleypoly
|
docker run -it --rm -p 8169:8169 localhost/roleypoly/roleypoly
|
||||||
|
|
||||||
precommit: fmt prettier tidy update-vendor-hash test
|
precommit: fmt tidy update-vendor-hash test
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
|
|
||||||
prettier:
|
|
||||||
prettier -w -c **/*.{css,html,json,md}
|
|
||||||
|
|
||||||
tidy:
|
tidy:
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
|
||||||
|
@ -31,6 +28,3 @@ test:
|
||||||
|
|
||||||
clean-repo:
|
clean-repo:
|
||||||
rm -rf tmp result
|
rm -rf tmp result
|
||||||
|
|
||||||
open-chromium path="/testing/t/picker":
|
|
||||||
nix-shell -p chromium --command "chromium http://localhost:8170{{path}}"
|
|
|
@ -1,59 +0,0 @@
|
||||||
package presentation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InputType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
InputCheckbox InputType = "checkbox"
|
|
||||||
InputRadio InputType = "radio"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PresentableRole struct {
|
|
||||||
ID string
|
|
||||||
CategoryID string
|
|
||||||
Name string
|
|
||||||
Selected bool
|
|
||||||
InputType InputType
|
|
||||||
Colors PresentableRoleColors
|
|
||||||
}
|
|
||||||
|
|
||||||
func Role(category *types.Category, role *types.Role, selected bool) PresentableRole {
|
|
||||||
inputType := InputCheckbox
|
|
||||||
if category.Type == types.CategorySingle {
|
|
||||||
inputType = InputRadio
|
|
||||||
}
|
|
||||||
|
|
||||||
colors := GetColors(role.Color)
|
|
||||||
|
|
||||||
return PresentableRole{
|
|
||||||
ID: role.ID,
|
|
||||||
CategoryID: category.ID,
|
|
||||||
Name: role.Name,
|
|
||||||
Selected: selected,
|
|
||||||
InputType: inputType,
|
|
||||||
Colors: colors,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PresentableRoleColors struct {
|
|
||||||
Main string
|
|
||||||
Alt string
|
|
||||||
IsDark bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetColors(roleColor uint32) PresentableRoleColors {
|
|
||||||
// TODO: no color
|
|
||||||
|
|
||||||
r, g, b := utils.IntToRgb(roleColor)
|
|
||||||
altR, altG, altB := utils.AltColor(r, g, b)
|
|
||||||
|
|
||||||
return PresentableRoleColors{
|
|
||||||
Main: utils.RgbToString(r, g, b),
|
|
||||||
Alt: utils.RgbToString(altR, altG, altB),
|
|
||||||
IsDark: utils.IsDarkColor(r, g, b),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package presentation_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/presentation"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types/fixtures"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRole(t *testing.T) {
|
|
||||||
r := presentation.Role(&fixtures.CategoryMulti, &fixtures.RoleWithDarkColor, true)
|
|
||||||
assert.Equal(t, fixtures.RoleWithDarkColor.ID, r.ID)
|
|
||||||
assert.Equal(t, fixtures.RoleWithDarkColor.Name, r.Name)
|
|
||||||
assert.Equal(t, presentation.InputCheckbox, r.InputType)
|
|
||||||
assert.Equal(t, "#a20000", r.Colors.Main)
|
|
||||||
assert.True(t, r.Colors.IsDark)
|
|
||||||
assert.True(t, r.Selected)
|
|
||||||
|
|
||||||
r = presentation.Role(&fixtures.CategorySingle, &fixtures.RoleWithDarkColor, false)
|
|
||||||
assert.Equal(t, presentation.InputRadio, r.InputType)
|
|
||||||
assert.False(t, r.Selected)
|
|
||||||
|
|
||||||
r = presentation.Role(&fixtures.CategorySingle, &fixtures.RoleWithLightColor, true)
|
|
||||||
assert.False(t, r.Colors.IsDark)
|
|
||||||
assert.True(t, r.Selected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetColors(t *testing.T) {
|
|
||||||
c := presentation.GetColors(0xa20000)
|
|
||||||
assert.Equal(t, "#a20000", c.Main)
|
|
||||||
assert.True(t, c.IsDark)
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"github.com/gofiber/fiber/v3/middleware/static"
|
"github.com/gofiber/fiber/v3/middleware/static"
|
||||||
"github.com/gofiber/template/html/v2"
|
"github.com/gofiber/template/html/v2"
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/auth/authmiddleware"
|
"git.sapphic.engineer/roleypoly/v4/authmiddleware"
|
||||||
"git.sapphic.engineer/roleypoly/v4/discord"
|
"git.sapphic.engineer/roleypoly/v4/discord"
|
||||||
"git.sapphic.engineer/roleypoly/v4/interactions"
|
"git.sapphic.engineer/roleypoly/v4/interactions"
|
||||||
staticfs "git.sapphic.engineer/roleypoly/v4/static"
|
staticfs "git.sapphic.engineer/roleypoly/v4/static"
|
||||||
|
|
|
@ -4,7 +4,5 @@
|
||||||
just
|
just
|
||||||
nil
|
nil
|
||||||
air
|
air
|
||||||
nodePackages.prettier
|
|
||||||
pre-commit
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect fill="#000" width="2" height="5" x="3" y="4" style="transform: rotate(-45deg); transform-origin: center;" />
|
|
||||||
<rect fill="#000" width="2" height="7" x="7" y="4.5" style="transform: rotate(45deg); transform-origin: center;" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 325 B |
103
static/main.css
103
static/main.css
|
@ -1,106 +1,3 @@
|
||||||
:root {
|
|
||||||
--taupe100: #332d2d;
|
|
||||||
--taupe200: #453e3d;
|
|
||||||
--taupe300: #5d5352;
|
|
||||||
--taupe400: #756867;
|
|
||||||
--taupe500: #ab9b9a;
|
|
||||||
--taupe600: #ebd6d4;
|
|
||||||
|
|
||||||
--discord100: #23272a;
|
|
||||||
--discord200: #2c2f33;
|
|
||||||
--discord400: #7289da;
|
|
||||||
--discord500: #99aab5;
|
|
||||||
|
|
||||||
--green400: #46b646;
|
|
||||||
--green200: #1d8227;
|
|
||||||
|
|
||||||
--red400: #e95353;
|
|
||||||
--red200: #f14343;
|
|
||||||
|
|
||||||
--gold400: #efcf24;
|
|
||||||
|
|
||||||
--grey100: #1c1010;
|
|
||||||
--grey500: #dbd9d9;
|
|
||||||
--grey600: #f2efef;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: "Atkinson Hyperlegible", sans-serif;
|
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||||
background-color: var(--taupe200);
|
|
||||||
color: var(--taupe600);
|
|
||||||
}
|
|
||||||
|
|
||||||
.role {
|
|
||||||
/* TODO: dont do this, don't remember why?? (^aki) */
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
border: 2px solid var(--role-color);
|
|
||||||
border-radius: 3px;
|
|
||||||
user-select: none;
|
|
||||||
padding: 0.217rem; /* this is silly number pls ignore :3 (^noe) */
|
|
||||||
gap: 0.215rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.35s ease-in-out;
|
|
||||||
|
|
||||||
input {
|
|
||||||
cursor: pointer;
|
|
||||||
appearance: none;
|
|
||||||
position: relative;
|
|
||||||
width: 1.216rem;
|
|
||||||
height: 1.216rem;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 2px solid var(--role-color);
|
|
||||||
transition: all 0.25s ease-in-out;
|
|
||||||
border-radius: 1.216rem;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--role-color);
|
|
||||||
&::before {
|
|
||||||
opacity: 1;
|
|
||||||
background-color: var(--contrast-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
transition: all 0.35s ease-in-out;
|
|
||||||
content: "";
|
|
||||||
mask-image: url(/static/images/check.svg);
|
|
||||||
mask-size: cover;
|
|
||||||
mask-position: center center;
|
|
||||||
background-color: var(--role-color);
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 1.216rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:has(input:checked) {
|
|
||||||
background-color: var(--role-color);
|
|
||||||
|
|
||||||
input {
|
|
||||||
border-color: var(--contrast-color);
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
opacity: 1;
|
|
||||||
background-color: var(--contrast-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
color: var(--contrast-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
<nav>
|
|
||||||
<div class="logo">Roleypoly</div>
|
|
||||||
<div class="username">41666</div>
|
|
||||||
</nav>
|
|
|
@ -1,10 +0,0 @@
|
||||||
{{ $for := printf "category-%s_role-%s" .CategoryID .ID }}
|
|
||||||
<div
|
|
||||||
class="role"
|
|
||||||
style="--role-color: {{.Colors.Main}}; --contrast-color: {{.Colors.Alt}};"
|
|
||||||
data-testid="role-{{.ID}}"
|
|
||||||
>
|
|
||||||
<input type="{{.InputType}}" id="{{$for}}" {{if eq .InputType
|
|
||||||
"radio"}}name="category_group_{{.CategoryID}}"{{end}} />
|
|
||||||
<label for="{{$for}}">{{.Name}}</label>
|
|
||||||
</div>
|
|
|
@ -1,58 +0,0 @@
|
||||||
package components_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/presentation"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/templates"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types/fixtures"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Templates = template.Must(template.ParseFS(templates.FS, "components/*.html"))
|
|
||||||
)
|
|
||||||
|
|
||||||
func renderRole(t *testing.T, c *types.Category, r *types.Role, s bool) string {
|
|
||||||
data := presentation.Role(c, r, s)
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
err := Templates.ExecuteTemplate(&buf, "role.html", data)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("template failed to render", err)
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRole(t *testing.T) {
|
|
||||||
c := &fixtures.CategoryMulti
|
|
||||||
r := &fixtures.RoleWithDarkColor
|
|
||||||
html := renderRole(t, c, r, false)
|
|
||||||
assert.Contains(t, html, "--role-color: #a20000;", "role color is set")
|
|
||||||
assert.Contains(t, html, `type="checkbox"`, "multi has input type=checkbox")
|
|
||||||
assert.Contains(t, html, fmt.Sprintf("--contrast-color: %s;", utils.RgbToString(utils.AltColor(162, 0, 0))), "contrast color is set")
|
|
||||||
assert.Contains(t, html, fmt.Sprintf(`id="%s"`, roleInputID(c, r)), "input has ID attr")
|
|
||||||
assert.Contains(t, html, fmt.Sprintf(`for="%s"`, roleInputID(c, r)), "label has for attr")
|
|
||||||
assert.NotContains(t, html, fmt.Sprintf(`name="%s"`, roleInputName(c)), "multi has no name attr")
|
|
||||||
// TODO: selected?
|
|
||||||
|
|
||||||
c = &fixtures.CategorySingle
|
|
||||||
r = &fixtures.RoleWithLightColor
|
|
||||||
html = renderRole(t, c, r, true)
|
|
||||||
assert.Contains(t, html, `type="radio"`, "single has input type=radio")
|
|
||||||
assert.Contains(t, html, fmt.Sprintf("--contrast-color: %s;", utils.RgbToString(utils.AltColor(0xff, 0xaa, 0x88))), "contrast color")
|
|
||||||
assert.Contains(t, html, fmt.Sprintf(`name="%s"`, roleInputName(c)), "single has name attr")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: these can probably be string utils that are injected as functions into template
|
|
||||||
func roleInputID(c *types.Category, r *types.Role) string {
|
|
||||||
return fmt.Sprintf("category-%s_role-%s", c.ID, r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func roleInputName(c *types.Category) string {
|
|
||||||
return fmt.Sprintf("category_group_%s", c.ID)
|
|
||||||
}
|
|
|
@ -11,6 +11,6 @@
|
||||||
<link rel="stylesheet" href="/static/main.css" />
|
<link rel="stylesheet" href="/static/main.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{ template "components/nav" . }} {{embed}}
|
{{embed}}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
margin: 3rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="cat-multi">
|
|
||||||
{{ template "components/role" .TestRole }} {{ template "components/role"
|
|
||||||
.TestRole2 }}
|
|
||||||
</div>
|
|
||||||
<div class="cat-single">
|
|
||||||
{{ template "components/role" .TestRole3 }} {{ template "components/role"
|
|
||||||
.TestRole4 }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -5,11 +5,9 @@ import (
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/auth/authmiddleware"
|
"git.sapphic.engineer/roleypoly/v4/authmiddleware"
|
||||||
"git.sapphic.engineer/roleypoly/v4/discord"
|
"git.sapphic.engineer/roleypoly/v4/discord"
|
||||||
"git.sapphic.engineer/roleypoly/v4/presentation"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types"
|
"git.sapphic.engineer/roleypoly/v4/types"
|
||||||
"git.sapphic.engineer/roleypoly/v4/types/fixtures"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestingController struct {
|
type TestingController struct {
|
||||||
|
@ -36,14 +34,7 @@ func (t *TestingController) Picker(c fiber.Ctx) error {
|
||||||
|
|
||||||
func (t *TestingController) TestTemplate(c fiber.Ctx) error {
|
func (t *TestingController) TestTemplate(c fiber.Ctx) error {
|
||||||
which := c.Params("which")
|
which := c.Params("which")
|
||||||
cat1 := fixtures.Category(fixtures.CategoryMulti)
|
return c.Render("tests/"+which, fiber.Map{})
|
||||||
cat2 := fixtures.Category(fixtures.CategorySingle)
|
|
||||||
return c.Render("tests/"+which, fiber.Map{
|
|
||||||
"TestRole": presentation.Role(cat1, &fixtures.RoleWithDarkColor, false),
|
|
||||||
"TestRole2": presentation.Role(cat1, &fixtures.RoleWithLightColor, true),
|
|
||||||
"TestRole3": presentation.Role(cat2, &fixtures.RoleWithDarkColor, false),
|
|
||||||
"TestRole4": presentation.Role(cat2, &fixtures.RoleWithLightColor, true),
|
|
||||||
}, "layouts/main")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestingController) GetMember(c fiber.Ctx) error {
|
func (t *TestingController) GetMember(c fiber.Ctx) error {
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
type CategoryType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
CategoryMultiple CategoryType = "multiple"
|
|
||||||
CategorySingle CategoryType = "single"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Category struct {
|
|
||||||
ID string
|
|
||||||
Name string
|
|
||||||
Type CategoryType
|
|
||||||
Roles []string // of role IDs
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package fixtures
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
CategoryMulti = types.Category{
|
|
||||||
ID: "multi",
|
|
||||||
Name: "Roles",
|
|
||||||
Type: types.CategoryMultiple,
|
|
||||||
Roles: []string{RoleWithDarkColor.ID, RoleWithLightColor.ID, RoleWithoutColor.ID},
|
|
||||||
}
|
|
||||||
|
|
||||||
CategorySingle = types.Category{
|
|
||||||
ID: "single",
|
|
||||||
Name: "Roles",
|
|
||||||
Type: types.CategorySingle,
|
|
||||||
Roles: []string{RoleWithDarkColor.ID, RoleWithLightColor.ID, RoleWithoutColor.ID},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func Category(base types.Category) *types.Category {
|
|
||||||
base.ID = fmt.Sprintf("%s-%d", base.ID, rand.Uint32())
|
|
||||||
return &base
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package fixtures
|
|
||||||
|
|
||||||
import "git.sapphic.engineer/roleypoly/v4/types"
|
|
||||||
|
|
||||||
var (
|
|
||||||
RoleWithDarkColor = types.Role{
|
|
||||||
ID: "dark-color",
|
|
||||||
Name: "role with dark color",
|
|
||||||
Color: 0xa20000,
|
|
||||||
Permissions: 0,
|
|
||||||
Position: 10,
|
|
||||||
}
|
|
||||||
RoleWithLightColor = types.Role{
|
|
||||||
ID: "light-color",
|
|
||||||
Name: "role with light color",
|
|
||||||
Color: 0xffaa88,
|
|
||||||
Permissions: 0,
|
|
||||||
Position: 10,
|
|
||||||
}
|
|
||||||
RoleWithoutColor = types.Role{
|
|
||||||
ID: "without-color",
|
|
||||||
Name: "role",
|
|
||||||
Color: 0x000000,
|
|
||||||
Permissions: 0,
|
|
||||||
Position: 11,
|
|
||||||
}
|
|
||||||
//TODO: role with admin (bad)
|
|
||||||
//TODO: role with manage roles (bad)
|
|
||||||
//TODO: role above roleypoly (bad)
|
|
||||||
//TODO: role with managed (bad)
|
|
||||||
//TODO: role that is roleypoly (hi)
|
|
||||||
)
|
|
|
@ -1,11 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
type Role struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Color uint32 `json:"color"`
|
|
||||||
Icon string `json:"icon"` // unused, future?
|
|
||||||
UnicodeEmoji string `json:"unicode_emoji"` // unused, future?
|
|
||||||
Permissions uint64 `json:"permissions,string"`
|
|
||||||
Position uint8 `json:"position"`
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Pred float64 = 0.299
|
|
||||||
Pgreen float64 = 0.587
|
|
||||||
Pblue float64 = 0.114
|
|
||||||
)
|
|
||||||
|
|
||||||
func IsDarkColor(r, g, b uint8) bool {
|
|
||||||
lum := Luminance(r, g, b)
|
|
||||||
|
|
||||||
return lum <= 130
|
|
||||||
}
|
|
||||||
|
|
||||||
func IntToRgb(color uint32) (uint8, uint8, uint8) {
|
|
||||||
b := color % 256
|
|
||||||
g := color / 256 % 256
|
|
||||||
r := color / (256 * 256) % 256
|
|
||||||
|
|
||||||
return uint8(r), uint8(g), uint8(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RgbToString(r, g, b uint8) string {
|
|
||||||
return fmt.Sprintf("#%02x%02x%02x", r, g, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func AltColor(r, g, b uint8) (uint8, uint8, uint8) {
|
|
||||||
brightnessAmount := -0.6
|
|
||||||
if IsDarkColor(r, g, b) {
|
|
||||||
brightnessAmount = 0.85
|
|
||||||
}
|
|
||||||
return Brighten(r, g, b, brightnessAmount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Brighten(r, g, b uint8, amount float64) (uint8, uint8, uint8) {
|
|
||||||
return multiply(r, amount), multiply(g, amount), multiply(b, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func multiply(i uint8, amount float64) uint8 {
|
|
||||||
iF := float64(i)
|
|
||||||
return uint8(
|
|
||||||
math.Max(
|
|
||||||
0,
|
|
||||||
math.Min(
|
|
||||||
255, iF+255*amount,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Luminance(r, g, b uint8) float64 {
|
|
||||||
rC := Pred * math.Pow(float64(r), 2)
|
|
||||||
gC := Pgreen * math.Pow(float64(g), 2)
|
|
||||||
bC := Pblue * math.Pow(float64(b), 2)
|
|
||||||
|
|
||||||
return math.Sqrt(rC + gC + bC)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WCAGRatio(l1, l2 float64) float64 {
|
|
||||||
if l1 < l2 {
|
|
||||||
return (l1 + 0.05) / (l2 + 0.05)
|
|
||||||
} else {
|
|
||||||
return (l2 + 0.05) / (l1 + 0.05)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package utils_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
WCAGAAA float64 = 0.14285714285714285
|
|
||||||
WCAGAA float64 = 0.25
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIntToRgb(t *testing.T) {
|
|
||||||
r, g, b := utils.IntToRgb(0x123456)
|
|
||||||
assert.Equal(t, uint8(0x12), r, "red")
|
|
||||||
assert.Equal(t, uint8(0x34), g, "green")
|
|
||||||
assert.Equal(t, uint8(0x56), b, "blue")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsDarkColor(t *testing.T) {
|
|
||||||
isDark := utils.IsDarkColor(0, 0, 0)
|
|
||||||
assert.True(t, isDark)
|
|
||||||
|
|
||||||
isLight := utils.IsDarkColor(255, 255, 255)
|
|
||||||
assert.False(t, isLight)
|
|
||||||
|
|
||||||
isQuestionable := utils.IsDarkColor(0x88, 0x88, 0x88)
|
|
||||||
assert.False(t, isQuestionable)
|
|
||||||
|
|
||||||
isReallyQuestionable := utils.IsDarkColor(0x00, 0x88, 0x00)
|
|
||||||
assert.True(t, isReallyQuestionable)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBrighten(t *testing.T) {
|
|
||||||
r, g, b := utils.Brighten(0, 0, 0, 0.1)
|
|
||||||
assert.Equal(t, uint8(0x19), r)
|
|
||||||
assert.Equal(t, uint8(0x19), g)
|
|
||||||
assert.Equal(t, uint8(0x19), b)
|
|
||||||
// assert.LessOrEqual(t, WCAGAA, utils.WCAGRatio(
|
|
||||||
// utils.Luminance(0, 0, 0),
|
|
||||||
// utils.Luminance(r, g, b),
|
|
||||||
// ))
|
|
||||||
|
|
||||||
r, g, b = utils.Brighten(0x88, 0x88, 0x88, -0.1)
|
|
||||||
assert.Equal(t, uint8(0x88-0x19-1), r)
|
|
||||||
assert.Equal(t, uint8(0x88-0x19-1), g)
|
|
||||||
assert.Equal(t, uint8(0x88-0x19-1), b)
|
|
||||||
// assert.LessOrEqual(t, WCAGAA, utils.WCAGRatio(
|
|
||||||
// utils.Luminance(0x88, 0x88, 0x88),
|
|
||||||
// utils.Luminance(r, g, b),
|
|
||||||
// ))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRgbToString(t *testing.T) {
|
|
||||||
assert.Equal(t, "#acab69", utils.RgbToString(0xac, 0xab, 0x69))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAltColor(t *testing.T) {
|
|
||||||
r, g, b := utils.AltColor(0xa2, 0xc2, 0x42)
|
|
||||||
assert.Equal(t, uint8(0x09), r, "red")
|
|
||||||
assert.Equal(t, uint8(0x29), g, "green")
|
|
||||||
assert.Equal(t, uint8(0x00), b, "blue")
|
|
||||||
|
|
||||||
r, g, b = utils.AltColor(0xa2, 0x15, 0x18)
|
|
||||||
assert.Equal(t, uint8(0xff), r, "red")
|
|
||||||
assert.Equal(t, uint8(0xed), g, "green")
|
|
||||||
assert.Equal(t, uint8(0xf0), b, "blue")
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package utils_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRandomEmoji(t *testing.T) {
|
|
||||||
for i := len(utils.AllEmojis) * 1000; i >= 0; i-- {
|
|
||||||
e := utils.GetRandomEmoji()
|
|
||||||
assert.Containsf(t, e.Name, "roleypolynext", "not valid on iteration %d", i)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RoleInputID(c *types.Category, r *types.Role) string {
|
|
||||||
return fmt.Sprintf("category-%s_role-%s", c.ID, r.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func RoleInputName(c *types.Category) string {
|
|
||||||
return fmt.Sprintf("category_group_%s", c.ID)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package utils_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/types"
|
|
||||||
"git.sapphic.engineer/roleypoly/v4/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRoleInputID(t *testing.T) {
|
|
||||||
assert.Equal(t, "category-123_role-456", utils.RoleInputID(&types.Category{ID: "123"}, &types.Role{ID: "456"}))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRoleInputName(t *testing.T) {
|
|
||||||
assert.Equal(t, "category_group_123", utils.RoleInputName(&types.Category{ID: "123"}))
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue