mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-28 08:45:32 +00:00
resetbutton & almanach edit start
This commit is contained in:
@@ -68,6 +68,7 @@ type AlmanachResult struct {
|
||||
EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
|
||||
EntriesAgents []*dbmodels.REntriesAgents
|
||||
ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
|
||||
User *dbmodels.User
|
||||
|
||||
Types []string
|
||||
HasScans bool
|
||||
@@ -166,6 +167,16 @@ func NewAlmanachResult(app core.App, id string, params BeitraegeFilterParameters
|
||||
agentsMap[a.Id] = a
|
||||
}
|
||||
|
||||
var user *dbmodels.User
|
||||
if entry.Editor() != "" {
|
||||
u, err := dbmodels.Users_ID(app, entry.Editor())
|
||||
if err == nil {
|
||||
user = u
|
||||
} else {
|
||||
app.Logger().Error("Failed to load user for entry editor", "entry", entry.Id, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
ret := &AlmanachResult{
|
||||
Entry: entry,
|
||||
Places: places,
|
||||
@@ -177,6 +188,7 @@ func NewAlmanachResult(app core.App, id string, params BeitraegeFilterParameters
|
||||
ContentsAgents: caMap,
|
||||
Types: types,
|
||||
HasScans: hs,
|
||||
User: user,
|
||||
}
|
||||
|
||||
ret.Collections()
|
||||
|
||||
@@ -125,12 +125,11 @@ func (p *LoginPage) POST(engine *templating.Engine, app core.App) HandleFunc {
|
||||
return Unauthorized(engine, e, fmt.Errorf("Benuztername oder Passwort falsch. Bitte versuchen Sie es erneut."), data)
|
||||
}
|
||||
|
||||
record, err := app.FindFirstRecordByData(dbmodels.USERS_TABLE, dbmodels.USERS_EMAIL_FIELD, formdata.Username)
|
||||
if err != nil || !record.ValidatePassword(formdata.Password) {
|
||||
user, err := dbmodels.Users_Email(app, formdata.Username)
|
||||
if err != nil || !user.ValidatePassword(formdata.Password) {
|
||||
return Unauthorized(engine, e, fmt.Errorf("Benuztername oder Passwort falsch. Bitte versuchen Sie es erneut."), data)
|
||||
}
|
||||
|
||||
user := dbmodels.NewUser(record)
|
||||
if user.Deactivated() {
|
||||
return Unauthorized(engine, e, fmt.Errorf("Ihr Benutzerkonto ist deaktiviert. Bitte kontaktieren Sie den Administrator."), data)
|
||||
}
|
||||
@@ -140,7 +139,7 @@ func (p *LoginPage) POST(engine *templating.Engine, app core.App) HandleFunc {
|
||||
duration = time.Hour * 24 * 90
|
||||
}
|
||||
|
||||
token, err := dbmodels.CreateSessionToken(app, record.Id, e.RealIP(), e.Request.UserAgent(), formdata.Persistent == "on", duration)
|
||||
token, err := dbmodels.CreateSessionToken(app, user.Id, e.RealIP(), e.Request.UserAgent(), formdata.Persistent == "on", duration)
|
||||
if err != nil || token == nil || token.SessionTokenClear == "" {
|
||||
return engine.Response500(e, err, data)
|
||||
}
|
||||
|
||||
@@ -53,14 +53,13 @@ func Logout(e *core.RequestEvent, app *core.App) {
|
||||
if err == nil && app != nil {
|
||||
go func() {
|
||||
app := *app
|
||||
record, err := app.FindFirstRecordByData(dbmodels.SESSIONS_TABLE, dbmodels.SESSIONS_TOKEN_FIELD, dbmodels.HashStringSHA256(cookie.Value))
|
||||
if err == nil && record != nil {
|
||||
session := dbmodels.NewSession(record)
|
||||
session, err := dbmodels.Sessions_Token(app, cookie.Value)
|
||||
if err == nil {
|
||||
session.SetStatus(dbmodels.MUSENALM_STATUS_VALUES[1])
|
||||
if err := app.Save(session); err != nil {
|
||||
app.Logger().Error("Failed to update session status.", "error", err.Error())
|
||||
}
|
||||
} else if err != nil {
|
||||
} else {
|
||||
app.Logger().Error("Failed to find session record.", "error", err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -64,12 +64,11 @@ func (p *UserEditPage) GET(engine *templating.Engine, app core.App) HandleFunc {
|
||||
|
||||
func (p *UserEditPage) getData(app core.App, data map[string]any, e *core.RequestEvent) error {
|
||||
uid := e.Request.PathValue(UID_PATH_VALUE)
|
||||
u, err := app.FindRecordById(dbmodels.USERS_TABLE, uid)
|
||||
user, err := dbmodels.Users_ID(app, uid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Konnte Nutzer nicht finden: %w", err)
|
||||
}
|
||||
|
||||
user := dbmodels.NewUser(u)
|
||||
fu := user.Fixed()
|
||||
|
||||
data["user"] = &fu
|
||||
@@ -220,11 +219,10 @@ func (p *UserEditPage) POST(engine *templating.Engine, app core.App) HandleFunc
|
||||
req := templating.NewRequest(e)
|
||||
user := req.User()
|
||||
|
||||
u, err := app.FindRecordById(dbmodels.USERS_TABLE, uid)
|
||||
user_proxy, err := dbmodels.Users_ID(app, uid)
|
||||
if err != nil {
|
||||
return engine.Response404(e, err, nil)
|
||||
}
|
||||
user_proxy := dbmodels.NewUser(u)
|
||||
fu := user_proxy.Fixed()
|
||||
|
||||
formdata := struct {
|
||||
|
||||
@@ -142,13 +142,11 @@ func (p *UserManagementPage) POSTDeactivate(engine *templating.Engine, app core.
|
||||
return p.ErrorResponse(engine, e, err)
|
||||
}
|
||||
|
||||
user, err := app.FindRecordById(dbmodels.USERS_TABLE, formdata.User)
|
||||
u, err := dbmodels.Users_ID(app, formdata.User)
|
||||
if err != nil {
|
||||
return p.ErrorResponse(engine, e, fmt.Errorf("Konnte Nutzer nicht finden."))
|
||||
}
|
||||
|
||||
u := dbmodels.NewUser(user)
|
||||
|
||||
u.SetDeactivated(true)
|
||||
|
||||
if err := app.Save(u); err != nil {
|
||||
@@ -187,13 +185,11 @@ func (p *UserManagementPage) POSTActivate(engine *templating.Engine, app core.Ap
|
||||
return p.ErrorResponse(engine, e, err)
|
||||
}
|
||||
|
||||
user, err := app.FindRecordById(dbmodels.USERS_TABLE, formdata.User)
|
||||
u, err := dbmodels.Users_ID(app, formdata.User)
|
||||
if err != nil {
|
||||
return p.ErrorResponse(engine, e, fmt.Errorf("Konnte Nutzer nicht finden."))
|
||||
}
|
||||
|
||||
u := dbmodels.NewUser(user)
|
||||
|
||||
u.SetDeactivated(false)
|
||||
|
||||
if err := app.Save(u); err != nil {
|
||||
@@ -232,12 +228,11 @@ func (p *UserManagementPage) POSTLogout(engine *templating.Engine, app core.App)
|
||||
return p.ErrorResponse(engine, e, err)
|
||||
}
|
||||
|
||||
user, err := app.FindRecordById(dbmodels.USERS_TABLE, formdata.User)
|
||||
u, err := dbmodels.Users_ID(app, formdata.User)
|
||||
if err != nil {
|
||||
return p.ErrorResponse(engine, e, fmt.Errorf("Konnte Nutzer nicht finden."))
|
||||
}
|
||||
|
||||
u := dbmodels.NewUser(user)
|
||||
DeleteSessionsForUser(app, u.Id)
|
||||
|
||||
data := make(map[string]any)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
var _ core.RecordProxy = (*Entry)(nil)
|
||||
@@ -243,3 +244,19 @@ func (e *Entry) Editor() string {
|
||||
func (e *Entry) SetEditor(editor string) {
|
||||
e.Set(EDITOR_FIELD, editor)
|
||||
}
|
||||
|
||||
func (e *Entry) Updated() types.DateTime {
|
||||
return e.GetDateTime(UPDATED_FIELD)
|
||||
}
|
||||
|
||||
func (e *Entry) SetUpdated(updated types.DateTime) {
|
||||
e.Set(UPDATED_FIELD, updated)
|
||||
}
|
||||
|
||||
func (e *Entry) Created() types.DateTime {
|
||||
return e.GetDateTime(CREATED_FIELD)
|
||||
}
|
||||
|
||||
func (e *Entry) SetCreated(created types.DateTime) {
|
||||
e.Set(CREATED_FIELD, created)
|
||||
}
|
||||
|
||||
@@ -133,6 +133,42 @@ func Series_ID(app core.App, id string) (*Series, error) {
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
func Users_ID(app core.App, id string) (*User, error) {
|
||||
ret, err := TableByID[User](app, USERS_TABLE, id)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
func Sessions_ID(app core.App, id string) (*Session, error) {
|
||||
ret, err := TableByID[Session](app, SESSIONS_TABLE, id)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
func AccessTokens_Token(app core.App, token string) (*AccessToken, error) {
|
||||
t := HashStringSHA256(token)
|
||||
return TableByField[*AccessToken](
|
||||
app,
|
||||
ACCESS_TOKENS_TABLE,
|
||||
ACCESS_TOKENS_TOKEN_FIELD,
|
||||
t,
|
||||
)
|
||||
}
|
||||
|
||||
func Users_Email(app core.App, email string) (*User, error) {
|
||||
ret, err := TableByField[User](app, USERS_TABLE, USERS_EMAIL_FIELD, email)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
func Sessions_Token(app core.App, token string) (*Session, error) {
|
||||
t := HashStringSHA256(token)
|
||||
ret, err := TableByField[Session](
|
||||
app,
|
||||
SESSIONS_TABLE,
|
||||
SESSIONS_TOKEN_FIELD,
|
||||
t,
|
||||
)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
func Places_IDs(app core.App, ids []any) ([]*Place, error) {
|
||||
return TableByIDs[*Place](app, PLACES_TABLE, ids)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package functions
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
type Weekday struct {
|
||||
@@ -18,6 +20,7 @@ type Month struct {
|
||||
}
|
||||
|
||||
var Months = []Month{
|
||||
{"N/A", "N/A", 0},
|
||||
{"Januar", "Jan", 1},
|
||||
{"Februar", "Feb", 2},
|
||||
{"März", "Mär", 3},
|
||||
@@ -30,7 +33,6 @@ var Months = []Month{
|
||||
{"Oktober", "Okt", 10},
|
||||
{"November", "Nov", 11},
|
||||
{"Dezember", "Dez", 12},
|
||||
{"N/A", "N/A", 0},
|
||||
}
|
||||
|
||||
var Weekdays = []Weekday{
|
||||
@@ -65,3 +67,27 @@ func GetMonth(month any) Month {
|
||||
fmt.Println("Invalid month value", month)
|
||||
return Months[12]
|
||||
}
|
||||
|
||||
func GermanDate(t types.DateTime) string {
|
||||
if t.IsZero() {
|
||||
return "N/A"
|
||||
}
|
||||
|
||||
location, _ := time.LoadLocation("Europe/Berlin")
|
||||
|
||||
time := t.Time().In(location)
|
||||
month := Months[time.Month()]
|
||||
weekday := Weekdays[time.Weekday()]
|
||||
return fmt.Sprintf("%s, %d. %s %d", weekday.ShortName, time.Day(), month.ShortName, time.Year())
|
||||
}
|
||||
|
||||
func GermanTime(t types.DateTime) string {
|
||||
if t.IsZero() {
|
||||
return "N/A"
|
||||
}
|
||||
|
||||
location, _ := time.LoadLocation("Europe/Berlin")
|
||||
|
||||
time := t.Time().In(location)
|
||||
return fmt.Sprintf("%02d:%02d", time.Hour(), time.Minute())
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ var deact_cookie = &http.Cookie{
|
||||
func Authenticated(app core.App) func(*core.RequestEvent) error {
|
||||
return func(e *core.RequestEvent) error {
|
||||
if strings.HasPrefix(e.Request.URL.Path, "/assets") ||
|
||||
strings.HasPrefix(e.Request.URL.Path, "/api") {
|
||||
strings.HasPrefix(e.Request.URL.Path, "/api") ||
|
||||
strings.HasPrefix(e.Request.URL.Path, "/_") {
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
@@ -32,22 +33,20 @@ func Authenticated(app core.App) func(*core.RequestEvent) error {
|
||||
|
||||
user, session, loaded := SESSION_CACHE.Get(cookie.Value)
|
||||
if !loaded {
|
||||
hashedsession := dbmodels.HashStringSHA256(cookie.Value)
|
||||
record, err := app.FindFirstRecordByData(dbmodels.SESSIONS_TABLE, dbmodels.SESSIONS_TOKEN_FIELD, hashedsession)
|
||||
s, err := dbmodels.Sessions_Token(app, cookie.Value)
|
||||
if err != nil {
|
||||
e.SetCookie(deact_cookie)
|
||||
e.Response.Header().Set("Clear-Site-Data", "\"cookies\"")
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
s := dbmodels.NewSession(record)
|
||||
r, err := app.FindRecordById(dbmodels.USERS_TABLE, s.User())
|
||||
slog.Debug("Session loaded from database", "session", s.Id, "user", s.User())
|
||||
u, err := dbmodels.Users_ID(app, s.User())
|
||||
if err != nil {
|
||||
e.SetCookie(deact_cookie)
|
||||
e.Response.Header().Set("Clear-Site-Data", "\"cookies\"")
|
||||
return e.Next()
|
||||
}
|
||||
u := dbmodels.NewUser(r)
|
||||
user, session = SESSION_CACHE.Set(u, s)
|
||||
}
|
||||
|
||||
@@ -59,12 +58,15 @@ func Authenticated(app core.App) func(*core.RequestEvent) error {
|
||||
slog.Warn("Session expired", "user", user.Id, "name", user.Name, "session", session.ID)
|
||||
SESSION_CACHE.Delete(cookie.Value)
|
||||
go func() {
|
||||
r, err := app.FindRecordById(dbmodels.SESSIONS_TABLE, session.ID)
|
||||
r, err := dbmodels.Sessions_ID(app, session.ID)
|
||||
if err == nil {
|
||||
r.SetStatus(dbmodels.TOKEN_STATUS_VALUES[1])
|
||||
if err := app.Save(r); err != nil {
|
||||
app.Logger().Error("Failed to save session status", "session", session.ID, "error", err)
|
||||
}
|
||||
}
|
||||
e.SetCookie(deact_cookie)
|
||||
e.Response.Header().Set("Clear-Site-Data", "\"cookies\"")
|
||||
if err == nil {
|
||||
app.Delete(r)
|
||||
}
|
||||
}()
|
||||
return e.Next()
|
||||
}
|
||||
@@ -74,21 +76,19 @@ func Authenticated(app core.App) func(*core.RequestEvent) error {
|
||||
|
||||
token := e.Request.URL.Query().Get("token")
|
||||
if token != "" {
|
||||
record, err := app.FindFirstRecordByData(dbmodels.ACCESS_TOKENS_TABLE, dbmodels.ACCESS_TOKENS_TOKEN_FIELD, token)
|
||||
a, err := dbmodels.AccessTokens_Token(app, token)
|
||||
if err != nil {
|
||||
slog.Error("Failed to find access token", "token", token, "error", err)
|
||||
return e.Next()
|
||||
}
|
||||
a := dbmodels.NewAccessToken(record)
|
||||
|
||||
if a.User() != "" {
|
||||
r, err := app.FindRecordById(dbmodels.USERS_TABLE, a.User())
|
||||
u, err := dbmodels.Users_ID(app, a.User())
|
||||
if err != nil {
|
||||
slog.Error("Failed to find access token user", "user", a.User(), "error", err)
|
||||
return e.Next()
|
||||
}
|
||||
|
||||
u := dbmodels.NewUser(r)
|
||||
e.Set("access_token_user", u.Fixed())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,3 +12,11 @@ Ideen:
|
||||
|
||||
- Logout auf einer geschützen Seite: weiterleitung (evtl. referer nutzen?) -> evtl. footer-logout link ändern auf AdminPage
|
||||
- Tooltips
|
||||
|
||||
|
||||
06221 56 34 553
|
||||
hr. konuk
|
||||
9-15.30 Uhr
|
||||
|
||||
|
||||
von beratung sprechen
|
||||
|
||||
@@ -124,6 +124,8 @@ func (e *Engine) funcs() error {
|
||||
e.AddFunc("Contains", functions.Contains)
|
||||
e.AddFunc("Add", functions.Add)
|
||||
e.AddFunc("Len", functions.Length)
|
||||
e.AddFunc("GermanDate", functions.GermanDate)
|
||||
e.AddFunc("GermanTime", functions.GermanTime)
|
||||
|
||||
// String Functions
|
||||
e.AddFunc("Lower", functions.Lower)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
325
views/bun.lock
Normal file
325
views/bun.lock
Normal file
@@ -0,0 +1,325 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "caveman_views",
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.0.0",
|
||||
"daisyui": "^5.0.0-beta.8",
|
||||
"postcss": "^8.4.47",
|
||||
"postcss-cli": "^11.0.0",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-go-template": "^0.0.15",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"vite": "^6.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
|
||||
|
||||
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.5", "", { "os": "android", "cpu": "arm64" }, "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.5", "", { "os": "android", "cpu": "x64" }, "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.5", "", { "os": "linux", "cpu": "arm" }, "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.5", "", { "os": "none", "cpu": "arm64" }, "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.5", "", { "os": "none", "cpu": "x64" }, "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.5", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="],
|
||||
|
||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.41.1", "", { "os": "android", "cpu": "arm" }, "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.41.1", "", { "os": "android", "cpu": "arm64" }, "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.41.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.41.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.41.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.41.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.41.1", "", { "os": "linux", "cpu": "arm" }, "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.41.1", "", { "os": "linux", "cpu": "arm" }, "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.41.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.41.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg=="],
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw=="],
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.41.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.41.1", "", { "os": "linux", "cpu": "none" }, "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.41.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.41.1", "", { "os": "linux", "cpu": "x64" }, "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.41.1", "", { "os": "linux", "cpu": "x64" }, "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.41.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.41.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.41.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw=="],
|
||||
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.8", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.8" } }, "sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q=="],
|
||||
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.8", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.8", "@tailwindcss/oxide-darwin-arm64": "4.1.8", "@tailwindcss/oxide-darwin-x64": "4.1.8", "@tailwindcss/oxide-freebsd-x64": "4.1.8", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.8", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.8", "@tailwindcss/oxide-linux-arm64-musl": "4.1.8", "@tailwindcss/oxide-linux-x64-gnu": "4.1.8", "@tailwindcss/oxide-linux-x64-musl": "4.1.8", "@tailwindcss/oxide-wasm32-wasi": "4.1.8", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.8", "@tailwindcss/oxide-win32-x64-msvc": "4.1.8" } }, "sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A=="],
|
||||
|
||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw=="],
|
||||
|
||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8", "", { "os": "linux", "cpu": "arm" }, "sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.8", "", { "cpu": "none" }, "sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.8", "", { "os": "win32", "cpu": "x64" }, "sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ=="],
|
||||
|
||||
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.8", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.8", "@tailwindcss/oxide": "4.1.8", "postcss": "^8.4.41", "tailwindcss": "4.1.8" } }, "sha512-vB/vlf7rIky+w94aWMw34bWW1ka6g6C3xIOdICKX2GC0VcLtL6fhlLiafF0DVIwa9V6EHz8kbWMkS2s2QvvNlw=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||
|
||||
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||
|
||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||
|
||||
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"daisyui": ["daisyui@5.0.40", "", {}, "sha512-5GpRcRsArYjkeIhUrlMMIGGZzbuPCpCkEMokiO3PtkVr1/IFZezJO6lLR+lLxxMGm46EwRG/fSJw4VLeNMBZnw=="],
|
||||
|
||||
"dependency-graph": ["dependency-graph@1.0.0", "", {}, "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": "bin/esbuild" }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"fdir": ["fdir@6.4.5", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||
|
||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"jiti": ["jiti@2.4.2", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||
|
||||
"jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="],
|
||||
|
||||
"lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
|
||||
|
||||
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
|
||||
|
||||
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],
|
||||
|
||||
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="],
|
||||
|
||||
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="],
|
||||
|
||||
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="],
|
||||
|
||||
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="],
|
||||
|
||||
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="],
|
||||
|
||||
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="],
|
||||
|
||||
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="],
|
||||
|
||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
|
||||
|
||||
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||
|
||||
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||
|
||||
"minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
|
||||
|
||||
"mkdirp": ["mkdirp@3.0.1", "", { "bin": "dist/cjs/src/bin.js" }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
|
||||
|
||||
"pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="],
|
||||
|
||||
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||
|
||||
"postcss-cli": ["postcss-cli@11.0.1", "", { "dependencies": { "chokidar": "^3.3.0", "dependency-graph": "^1.0.0", "fs-extra": "^11.0.0", "picocolors": "^1.0.0", "postcss-load-config": "^5.0.0", "postcss-reporter": "^7.0.0", "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", "slash": "^5.0.0", "tinyglobby": "^0.2.12", "yargs": "^17.0.0" }, "peerDependencies": { "postcss": "^8.0.0" }, "bin": { "postcss": "index.js" } }, "sha512-0UnkNPSayHKRe/tc2YGW6XnSqqOA9eqpiRMgRlV1S6HdGi16vwJBx7lviARzbV1HpQHqLLRH3o8vTcB0cLc+5g=="],
|
||||
|
||||
"postcss-load-config": ["postcss-load-config@5.1.0", "", { "dependencies": { "lilconfig": "^3.1.1", "yaml": "^2.4.2" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1" }, "optionalPeers": ["tsx"] }, "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA=="],
|
||||
|
||||
"postcss-reporter": ["postcss-reporter@7.1.0", "", { "dependencies": { "picocolors": "^1.0.0", "thenby": "^1.3.4" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA=="],
|
||||
|
||||
"prettier": ["prettier@3.5.3", "", { "bin": "bin/prettier.cjs" }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
|
||||
|
||||
"prettier-plugin-go-template": ["prettier-plugin-go-template@0.0.15", "", { "dependencies": { "ulid": "^2.3.0" }, "peerDependencies": { "prettier": "^3.0.0" } }, "sha512-WqU92E1NokWYNZ9mLE6ijoRg6LtIGdLMePt2C7UBDjXeDH9okcRI3zRqtnWR4s5AloiqyvZ66jNBAa9tmRY5EQ=="],
|
||||
|
||||
"pretty-hrtime": ["pretty-hrtime@1.0.3", "", {}, "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A=="],
|
||||
|
||||
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
|
||||
|
||||
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||
|
||||
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
||||
|
||||
"rollup": ["rollup@4.41.1", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.41.1", "@rollup/rollup-android-arm64": "4.41.1", "@rollup/rollup-darwin-arm64": "4.41.1", "@rollup/rollup-darwin-x64": "4.41.1", "@rollup/rollup-freebsd-arm64": "4.41.1", "@rollup/rollup-freebsd-x64": "4.41.1", "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", "@rollup/rollup-linux-arm-musleabihf": "4.41.1", "@rollup/rollup-linux-arm64-gnu": "4.41.1", "@rollup/rollup-linux-arm64-musl": "4.41.1", "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-musl": "4.41.1", "@rollup/rollup-linux-s390x-gnu": "4.41.1", "@rollup/rollup-linux-x64-gnu": "4.41.1", "@rollup/rollup-linux-x64-musl": "4.41.1", "@rollup/rollup-win32-arm64-msvc": "4.41.1", "@rollup/rollup-win32-ia32-msvc": "4.41.1", "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw=="],
|
||||
|
||||
"slash": ["slash@5.1.0", "", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.8", "", {}, "sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og=="],
|
||||
|
||||
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
|
||||
|
||||
"tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
||||
|
||||
"thenby": ["thenby@1.3.4", "", {}, "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"ulid": ["ulid@2.4.0", "", { "bin": "bin/cli.js" }, "sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg=="],
|
||||
|
||||
"universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
|
||||
|
||||
"vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx"], "bin": "bin/vite.js" }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||
|
||||
"yaml": ["yaml@2.8.0", "", { "bin": "bin.mjs" }, "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ=="],
|
||||
|
||||
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{{- $date := Today -}}
|
||||
<footer id="footer" class="container-normal pb-1.5 text-base text-gray-800 relative" x-data="{ openusermenu: false }">
|
||||
<!-- INFO: User menu -->
|
||||
{{- if .request.user -}}
|
||||
<div class="" x-show="openusermenu">
|
||||
<div
|
||||
@@ -8,7 +9,7 @@
|
||||
[&>a]:block [&>a]:px-3 [&>a]:py-2 [&>a]:text-sm [&>a]:w-full [&>a]:text-left
|
||||
[&>a]:whitespace-nowrap [&>a]:transition-all [&>a]:duration-200 [&>a]:border-b
|
||||
[&>a]:last:border-b-0">
|
||||
<a href="/user/{{ .request.user.Id }}/edit?redirectTo={{ .request.fullpath }}" class="">
|
||||
<a :href="'/user/{{ .request.user.Id }}/edit?redirectTo=' + window.location" class="">
|
||||
<i class="ri-user-3-line"></i>
|
||||
Profil bearbeiten
|
||||
</a>
|
||||
@@ -29,8 +30,9 @@
|
||||
</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
<!-- END: User menu -->
|
||||
|
||||
|
||||
<!-- INFO: Actual Footer -->
|
||||
<div class="mt-12 pt-3 flex flex-row justify-between">
|
||||
<div>
|
||||
<i class="ri-creative-commons-line"></i>
|
||||
|
||||
@@ -27,12 +27,5 @@
|
||||
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
|
||||
|
||||
<script type="module">
|
||||
document.body.addEventListener("htmx:responseError", function (event) {
|
||||
const config = event.detail.requestConfig;
|
||||
if (config.boosted) {
|
||||
document.body.innerHTML = event.detail.xhr.responseText;
|
||||
const newUrl = event.detail.xhr.responseURL || config.url;
|
||||
window.history.pushState(null, "", newUrl);
|
||||
}
|
||||
});
|
||||
ShowBoostedErrors();
|
||||
</script>
|
||||
|
||||
@@ -1,26 +1,11 @@
|
||||
{
|
||||
"name": "caveman_views",
|
||||
"version": "1.0.0",
|
||||
"description": "default views for caveman",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"tailwind": "tailwindcss -i transform/site.css -o assets/style.css",
|
||||
"css": "postcss transform/site.css -o assets/style.css",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"author": "Simon Martens",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "github.com/Simon-Martens/pocketcatalog"
|
||||
},
|
||||
"keywords": [
|
||||
"DB",
|
||||
"htmx",
|
||||
"frontend"
|
||||
],
|
||||
"author": "Simon Martens",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.0.0",
|
||||
"daisyui": "^5.0.0-beta.8",
|
||||
@@ -30,5 +15,20 @@
|
||||
"prettier-plugin-go-template": "^0.0.15",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"vite": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"description": "default views for caveman",
|
||||
"keywords": [
|
||||
"DB",
|
||||
"htmx",
|
||||
"frontend"
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"tailwind": "tailwindcss -i transform/site.css -o assets/style.css",
|
||||
"css": "postcss transform/site.css -o assets/style.css",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -9,23 +9,70 @@ type AlmanachResult struct {
|
||||
EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
|
||||
EntriesAgents []*dbmodels.REntriesAgents
|
||||
ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
|
||||
User *dbmodels.User
|
||||
|
||||
Types []string
|
||||
HasScans bool
|
||||
}
|
||||
-->
|
||||
|
||||
<div class="flex container-normal bg-slate-100 mx-auto !pt-36 px-8">
|
||||
<div class="flex-col w-full">
|
||||
{{ if $model.redirect_url }}
|
||||
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
|
||||
<i class="ri-arrow-left-s-line"></i> Zurück
|
||||
</a>
|
||||
{{ else }}
|
||||
<a href="/" class="text-gray-700 hover:text-slate-950">
|
||||
<i class="ri-arrow-left-s-line"></i> Startseite
|
||||
</a>
|
||||
{{ end }}
|
||||
<h1 class="text-2xl self-baseline w-full my-6 font-bold text-slate-900">Almanach bearbeiten</h1>
|
||||
<div class="flex container-normal bg-slate-100 mx-auto px-8">
|
||||
<div class="flex flex-row w-full justify-between pb-6">
|
||||
<div class="flex flex-col justify-end-safe pt-36 flex-2/5">
|
||||
<a href="/almanach/{{ $model.result.Entry.MusenalmID }}" class="text-gray-700 hover:text-slate-950 block mb-2"><i class="ri-arrow-left-s-line"></i>Anschauen</a>
|
||||
<h1 class="text-2xl w-full font-bold text-slate-900">Almanach bearbeiten</h1>
|
||||
<!--
|
||||
<div class="mt-1">
|
||||
{{ $model.result.Entry.PreferredTitle }}
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
<div class="flex flex-row" id="almanach-header-data">
|
||||
<div class="flex flex-col justify-end gap-y-6 pr-20">
|
||||
<div class="">
|
||||
<div class="font-bold text-sm">
|
||||
<i class="ri-database-2-line"></i> Datenbank-ID
|
||||
<tool-tip position="right" class="!inline">
|
||||
<div class="data-tip">Die Datenbank-ID kann zur Fehlerdiagnose hilfreich sein.</div>
|
||||
<i class="ri-information-line"></i>
|
||||
</tool-tip>
|
||||
</div>
|
||||
<div class="">{{ $model.result.Entry.Id }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-end gap-y-6 pr-4">
|
||||
<div class="">
|
||||
<div class="font-bold text-sm mb-1">
|
||||
<i class="ri-hashtag"></i> Alm-Nummer
|
||||
<tool-tip position="right" class="!inline">
|
||||
<div class="data-tip">Die Alm-Nr ist Teil der URL und wird automatisch vergeben.</div>
|
||||
<i class="ri-information-line"></i>
|
||||
</tool-tip>
|
||||
</div>
|
||||
<div class="px-1.5 py-0.5 rounded-xs bg-gray-200 w-fit font-bold">{{ $model.result.Entry.MusenalmID }}</div>
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="font-bold text-sm mb-1"><i class="ri-calendar-line"></i> Zuletzt bearbeitet</div>
|
||||
<div>
|
||||
<div class="px-1.5 py-0.5 rounded-xs bg-gray-200 w-fit">
|
||||
{{ GermanDate $model.result.Entry.Updated }};
|
||||
{{ GermanTime
|
||||
$model.result.Entry.Updated
|
||||
}}
|
||||
</div>
|
||||
{{- if $model.result.User -}}
|
||||
<div class="px-1.5 py-0.5 rounded-xs mt-1.5 bg-gray-200 w-fit">
|
||||
<i class="ri-user-line mr-1"></i> {{- $model.result.User.Name -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-normal mx-auto px-8 mt-4">
|
||||
{{ template "_usermessage" $model }}
|
||||
<form class="w-full grid grid-cols-12 gap-4" id="changealmanachform" x-target="changealmanachform user-message almanach-header-data" hx-boost="false" method="POST"></form>
|
||||
</div>
|
||||
|
||||
@@ -20,15 +20,11 @@
|
||||
<div id="breadcrumbs">
|
||||
<div>
|
||||
<div>
|
||||
<a href="/personen?letter={{- First $model.result.Agent.Name -}}"
|
||||
>Personen & Körperschaften</a
|
||||
>
|
||||
<a href="/personen?letter={{- First $model.result.Agent.Name -}}">Personen & Körperschaften</a>
|
||||
<i class="ri-arrow-right-wide-line"></i> <b>{{ $model.result.Agent.Name }}</b>
|
||||
</div>
|
||||
<div class="backbutton">
|
||||
<a href="/personen/" class="no-underline">
|
||||
<i class="ri-arrow-left-long-line"></i> Alle Personen & Körperschaften
|
||||
</a>
|
||||
<a href="/personen/" class="no-underline"> <i class="ri-arrow-left-long-line"></i> Alle Personen & Körperschaften </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -155,32 +151,17 @@
|
||||
<input type="checkbox" id="showall" autocomplete="off" />
|
||||
<label for="showall" class="cursor-pointer select-none ml-1">Alle anzeigen</label>
|
||||
<script type="module">
|
||||
const tablist = document.getElementById("entries-tabs");
|
||||
const checkbox = document.getElementById("showall");
|
||||
entriestabs?.hookupShowAll(showall);
|
||||
{{- if eq (len $model.result.CResult) 1 -}}
|
||||
if (checkbox) {
|
||||
if (tablist) {
|
||||
tablist.showAll();
|
||||
}
|
||||
checkbox.checked = true;
|
||||
checkbox.disabled = true;
|
||||
}
|
||||
{{- else -}}
|
||||
if (tablist && checkbox) {
|
||||
checkbox.addEventListener("change", () => {
|
||||
if (checkbox && checkbox.checked) {
|
||||
tablist.showAll();
|
||||
} else {
|
||||
tablist.default();
|
||||
}
|
||||
});
|
||||
}
|
||||
entriestabs?.showAll();
|
||||
showall?.checked = true;
|
||||
showall?.disabled = true;
|
||||
{{- end -}}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8">
|
||||
<tab-list id="entries-tabs">
|
||||
<tab-list id="entriestabs">
|
||||
{{- range $_, $e := $model.result.CResult -}}
|
||||
{{- $contents := index $model.result.Contents $e.Id -}}
|
||||
<div
|
||||
@@ -191,8 +172,7 @@
|
||||
<i class="ri-arrow-right-s-fill show-closed"></i>
|
||||
<i class="ri-arrow-down-s-fill show-opened"></i>
|
||||
</div>
|
||||
<div
|
||||
class="inline-block font-sans bg-slate-800 text-white h-max text-sm px-1.5 rounded">
|
||||
<div class="inline-block font-sans bg-slate-800 text-white h-max text-sm px-1.5 rounded">
|
||||
{{- len $contents -}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,42 +14,54 @@
|
||||
|
||||
<div class="flex container-normal mx-auto px-8 mt-4">
|
||||
<div class="flex-col max-w-2xl w-full">
|
||||
<form class="w-full grid grid-cols-3 gap-4" id="changeuserform" x-target="changeuserform footer" hx-boost="false" method="POST" x-data="{ openpw: false }">
|
||||
<form
|
||||
class="w-full flex flex-col gap-4 dbform"
|
||||
id="changeuserform"
|
||||
x-target="changeuserform
|
||||
footer"
|
||||
hx-boost="false"
|
||||
method="POST"
|
||||
x-data="{ openpw: false }"
|
||||
@rbichange="FormHasChanged($el) ? resetb.classList.add('hidden') : resetb.classList.remove('hidden')">
|
||||
<!-- INFO: MESSAGES -->
|
||||
<div class="col-span-3">
|
||||
{{ template "_usermessage" $model }}
|
||||
</div>
|
||||
<div
|
||||
class="rounded-xs col-span-3 border-2 border-transparent px-3
|
||||
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||
<label for="username" class="text-sm text-gray-700 font-bold"> Name <i class="ri-text"></i> </label>
|
||||
<input type="text" name="name" id="name" class="mt-1 block w-full focus:border-none focus:outline-none" placeholder="" required autocomplete="off" value="{{ $model.user.Name }}" autofocus />
|
||||
|
||||
<!-- INFO: BASIC FELDER -->
|
||||
<div class="inputwrapper">
|
||||
<label for="username" class="inputlabel"> Name <i class="ri-text"></i> </label>
|
||||
<div class="flex flex-row">
|
||||
<input type="text" name="name" id="name" class="inputinput" placeholder="" required autocomplete="off" value="{{ $model.user.Name }}" autofocus />
|
||||
<reset-button controls="name" wrapper-class="inputwrapper" modified-class-suffix="modified"></reset-button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-xs col-span-3 border-2 border-transparent px-3
|
||||
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||
<label for="username" class="text-sm text-gray-700 font-bold"> E-Mail <i class="ri-at-line"></i> </label>
|
||||
<input type="email" name="username" id="username" autocomplete="off" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required value="{{ $model.user.Email }}" />
|
||||
<div class="inputwrapper">
|
||||
<label for="username" class="inputlabel"> E-Mail <i class="ri-at-line"></i> </label>
|
||||
<div class="flex flex-row">
|
||||
<input type="email" name="username" id="username" autocomplete="off" class="inputinput" placeholder="" required value="{{ $model.user.Email }}" />
|
||||
<reset-button controls="username" wrapper-class="inputwrapper" modified-class-suffix="modified"></reset-button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-xs col-span-3 border-2 border-transparent px-3
|
||||
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||
<label for="role" class="text-sm text-gray-700 font-bold"> Rolle <i class="ri-user-3-line"></i> </label>
|
||||
<select
|
||||
{{ if not (eq $model.request.user.Role "Admin") -}}
|
||||
disabled
|
||||
{{- end }}
|
||||
name="role"
|
||||
id="role"
|
||||
autocomplete="off"
|
||||
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none
|
||||
disabled:opacity-50">
|
||||
<option value="User" {{ if eq $model.user.Role "User" }}selected{{ end }}>Benutzer</option>
|
||||
<option value="Editor" {{ if eq $model.user.Role "Editor" }}selected{{ end }}>Redakteur</option>
|
||||
<option value="Admin" {{ if eq $model.user.Role "Admin" }}selected{{ end }}>Administrator</option>
|
||||
</select>
|
||||
|
||||
<!-- INFO: ROLLE -->
|
||||
<div class="inputwrapper">
|
||||
<label for="role" class="inputlabel"> Rolle <i class="ri-user-3-line"></i> </label>
|
||||
<div class="flex flex-row">
|
||||
<select
|
||||
{{ if not (eq $model.request.user.Role "Admin") -}}
|
||||
disabled
|
||||
{{- end }}
|
||||
name="role"
|
||||
id="role"
|
||||
autocomplete="off"
|
||||
class="inputselect">
|
||||
<option value="User" {{ if eq $model.user.Role "User" }}selected{{ end }}>Benutzer</option>
|
||||
<option value="Editor" {{ if eq $model.user.Role "Editor" }}selected{{ end }}>Redakteur</option>
|
||||
<option value="Admin" {{ if eq $model.user.Role "Admin" }}selected{{ end }}>Administrator</option>
|
||||
</select>
|
||||
<reset-button controls="role" wrapper-class="inputwrapper" modified-class-suffix="modified"></reset-button>
|
||||
</div>
|
||||
</div>
|
||||
{{- if and
|
||||
(eq $model.request.user.Role "Admin")
|
||||
@@ -70,63 +82,49 @@
|
||||
<p class="text-sm text-gray-700 max-w-[80ch]">Achtung! Wenn Sie die Rolle eines Benutzers ändern, wird dieser unter Umständen von laufenden Sitzungen abgemeldet und muss sich erneut anmelden.</p>
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
|
||||
<!-- INFO: PW ÄNDERN AUSKLAPPEN -->
|
||||
<div class="col-span-3">
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" name="openpw" id="openpw" x-model="openpw" class="mr-2" />
|
||||
<label for="openpw" class="text-sm text-gray-700 font-bold"> Passwort ändern <i class="ri-key-2-line"></i> </label>
|
||||
<label for="openpw" class="inputlabeltext"> Passwort ändern <i class="ri-key-2-line"></i> </label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- INFO: PASSWORT -->
|
||||
{{- if not (eq $model.request.user.Role "Admin") -}}
|
||||
<div
|
||||
x-bind:style="!openpw ? 'display:none' : ''"
|
||||
class="rounded-xs col-span-3 border-2 border-transparent px-3
|
||||
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||
<label for="password_old" class="text-sm text-gray-700 font-bold"> Altes Passwort </label>
|
||||
<input x-bind:type="openpw ? 'password' : 'hidden'" name="password_old" id="password_old" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required />
|
||||
<div x-bind:style="!openpw ? 'display:none' : ''" class="inputwrapper">
|
||||
<label for="password_old" class="inputlabel"> Altes Passwort </label>
|
||||
<input x-bind:type="openpw ? 'password' : 'hidden'" name="password_old" id="password_old" class="inputinput" placeholder="" required />
|
||||
</div>
|
||||
{{- end -}}
|
||||
<div
|
||||
x-bind:style="!openpw ? 'display:none' : ''"
|
||||
class="rounded-xs col-span-3 border-2 border-transparent px-3
|
||||
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||
<label for="password" class="text-sm text-gray-700 font-bold"> Neues Passwort </label>
|
||||
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password" id="password" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required />
|
||||
<div x-bind:style="!openpw ? 'display:none' : ''" class="inputwrapper">
|
||||
<label for="password" class="inputlabel"> Neues Passwort </label>
|
||||
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password" id="password" class="inputinput" placeholder="" required />
|
||||
</div>
|
||||
<div
|
||||
x-bind:style="!openpw ? 'display:none' : ''"
|
||||
class="rounded-xs col-span-3 border-2 border-transparent px-3
|
||||
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||
<label for="password_repeat" class="text-sm text-gray-700 font-bold"> Passwort wiederholen </label>
|
||||
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password_repeat" id="password_repeat" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required />
|
||||
<div x-bind:style="!openpw ? 'display:none' : ''" class="inputwrapper">
|
||||
<label for="password_repeat" class="inputlabel"> Passwort wiederholen </label>
|
||||
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password_repeat" id="password_repeat" class="inputinput" placeholder="" required />
|
||||
</div>
|
||||
<div class="col-span-3 flex justify-end" x-bind:style="!openpw ? 'display:none' : ''">
|
||||
<input type="checkbox" name="logout" id="logout" class="mr-2" x-bind:style="!openpw ? 'display:none' : ''" />
|
||||
<label for="logout" class="text-sm text-gray-700 font-bold"> überall ausloggen <i class="ri-logout-box-line"></i> </label>
|
||||
<label for="logout" class="inputlabeltext"><i class="ri-logout-box-line"></i> überall ausloggen</label>
|
||||
</div>
|
||||
<div class="col-span-1 col-start-2">
|
||||
<a
|
||||
href="/user/{{ $model.user.Id }}/edit?redirectTo={{ $model.redirect_url }}"
|
||||
type="cancel"
|
||||
class="w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md text-sm font-medium text-gray-800 bg-stone-200 hover:bg-stone-300 cursor-pointer focus:outline-none
|
||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 no-underline">
|
||||
Zurücksetzen
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-span-1 col-start-3">
|
||||
<input type="hidden" name="csrf_token" id="csrf_token" required value="{{ $model.csrf_token }}" />
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md
|
||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer focus:outline-none
|
||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
<!-- INFO: Buttons -->
|
||||
<div class="grid grid-cols-3 gap-4 col-span-3 mt-6">
|
||||
<div id="resetb" class="col-span-1 col-start-2 hidden">
|
||||
<a href="/user/{{ $model.user.Id }}/edit?redirectTo={{ $model.redirect_url }}" type="cancel" class="resetbutton"> Zurücksetzen </a>
|
||||
</div>
|
||||
<div class="col-span-1 col-start-3">
|
||||
<input type="hidden" name="csrf_token" id="csrf_token" required value="{{ $model.csrf_token }}" />
|
||||
<button type="submit" class="submitbutton">Speichern</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- INFO: Aktivieren/Deaktivieren -->
|
||||
<div class="col-span-1 mt-12 justify-self-end self-end items-end flex flex-row justify-end">
|
||||
{{ if not $model.user.Deactivated }}
|
||||
<form id="actbtn" x-init @ajax:before="confirm('Der Benutzer {{ $model.user.Name }} wird deaktiviert und kann sich nicht mehr einloggen. Sicher?') || $event.preventDefault()" action="/user/{{ $model.user.Id }}/deactivate/" method="POST" hx-boost="false" x-target="user-message footer actbtn" x-target.away="_top">
|
||||
|
||||
@@ -4,73 +4,8 @@
|
||||
<script src="/assets/js/qrcode.min.js"></script>
|
||||
|
||||
<script type="module">
|
||||
/**
|
||||
* @param {number} timeout - Maximum time to wait in milliseconds.
|
||||
* @param {number} interval - How often to check in milliseconds.
|
||||
* @returns {Promise<Function>} Resolves with the QRCode constructor when available.
|
||||
*/
|
||||
function getQRCodeWhenAvailable(timeout = 5000, interval = 100) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let elapsedTime = 0;
|
||||
const checkInterval = setInterval(() => {
|
||||
if (typeof window.QRCode === "function") {
|
||||
clearInterval(checkInterval);
|
||||
resolve(window.QRCode); // Resolve with the QRCode object/function
|
||||
} else {
|
||||
elapsedTime += interval;
|
||||
if (elapsedTime >= timeout) {
|
||||
clearInterval(checkInterval);
|
||||
console.error("Timed out waiting for QRCode to become available.");
|
||||
reject(new Error("QRCode not available after " + timeout + "ms. Check if qrcode.min.js is loaded correctly and sets window.QRCode."));
|
||||
}
|
||||
}
|
||||
}, interval);
|
||||
});
|
||||
}
|
||||
|
||||
// INFO: We have to wait for the QRCode object to be available. It's messy.
|
||||
async function genQRCode() {
|
||||
console.debug("Generating QR Code...");
|
||||
const QRCode = await getQRCodeWhenAvailable();
|
||||
const tokenElement = document.getElementById("token");
|
||||
const qrElement = document.getElementById("qr");
|
||||
if (qrElement) {
|
||||
// INFO: Clear previous QR code if any
|
||||
// Also hide it initially to prevent flickering
|
||||
qrElement.innerHTML = "";
|
||||
qrElement.classList.add("hidden");
|
||||
new QRCode(qrElement, {
|
||||
text: tokenElement.value,
|
||||
width: 1280,
|
||||
height: 1280,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.H,
|
||||
});
|
||||
setTimeout(() => {
|
||||
qrElement.classList.remove("hidden");
|
||||
}, 20);
|
||||
}
|
||||
|
||||
// Add event listeners to the token input field to select its content on focus or click
|
||||
if (tokenElement) {
|
||||
tokenElement.addEventListener("focus", (ev) => {
|
||||
ev.preventDefault();
|
||||
tokenElement.select();
|
||||
});
|
||||
tokenElement.addEventListener("mousedown", (ev) => {
|
||||
ev.preventDefault();
|
||||
tokenElement.select();
|
||||
});
|
||||
tokenElement.addEventListener("mouseup", (ev) => {
|
||||
ev.preventDefault();
|
||||
tokenElement.select();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
genQRCode();
|
||||
window.genQRCode = genQRCode;
|
||||
GenQRCode(token.value);
|
||||
SelectableInput(token);
|
||||
</script>
|
||||
|
||||
<div class="flex container-normal bg-slate-100 mx-auto !pt-36 px-8">
|
||||
@@ -135,7 +70,7 @@
|
||||
<i class="ri-external-link-line"></i>
|
||||
</a>
|
||||
</tool-tip>
|
||||
<form class="" method="POST" hx-boost="false" x-target="token access-link qrinfo" @ajax:after="genQRCode()">
|
||||
<form class="" method="POST" hx-boost="false" x-target="token access-link qrinfo" @ajax:after="GenQRCode(token.value); SelectableInput(token)">
|
||||
<input type="hidden" name="csrf_token" id="csrf_token" required value="{{ $model.csrf_token }}" />
|
||||
<div class="col-span-9 flex flex-row items-center justify-center">
|
||||
<tool-tip position="top">
|
||||
|
||||
276
views/transform/form.css
Normal file
276
views/transform/form.css
Normal file
@@ -0,0 +1,276 @@
|
||||
@layer components {
|
||||
.dbform .inputwrapper {
|
||||
@apply rounded-xs border-2 border-transparent px-3
|
||||
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100;
|
||||
}
|
||||
|
||||
.dbform .inputwrapper .inputlabel {
|
||||
@apply text-sm text-gray-700 font-bold;
|
||||
}
|
||||
|
||||
.inputlabeltext {
|
||||
@apply text-sm text-gray-700 font-bold;
|
||||
}
|
||||
|
||||
.dbform .inputwrapper .inputselect {
|
||||
@apply mt-1 block w-full rounded-md focus:border-none focus:outline-none
|
||||
disabled:opacity-50;
|
||||
}
|
||||
|
||||
.dbform .inputwrapper .inputinput {
|
||||
@apply mt-1 block w-full focus:border-none focus:outline-none;
|
||||
}
|
||||
|
||||
.dbform .submitbutton {
|
||||
@apply w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 active:bg-slate-900 transition-all duration-75;
|
||||
}
|
||||
|
||||
.dbform .resetbutton {
|
||||
@apply w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md text-sm font-medium text-gray-800 bg-stone-200 hover:bg-stone-300 cursor-pointer focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 no-underline;
|
||||
}
|
||||
|
||||
/* Multi-Select-Role example styles */
|
||||
.msr-selected-items-container {
|
||||
@apply rounded-md;
|
||||
}
|
||||
.msr-placeholder-no-selection-text {
|
||||
@apply text-sm text-gray-500 italic px-2 py-1;
|
||||
}
|
||||
|
||||
.msr-input-area-wrapper {
|
||||
@apply p-2 rounded-md;
|
||||
}
|
||||
.msr-input-area-wrapper.msr-input-area-default-border {
|
||||
@apply border border-gray-300;
|
||||
}
|
||||
.msr-input-area-wrapper.msr-input-area-default-border:focus-within {
|
||||
@apply focus-within:border-gray-500 focus-within:ring-1 focus-within:ring-gray-400;
|
||||
}
|
||||
.msr-input-area-wrapper.msr-input-area-staged {
|
||||
@apply border border-transparent;
|
||||
}
|
||||
|
||||
.msr-text-input {
|
||||
@apply bg-transparent text-sm placeholder-gray-400;
|
||||
}
|
||||
|
||||
.msr-selected-item-pill {
|
||||
@apply bg-gray-200 text-gray-700 px-3 py-[0.3rem] rounded-md text-sm inline-flex items-center m-0.5;
|
||||
}
|
||||
.msr-item-name {
|
||||
@apply font-medium;
|
||||
}
|
||||
.msr-item-additional-data {
|
||||
@apply text-xs ml-1 text-gray-600;
|
||||
}
|
||||
.msr-selected-item-role {
|
||||
@apply font-semibold text-xs ml-1 text-gray-800;
|
||||
}
|
||||
.msr-selected-item-delete-btn {
|
||||
@apply bg-transparent border-none text-gray-500 text-lg leading-none px-1 cursor-pointer opacity-60 transition-opacity duration-200;
|
||||
}
|
||||
.msr-selected-item-delete-btn:hover {
|
||||
@apply hover:opacity-100 hover:text-gray-900;
|
||||
}
|
||||
|
||||
.msr-staged-item-pill {
|
||||
@apply bg-gray-100 text-gray-800 px-2 py-1 rounded-md text-sm font-medium;
|
||||
}
|
||||
.msr-staged-item-text {
|
||||
@apply mr-2;
|
||||
}
|
||||
|
||||
.msr-staged-role-select {
|
||||
@apply px-2 py-1 text-sm rounded-md border border-gray-300 bg-white outline-none text-gray-700;
|
||||
}
|
||||
.msr-staged-role-select:focus {
|
||||
@apply focus:border-gray-500 focus:ring-1 focus:ring-gray-400;
|
||||
}
|
||||
|
||||
.msr-staged-cancel-btn {
|
||||
@apply w-5 h-5 bg-gray-200 text-gray-600 rounded-full text-sm leading-none cursor-pointer;
|
||||
}
|
||||
.msr-staged-cancel-btn:hover {
|
||||
@apply hover:bg-gray-300 hover:text-gray-800;
|
||||
}
|
||||
|
||||
.msr-pre-add-button {
|
||||
@apply w-10 h-[42px] text-xl rounded-md bg-gray-50 text-gray-700 border border-gray-300 font-semibold outline-none;
|
||||
}
|
||||
.msr-pre-add-button:focus {
|
||||
@apply focus:border-gray-500 focus:ring-1 focus:ring-gray-400;
|
||||
}
|
||||
.msr-pre-add-button:hover {
|
||||
@apply hover:bg-gray-100;
|
||||
}
|
||||
.msr-pre-add-button:disabled {
|
||||
@apply disabled:bg-gray-200 disabled:text-gray-400 disabled:cursor-not-allowed disabled:border-gray-200;
|
||||
}
|
||||
.msr-pre-add-button.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.msr-add-button {
|
||||
@apply px-4 py-2 text-sm rounded-md bg-gray-600 text-white font-medium;
|
||||
}
|
||||
.msr-add-button:hover {
|
||||
@apply hover:bg-gray-700;
|
||||
}
|
||||
.msr-add-button:disabled {
|
||||
@apply disabled:bg-gray-300 disabled:cursor-not-allowed;
|
||||
}
|
||||
.msr-add-button.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.msr-options-list {
|
||||
@apply bg-white border border-gray-300 rounded-md shadow-md;
|
||||
}
|
||||
.msr-options-list.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.msr-option-item {
|
||||
@apply px-3 py-2 text-sm cursor-pointer transition-colors duration-75;
|
||||
}
|
||||
.msr-option-item:hover {
|
||||
@apply bg-gray-100 text-gray-800;
|
||||
}
|
||||
.msr-option-item-highlighted {
|
||||
@apply bg-gray-100 text-gray-800;
|
||||
}
|
||||
.msr-option-item-name {
|
||||
@apply font-medium;
|
||||
}
|
||||
.msr-option-item-detail {
|
||||
@apply text-xs ml-2 text-gray-500;
|
||||
}
|
||||
.msr-option-item-highlighted .msr-option-item-detail,
|
||||
.msr-option-item:hover .msr-option-item-detail {
|
||||
/* Ensure detail text color changes on hover too */
|
||||
@apply text-gray-600;
|
||||
}
|
||||
|
||||
multi-select-role[disabled] {
|
||||
/* This remains standard CSS as Tailwind's disabled: variant is for native elements */
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.msr-hidden-select {
|
||||
/* No specific styling needed as it's visually hidden by JS/inline style */
|
||||
}
|
||||
|
||||
/* --- MultiSelectSimple Component Base Styles (using @apply) --- */
|
||||
.mss-component-wrapper {
|
||||
/* 'relative' is set inline for positioning dropdown */
|
||||
}
|
||||
|
||||
.mss-selected-items-container {
|
||||
@apply border border-gray-300 p-1.5 rounded;
|
||||
/* Tailwind classes from component: flex flex-wrap gap-1 mb-1 min-h-[38px] */
|
||||
}
|
||||
|
||||
.mss-no-items-text {
|
||||
@apply italic text-xs text-gray-500 p-1 w-full; /* Adjusted font size slightly to match 'xs' */
|
||||
}
|
||||
|
||||
.mss-selected-item-pill {
|
||||
@apply bg-gray-200 text-gray-800 py-0.5 px-2 rounded text-xs leading-5; /* Adjusted font size and padding */
|
||||
/* Tailwind classes from component: flex items-center */
|
||||
}
|
||||
|
||||
.mss-selected-item-text {
|
||||
/* Base styles for text part of the pill */
|
||||
}
|
||||
.mss-selected-item-pill-detail {
|
||||
@apply ml-1 opacity-75 text-xs text-gray-600;
|
||||
}
|
||||
.mss-selected-item-pill-detail.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.mss-selected-item-delete-btn {
|
||||
@apply bg-transparent border-none text-gray-600 opacity-70 cursor-pointer ml-1 text-base leading-none align-middle hover:opacity-100 hover:text-gray-900 disabled:opacity-40 disabled:cursor-not-allowed;
|
||||
}
|
||||
|
||||
.mss-input-controls-container {
|
||||
/* Tailwind classes from component: flex items-center space-x-2 */
|
||||
}
|
||||
|
||||
.mss-input-wrapper {
|
||||
@apply border border-gray-300 rounded;
|
||||
/* Tailwind classes from component: relative flex items-center flex-grow */
|
||||
}
|
||||
.mss-input-wrapper-focused {
|
||||
@apply border-indigo-600 ring-1 ring-indigo-600; /* Using ring for focus shadow */
|
||||
}
|
||||
|
||||
.mss-text-input {
|
||||
@apply py-1.5 px-2 text-sm;
|
||||
/* Tailwind classes from component: w-full outline-none bg-transparent */
|
||||
}
|
||||
.mss-text-input::placeholder {
|
||||
@apply text-gray-400 italic;
|
||||
}
|
||||
|
||||
.mss-create-new-button {
|
||||
@apply bg-gray-100 text-gray-700 border border-gray-300 py-1 px-1.5 text-sm rounded hover:bg-gray-200 hover:border-gray-400 disabled:bg-gray-50 disabled:text-gray-400 disabled:border-gray-200 disabled:opacity-70 disabled:cursor-not-allowed;
|
||||
}
|
||||
.mss-create-new-button.hidden {
|
||||
@apply !hidden; /* Ensure it hides */
|
||||
}
|
||||
|
||||
.mss-options-list {
|
||||
@apply bg-white border border-gray-300 rounded shadow-md; /* Using shadow-md as a softer default */
|
||||
/* Tailwind classes from component: absolute z-20 w-full max-h-60 overflow-y-auto mt-1 hidden */
|
||||
}
|
||||
|
||||
.mss-option-item {
|
||||
@apply text-gray-700 py-1.5 px-2.5 text-sm cursor-pointer transition-colors duration-75 hover:bg-gray-100;
|
||||
}
|
||||
|
||||
.mss-option-item-name {
|
||||
@apply font-medium;
|
||||
}
|
||||
|
||||
.mss-option-item-detail {
|
||||
@apply text-gray-500 text-xs ml-1.5;
|
||||
}
|
||||
|
||||
.mss-option-item-highlighted {
|
||||
@apply bg-indigo-100 text-indigo-800;
|
||||
}
|
||||
.mss-option-item-highlighted .mss-option-item-name {
|
||||
/* @apply font-medium; */ /* Already set by .mss-option-item-name, inherit color from parent */
|
||||
}
|
||||
.mss-option-item-highlighted .mss-option-item-detail {
|
||||
@apply text-indigo-700;
|
||||
}
|
||||
|
||||
.mss-hidden-select {
|
||||
/* Styles are inline in _render for !important, no change needed here */
|
||||
}
|
||||
|
||||
multi-select-simple[disabled] {
|
||||
@apply opacity-60; /* Adjusted opacity */
|
||||
}
|
||||
multi-select-simple[disabled] .mss-selected-items-container {
|
||||
@apply bg-gray-100;
|
||||
}
|
||||
multi-select-simple[disabled] .mss-selected-item-pill {
|
||||
@apply bg-gray-300 text-gray-500;
|
||||
}
|
||||
multi-select-simple[disabled] .mss-selected-item-delete-btn {
|
||||
@apply text-gray-400;
|
||||
}
|
||||
|
||||
.rbi-button {
|
||||
@apply disabled:hidden;
|
||||
}
|
||||
|
||||
select + reset-button .rbi-button {
|
||||
@apply ml-3;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { IntLink } from "./int-link.js";
|
||||
import { ImageReel } from "./image-reel.js";
|
||||
import { MultiSelectRole } from "./multi-select-role.js";
|
||||
import { MultiSelectSimple } from "./multi-select-simple.js";
|
||||
import { ResetButton } from "./reset-button.js";
|
||||
|
||||
const FILTER_LIST_ELEMENT = "filter-list";
|
||||
const SCROLL_BUTTON_ELEMENT = "scroll-button";
|
||||
@@ -24,6 +25,7 @@ const FILTER_PILL_ELEMENT = "filter-pill";
|
||||
const IMAGE_REEL_ELEMENT = "image-reel";
|
||||
const MULTI_SELECT_ROLE_ELEMENT = "multi-select-places";
|
||||
const MULTI_SELECT_SIMPLE_ELEMENT = "multi-select-simple";
|
||||
const RESET_BUTTON_ELEMENT = "reset-button";
|
||||
|
||||
customElements.define(INT_LINK_ELEMENT, IntLink);
|
||||
customElements.define(ABBREV_TOOLTIPS_ELEMENT, AbbreviationTooltips);
|
||||
@@ -36,5 +38,118 @@ customElements.define(FILTER_PILL_ELEMENT, FilterPill);
|
||||
customElements.define(IMAGE_REEL_ELEMENT, ImageReel);
|
||||
customElements.define(MULTI_SELECT_ROLE_ELEMENT, MultiSelectRole);
|
||||
customElements.define(MULTI_SELECT_SIMPLE_ELEMENT, MultiSelectSimple);
|
||||
customElements.define(RESET_BUTTON_ELEMENT, ResetButton);
|
||||
|
||||
export { FilterList, ScrollButton, AbbreviationTooltips };
|
||||
function PathPlusQuery() {
|
||||
const path = window.location.pathname;
|
||||
const query = window.location.search;
|
||||
const fullPath = path + query;
|
||||
return encodeURIComponent(fullPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} timeout - Maximum time to wait in milliseconds.
|
||||
* @param {number} interval - How often to check in milliseconds.
|
||||
* @returns {Promise<Function>} Resolves with the QRCode constructor when available.
|
||||
*/
|
||||
function getQRCodeWhenAvailable(timeout = 5000, interval = 100) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let elapsedTime = 0;
|
||||
const checkInterval = setInterval(() => {
|
||||
if (typeof window.QRCode === "function") {
|
||||
clearInterval(checkInterval);
|
||||
resolve(window.QRCode); // Resolve with the QRCode object/function
|
||||
} else {
|
||||
elapsedTime += interval;
|
||||
if (elapsedTime >= timeout) {
|
||||
clearInterval(checkInterval);
|
||||
console.error("Timed out waiting for QRCode to become available.");
|
||||
reject(new Error("QRCode not available after " + timeout + "ms. Check if qrcode.min.js is loaded correctly and sets window.QRCode."));
|
||||
}
|
||||
}
|
||||
}, interval);
|
||||
});
|
||||
}
|
||||
|
||||
// INFO: We have to wait for the QRCode object to be available. It's messy.
|
||||
async function GenQRCode(value) {
|
||||
const QRCode = await getQRCodeWhenAvailable();
|
||||
const qrElement = document.getElementById("qr");
|
||||
if (qrElement) {
|
||||
// INFO: Clear previous QR code if any
|
||||
// Also hide it initially to prevent flickering
|
||||
qrElement.innerHTML = "";
|
||||
qrElement.classList.add("hidden");
|
||||
new QRCode(qrElement, {
|
||||
text: value,
|
||||
width: 1280,
|
||||
height: 1280,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.H,
|
||||
});
|
||||
setTimeout(() => {
|
||||
qrElement.classList.remove("hidden");
|
||||
}, 20);
|
||||
}
|
||||
|
||||
// Add event listeners to the token input field to select its content on focus or click
|
||||
}
|
||||
|
||||
function SelectableInput(tokenElement) {
|
||||
if (tokenElement) {
|
||||
tokenElement.addEventListener("focus", (ev) => {
|
||||
ev.preventDefault();
|
||||
tokenElement.select();
|
||||
});
|
||||
tokenElement.addEventListener("mousedown", (ev) => {
|
||||
ev.preventDefault();
|
||||
tokenElement.select();
|
||||
});
|
||||
tokenElement.addEventListener("mouseup", (ev) => {
|
||||
ev.preventDefault();
|
||||
tokenElement.select();
|
||||
});
|
||||
}
|
||||
if (tokenElement) {
|
||||
tokenElement.addEventListener("focus", () => {
|
||||
tokenElement.select();
|
||||
});
|
||||
tokenElement.addEventListener("click", () => {
|
||||
tokenElement.select();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Doesn't work properly.
|
||||
// Intended to make sure errors from boosted links are shown.
|
||||
function ShowBoostedErrors() {
|
||||
document.body.addEventListener("htmx:responseError", function (event) {
|
||||
const config = event.detail.requestConfig;
|
||||
if (config.boosted) {
|
||||
document.body.innerHTML = event.detail.xhr.responseText;
|
||||
const newUrl = event.detail.xhr.responseURL || config.url;
|
||||
window.history.pushState(null, "", newUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function FormHasChanged(form) {
|
||||
if (!form || !(form instanceof HTMLFormElement)) {
|
||||
return false;
|
||||
}
|
||||
const resetButton = form.querySelector("reset-button");
|
||||
if (resetButton && resetButton.changed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
window.ShowBoostedErrors = ShowBoostedErrors;
|
||||
window.GenQRCode = GenQRCode;
|
||||
window.SelectableInput = SelectableInput;
|
||||
window.PathPlusQuery = PathPlusQuery;
|
||||
window.FormHasChanged = FormHasChanged;
|
||||
|
||||
export { FilterList, ScrollButton, AbbreviationTooltips, MultiSelectSimple, MultiSelectRole, ToolTip, PopupImage, TabList, FilterPill, ImageReel, IntLink };
|
||||
|
||||
263
views/transform/reset-button.js
Normal file
263
views/transform/reset-button.js
Normal file
@@ -0,0 +1,263 @@
|
||||
const RBI_BUTTON_BASE_CLASS = "rbi-button";
|
||||
const RBI_ICON_CLASS = "rbi-icon";
|
||||
|
||||
export class ResetButton extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.initialStates = new Map();
|
||||
this._controlledElements = [];
|
||||
this.button = null;
|
||||
this.changed = false;
|
||||
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.handleReset = this.handleReset.bind(this);
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["controls", "wrapper-class", "modified-class-suffix", "button-aria-label"];
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// Use an HTML template literal string to define the button's structure
|
||||
const buttonHTML = `
|
||||
<button type="button" class="${RBI_BUTTON_BASE_CLASS} cursor-pointer disabled:cursor-default" aria-label="Reset field">
|
||||
<tool-tip position="right">
|
||||
<div class="data-tip">Feld zurücksetzen</div>
|
||||
<span class="${RBI_ICON_CLASS} ri-arrow-go-back-fill"></span>
|
||||
</tool-tip>
|
||||
</button>
|
||||
`;
|
||||
this.innerHTML = buttonHTML; // Set the inner HTML of the custom element
|
||||
this.button = this.querySelector("button"); // Get the button element
|
||||
|
||||
if (this.button) {
|
||||
this.button.addEventListener("click", this.handleReset);
|
||||
} else {
|
||||
// This case should ideally not be reached if the HTML string is correct
|
||||
console.error("ResetButtonIndividual: Button element not found after setting innerHTML.");
|
||||
}
|
||||
|
||||
this.updateControlledElements();
|
||||
this.updateButtonAriaLabel();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.button) {
|
||||
this.button.removeEventListener("click", this.handleReset);
|
||||
}
|
||||
this._controlledElements.forEach((el) => {
|
||||
el.removeEventListener("input", this.handleInputChange);
|
||||
el.removeEventListener("change", this.handleInputChange);
|
||||
});
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
|
||||
if (name === "controls") {
|
||||
this.updateControlledElements();
|
||||
}
|
||||
if (name === "controls" || name === "button-aria-label") {
|
||||
this.updateButtonAriaLabel();
|
||||
}
|
||||
}
|
||||
|
||||
updateControlledElements() {
|
||||
this._controlledElements.forEach((el) => {
|
||||
el.removeEventListener("input", this.handleInputChange);
|
||||
el.removeEventListener("change", this.handleInputChange);
|
||||
});
|
||||
this._controlledElements = [];
|
||||
this.initialStates.clear();
|
||||
|
||||
const controlIds = (this.getAttribute("controls") || "")
|
||||
.split(",")
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id);
|
||||
|
||||
if (!controlIds.length && this.button) {
|
||||
this.button.disabled = true;
|
||||
this.button.setAttribute("aria-disabled", "true");
|
||||
return;
|
||||
}
|
||||
|
||||
const foundElements = [];
|
||||
controlIds.forEach((id) => {
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
foundElements.push(element);
|
||||
this.storeInitialState(element);
|
||||
element.addEventListener("input", this.handleInputChange);
|
||||
element.addEventListener("change", this.handleInputChange);
|
||||
} else {
|
||||
console.warn(`ResetButtonIndividual: Element with ID "${id}" not found.`);
|
||||
}
|
||||
});
|
||||
this._controlledElements = foundElements;
|
||||
|
||||
if (this.button) {
|
||||
this.button.disabled = this._controlledElements.length === 0;
|
||||
this.button.setAttribute("aria-controls", this._controlledElements.map((el) => el.id).join(" "));
|
||||
if (this.button.disabled) {
|
||||
this.button.setAttribute("aria-disabled", "true");
|
||||
} else {
|
||||
this.button.removeAttribute("aria-disabled");
|
||||
}
|
||||
}
|
||||
this.checkIfModified();
|
||||
}
|
||||
|
||||
storeInitialState(element) {
|
||||
let state;
|
||||
switch (element.type) {
|
||||
case "checkbox":
|
||||
case "radio":
|
||||
state = { checked: element.checked };
|
||||
break;
|
||||
case "select-multiple":
|
||||
state = {
|
||||
selectedOptions: Array.from(element.options)
|
||||
.filter((o) => o.selected)
|
||||
.map((o) => o.value),
|
||||
};
|
||||
break;
|
||||
case "select-one":
|
||||
default:
|
||||
state = { value: element.value };
|
||||
break;
|
||||
}
|
||||
this.initialStates.set(element.id, state);
|
||||
}
|
||||
|
||||
resetElement(element) {
|
||||
const initialState = this.initialStates.get(element.id);
|
||||
if (!initialState) return;
|
||||
|
||||
switch (element.type) {
|
||||
case "checkbox":
|
||||
case "radio":
|
||||
element.checked = initialState.checked;
|
||||
break;
|
||||
case "select-multiple":
|
||||
Array.from(element.options).forEach((option) => {
|
||||
option.selected = initialState.selectedOptions.includes(option.value);
|
||||
});
|
||||
break;
|
||||
case "select-one":
|
||||
default:
|
||||
element.value = initialState.value;
|
||||
break;
|
||||
}
|
||||
element.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
|
||||
element.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
}
|
||||
|
||||
handleReset() {
|
||||
this._controlledElements.forEach((el) => {
|
||||
this.resetElement(el);
|
||||
});
|
||||
this.checkIfModified();
|
||||
}
|
||||
|
||||
handleInputChange(event) {
|
||||
if (this._controlledElements.includes(event.target)) {
|
||||
this.checkIfModified();
|
||||
}
|
||||
}
|
||||
|
||||
isElementModified(element) {
|
||||
const initialState = this.initialStates.get(element.id);
|
||||
if (!initialState) return false;
|
||||
|
||||
switch (element.type) {
|
||||
case "checkbox":
|
||||
case "radio":
|
||||
return element.checked !== initialState.checked;
|
||||
case "select-multiple":
|
||||
const currentSelected = Array.from(element.options)
|
||||
.filter((o) => o.selected)
|
||||
.map((o) => o.value);
|
||||
const initialSelected = initialState.selectedOptions;
|
||||
return currentSelected.length !== initialSelected.length || currentSelected.some((val) => !initialSelected.includes(val)) || initialSelected.some((val) => !currentSelected.includes(val));
|
||||
case "select-one":
|
||||
default:
|
||||
return element.value !== initialState.value;
|
||||
}
|
||||
}
|
||||
|
||||
checkIfModified() {
|
||||
let overallModified = false;
|
||||
this._controlledElements.forEach((el) => {
|
||||
const modified = this.isElementModified(el);
|
||||
if (modified) {
|
||||
overallModified = true;
|
||||
el.classList.add("modified-element");
|
||||
} else {
|
||||
el.classList.remove("modified-element");
|
||||
}
|
||||
});
|
||||
|
||||
const wrapperClass = this.getAttribute("wrapper-class");
|
||||
if (wrapperClass) {
|
||||
const wrapperElement = this.closest(`.${wrapperClass}`);
|
||||
if (wrapperElement) {
|
||||
const modifiedSuffix = this.getAttribute("modified-class-suffix") || "modified";
|
||||
const modifiedWrapperClassName = `${wrapperClass}-${modifiedSuffix}`;
|
||||
if (overallModified) {
|
||||
wrapperElement.classList.add(modifiedWrapperClassName);
|
||||
} else {
|
||||
wrapperElement.classList.remove(modifiedWrapperClassName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.button) {
|
||||
this.button.disabled = !overallModified || this._controlledElements.length === 0;
|
||||
if (this.button.disabled) {
|
||||
this.button.setAttribute("aria-disabled", "true");
|
||||
} else {
|
||||
this.button.removeAttribute("aria-disabled");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.changed !== overallModified) {
|
||||
const event = new CustomEvent("rbichange", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
modified: overallModified,
|
||||
controlledElementIds: this._controlledElements.map((el) => el.id),
|
||||
instance: this,
|
||||
},
|
||||
});
|
||||
this.dispatchEvent(event);
|
||||
this.changed = overallModified;
|
||||
}
|
||||
}
|
||||
|
||||
updateButtonAriaLabel() {
|
||||
if (!this.button) return;
|
||||
|
||||
let labelText = this.getAttribute("button-aria-label");
|
||||
|
||||
if (!labelText) {
|
||||
const controlIds = this._controlledElements.map((el) => el.id);
|
||||
if (controlIds.length === 1 && this._controlledElements[0]) {
|
||||
const controlledEl = this._controlledElements[0];
|
||||
const labelEl = document.querySelector(`label[for="${controlledEl.id}"]`);
|
||||
let fieldName = controlledEl.name || controlledEl.id;
|
||||
if (labelEl && labelEl.textContent) {
|
||||
fieldName = labelEl.textContent.trim().replace(/[:*]$/, "").trim();
|
||||
} else if (controlledEl.getAttribute("aria-label")) {
|
||||
fieldName = controlledEl.getAttribute("aria-label");
|
||||
}
|
||||
labelText = `Reset ${fieldName}`;
|
||||
} else if (controlIds.length > 1) {
|
||||
labelText = "Reset selected fields";
|
||||
} else {
|
||||
labelText = "Reset field";
|
||||
}
|
||||
}
|
||||
this.button.setAttribute("aria-label", labelText);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
@import "tailwindcss";
|
||||
@import "./form.css";
|
||||
@import "./usermgmt.css";
|
||||
|
||||
@theme {
|
||||
--font-script: Rancho, ui-serif;
|
||||
--font-sans: "Source Sans 3", "Merriweather Sans", ui-sans-serif;
|
||||
@@ -516,55 +519,6 @@
|
||||
@apply !text-slate-900 bg-stone-50;
|
||||
}
|
||||
|
||||
.user-chooser a {
|
||||
@apply px-4 py-2 no-underline text-gray-500 hover:text-slate-900 font-serif font-bold border-l-4 border-transparent hover:bg-slate-100 transition-all duration-75 rounded-xs;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"] {
|
||||
@apply text-slate-900 font-bold bg-slate-100 border-slate-900 shadow-sm;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"]:nth-child(1) {
|
||||
@apply border-blue-500;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"]:nth-child(2) {
|
||||
@apply border-orange-600;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"]:nth-child(3) {
|
||||
@apply border-red-600;
|
||||
}
|
||||
|
||||
.user-mgmt thead th {
|
||||
@apply text-left font-bold border-b-2 border-slate-800 py-2 px-3;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr td {
|
||||
@apply px-3 py-1.5;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr:nth-child(odd) td {
|
||||
@apply bg-slate-100;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr:nth-child(even) td {
|
||||
@apply bg-slate-50;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr td:last-of-type {
|
||||
@apply align-middle text-right pr-4;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr.deactivated td:not(:last-of-type) {
|
||||
@apply text-gray-400 line-through;
|
||||
}
|
||||
|
||||
.user-mgmt form button,
|
||||
.user-mgmt .edit-button {
|
||||
@apply bg-slate-700 text-gray-200 text-base rounded-xs font-sans transition-all duration-75 px-3 py-1.5 hover:bg-slate-800 hover:text-white cursor-pointer;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
@@ -576,240 +530,4 @@
|
||||
transform: rotate(360deg);
|
||||
} /* Pause at the final position */
|
||||
}
|
||||
|
||||
/* Multi-Select-Role example styles */
|
||||
.msr-selected-items-container {
|
||||
@apply rounded-md;
|
||||
}
|
||||
.msr-placeholder-no-selection-text {
|
||||
@apply text-sm text-gray-500 italic px-2 py-1;
|
||||
}
|
||||
|
||||
.msr-input-area-wrapper {
|
||||
@apply p-2 rounded-md;
|
||||
}
|
||||
.msr-input-area-wrapper.msr-input-area-default-border {
|
||||
@apply border border-gray-300;
|
||||
}
|
||||
.msr-input-area-wrapper.msr-input-area-default-border:focus-within {
|
||||
@apply focus-within:border-gray-500 focus-within:ring-1 focus-within:ring-gray-400;
|
||||
}
|
||||
.msr-input-area-wrapper.msr-input-area-staged {
|
||||
@apply border border-transparent;
|
||||
}
|
||||
|
||||
.msr-text-input {
|
||||
@apply bg-transparent text-sm placeholder-gray-400;
|
||||
}
|
||||
|
||||
.msr-selected-item-pill {
|
||||
@apply bg-gray-200 text-gray-700 px-3 py-[0.3rem] rounded-md text-sm inline-flex items-center m-0.5;
|
||||
}
|
||||
.msr-item-name {
|
||||
@apply font-medium;
|
||||
}
|
||||
.msr-item-additional-data {
|
||||
@apply text-xs ml-1 text-gray-600;
|
||||
}
|
||||
.msr-selected-item-role {
|
||||
@apply font-semibold text-xs ml-1 text-gray-800;
|
||||
}
|
||||
.msr-selected-item-delete-btn {
|
||||
@apply bg-transparent border-none text-gray-500 text-lg leading-none px-1 cursor-pointer opacity-60 transition-opacity duration-200;
|
||||
}
|
||||
.msr-selected-item-delete-btn:hover {
|
||||
@apply hover:opacity-100 hover:text-gray-900;
|
||||
}
|
||||
|
||||
.msr-staged-item-pill {
|
||||
@apply bg-gray-100 text-gray-800 px-2 py-1 rounded-md text-sm font-medium;
|
||||
}
|
||||
.msr-staged-item-text {
|
||||
@apply mr-2;
|
||||
}
|
||||
|
||||
.msr-staged-role-select {
|
||||
@apply px-2 py-1 text-sm rounded-md border border-gray-300 bg-white outline-none text-gray-700;
|
||||
}
|
||||
.msr-staged-role-select:focus {
|
||||
@apply focus:border-gray-500 focus:ring-1 focus:ring-gray-400;
|
||||
}
|
||||
|
||||
.msr-staged-cancel-btn {
|
||||
@apply w-5 h-5 bg-gray-200 text-gray-600 rounded-full text-sm leading-none cursor-pointer;
|
||||
}
|
||||
.msr-staged-cancel-btn:hover {
|
||||
@apply hover:bg-gray-300 hover:text-gray-800;
|
||||
}
|
||||
|
||||
.msr-pre-add-button {
|
||||
@apply w-10 h-[42px] text-xl rounded-md bg-gray-50 text-gray-700 border border-gray-300 font-semibold outline-none;
|
||||
}
|
||||
.msr-pre-add-button:focus {
|
||||
@apply focus:border-gray-500 focus:ring-1 focus:ring-gray-400;
|
||||
}
|
||||
.msr-pre-add-button:hover {
|
||||
@apply hover:bg-gray-100;
|
||||
}
|
||||
.msr-pre-add-button:disabled {
|
||||
@apply disabled:bg-gray-200 disabled:text-gray-400 disabled:cursor-not-allowed disabled:border-gray-200;
|
||||
}
|
||||
.msr-pre-add-button.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.msr-add-button {
|
||||
@apply px-4 py-2 text-sm rounded-md bg-gray-600 text-white font-medium;
|
||||
}
|
||||
.msr-add-button:hover {
|
||||
@apply hover:bg-gray-700;
|
||||
}
|
||||
.msr-add-button:disabled {
|
||||
@apply disabled:bg-gray-300 disabled:cursor-not-allowed;
|
||||
}
|
||||
.msr-add-button.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.msr-options-list {
|
||||
@apply bg-white border border-gray-300 rounded-md shadow-md;
|
||||
}
|
||||
.msr-options-list.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.msr-option-item {
|
||||
@apply px-3 py-2 text-sm cursor-pointer transition-colors duration-75;
|
||||
}
|
||||
.msr-option-item:hover {
|
||||
@apply bg-gray-100 text-gray-800;
|
||||
}
|
||||
.msr-option-item-highlighted {
|
||||
@apply bg-gray-100 text-gray-800;
|
||||
}
|
||||
.msr-option-item-name {
|
||||
@apply font-medium;
|
||||
}
|
||||
.msr-option-item-detail {
|
||||
@apply text-xs ml-2 text-gray-500;
|
||||
}
|
||||
.msr-option-item-highlighted .msr-option-item-detail,
|
||||
.msr-option-item:hover .msr-option-item-detail {
|
||||
/* Ensure detail text color changes on hover too */
|
||||
@apply text-gray-600;
|
||||
}
|
||||
|
||||
multi-select-role[disabled] {
|
||||
/* This remains standard CSS as Tailwind's disabled: variant is for native elements */
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.msr-hidden-select {
|
||||
/* No specific styling needed as it's visually hidden by JS/inline style */
|
||||
}
|
||||
|
||||
/* --- MultiSelectSimple Component Base Styles (using @apply) --- */
|
||||
.mss-component-wrapper {
|
||||
/* 'relative' is set inline for positioning dropdown */
|
||||
}
|
||||
|
||||
.mss-selected-items-container {
|
||||
@apply border border-gray-300 p-1.5 rounded;
|
||||
/* Tailwind classes from component: flex flex-wrap gap-1 mb-1 min-h-[38px] */
|
||||
}
|
||||
|
||||
.mss-no-items-text {
|
||||
@apply italic text-xs text-gray-500 p-1 w-full; /* Adjusted font size slightly to match 'xs' */
|
||||
}
|
||||
|
||||
.mss-selected-item-pill {
|
||||
@apply bg-gray-200 text-gray-800 py-0.5 px-2 rounded text-xs leading-5; /* Adjusted font size and padding */
|
||||
/* Tailwind classes from component: flex items-center */
|
||||
}
|
||||
|
||||
.mss-selected-item-text {
|
||||
/* Base styles for text part of the pill */
|
||||
}
|
||||
.mss-selected-item-pill-detail {
|
||||
@apply ml-1 opacity-75 text-xs text-gray-600;
|
||||
}
|
||||
.mss-selected-item-pill-detail.hidden {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.mss-selected-item-delete-btn {
|
||||
@apply bg-transparent border-none text-gray-600 opacity-70 cursor-pointer ml-1 text-base leading-none align-middle hover:opacity-100 hover:text-gray-900 disabled:opacity-40 disabled:cursor-not-allowed;
|
||||
}
|
||||
|
||||
.mss-input-controls-container {
|
||||
/* Tailwind classes from component: flex items-center space-x-2 */
|
||||
}
|
||||
|
||||
.mss-input-wrapper {
|
||||
@apply border border-gray-300 rounded;
|
||||
/* Tailwind classes from component: relative flex items-center flex-grow */
|
||||
}
|
||||
.mss-input-wrapper-focused {
|
||||
@apply border-indigo-600 ring-1 ring-indigo-600; /* Using ring for focus shadow */
|
||||
}
|
||||
|
||||
.mss-text-input {
|
||||
@apply py-1.5 px-2 text-sm;
|
||||
/* Tailwind classes from component: w-full outline-none bg-transparent */
|
||||
}
|
||||
.mss-text-input::placeholder {
|
||||
@apply text-gray-400 italic;
|
||||
}
|
||||
|
||||
.mss-create-new-button {
|
||||
@apply bg-gray-100 text-gray-700 border border-gray-300 py-1 px-1.5 text-sm rounded hover:bg-gray-200 hover:border-gray-400 disabled:bg-gray-50 disabled:text-gray-400 disabled:border-gray-200 disabled:opacity-70 disabled:cursor-not-allowed;
|
||||
}
|
||||
.mss-create-new-button.hidden {
|
||||
@apply !hidden; /* Ensure it hides */
|
||||
}
|
||||
|
||||
.mss-options-list {
|
||||
@apply bg-white border border-gray-300 rounded shadow-md; /* Using shadow-md as a softer default */
|
||||
/* Tailwind classes from component: absolute z-20 w-full max-h-60 overflow-y-auto mt-1 hidden */
|
||||
}
|
||||
|
||||
.mss-option-item {
|
||||
@apply text-gray-700 py-1.5 px-2.5 text-sm cursor-pointer transition-colors duration-75 hover:bg-gray-100;
|
||||
}
|
||||
|
||||
.mss-option-item-name {
|
||||
@apply font-medium;
|
||||
}
|
||||
|
||||
.mss-option-item-detail {
|
||||
@apply text-gray-500 text-xs ml-1.5;
|
||||
}
|
||||
|
||||
.mss-option-item-highlighted {
|
||||
@apply bg-indigo-100 text-indigo-800;
|
||||
}
|
||||
.mss-option-item-highlighted .mss-option-item-name {
|
||||
/* @apply font-medium; */ /* Already set by .mss-option-item-name, inherit color from parent */
|
||||
}
|
||||
.mss-option-item-highlighted .mss-option-item-detail {
|
||||
@apply text-indigo-700;
|
||||
}
|
||||
|
||||
.mss-hidden-select {
|
||||
/* Styles are inline in _render for !important, no change needed here */
|
||||
}
|
||||
|
||||
multi-select-simple[disabled] {
|
||||
@apply opacity-60; /* Adjusted opacity */
|
||||
}
|
||||
multi-select-simple[disabled] .mss-selected-items-container {
|
||||
@apply bg-gray-100;
|
||||
}
|
||||
multi-select-simple[disabled] .mss-selected-item-pill {
|
||||
@apply bg-gray-300 text-gray-500;
|
||||
}
|
||||
multi-select-simple[disabled] .mss-selected-item-delete-btn {
|
||||
@apply text-gray-400;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export class TabList extends HTMLElement {
|
||||
this.shown = -1;
|
||||
this._headings = [];
|
||||
this._contents = [];
|
||||
this._checkbox = null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -38,6 +39,19 @@ export class TabList extends HTMLElement {
|
||||
});
|
||||
}
|
||||
|
||||
hookupShowAll(checkbox) {
|
||||
if (checkbox) {
|
||||
this._checkbox = checkbox;
|
||||
checkbox.addEventListener("change", (event) => {
|
||||
if (event.target.checked) {
|
||||
this.showAll();
|
||||
} else {
|
||||
this.default();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
hookupEvtHandlers() {
|
||||
for (let heading of this._headings) {
|
||||
heading.addEventListener("click", this.handleTabClick.bind(this));
|
||||
|
||||
50
views/transform/usermgmt.css
Normal file
50
views/transform/usermgmt.css
Normal file
@@ -0,0 +1,50 @@
|
||||
@layer components {
|
||||
.user-chooser a {
|
||||
@apply px-4 py-2 no-underline text-gray-500 hover:text-slate-900 font-serif font-bold border-l-4 border-transparent hover:bg-slate-100 transition-all duration-75 rounded-xs;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"] {
|
||||
@apply text-slate-900 font-bold bg-slate-100 border-slate-900 shadow-sm;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"]:nth-child(1) {
|
||||
@apply border-blue-500;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"]:nth-child(2) {
|
||||
@apply border-orange-600;
|
||||
}
|
||||
|
||||
.user-chooser a[aria-current="page"]:nth-child(3) {
|
||||
@apply border-red-600;
|
||||
}
|
||||
|
||||
.user-mgmt thead th {
|
||||
@apply text-left font-bold border-b-2 border-slate-800 py-2 px-3;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr td {
|
||||
@apply px-3 py-1.5;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr:nth-child(odd) td {
|
||||
@apply bg-slate-100;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr:nth-child(even) td {
|
||||
@apply bg-slate-50;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr td:last-of-type {
|
||||
@apply align-middle text-right pr-4;
|
||||
}
|
||||
|
||||
.user-mgmt tbody tr.deactivated td:not(:last-of-type) {
|
||||
@apply text-gray-400 line-through;
|
||||
}
|
||||
|
||||
.user-mgmt form button,
|
||||
.user-mgmt .edit-button {
|
||||
@apply bg-slate-700 text-gray-200 text-base rounded-xs font-sans transition-all duration-75 px-3 py-1.5 hover:bg-slate-800 hover:text-white cursor-pointer;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user