New rewrite with svelte and pocketbase
5
.dockerignore
Normal file
|
@ -0,0 +1,5 @@
|
|||
frontend/node_modules
|
||||
frontend/.svelte-kit
|
||||
frontend/build
|
||||
|
||||
backend/pb_data
|
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
frontend/node_modules
|
||||
frontend/.svelte-kit
|
||||
frontend/build
|
||||
|
||||
backend/pb_data
|
47
Dockerfile
Normal file
|
@ -0,0 +1,47 @@
|
|||
FROM golang:1.24.1 AS gobuild
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Download Go modules
|
||||
COPY backend/go.mod backend/go.sum .
|
||||
RUN go mod download
|
||||
|
||||
# Copy the source code. Note the slash at the end, as explained in
|
||||
# https://docs.docker.com/engine/reference/builder/#copy
|
||||
COPY backend/*.go ./
|
||||
|
||||
# Build
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o custom_pocketbase
|
||||
|
||||
FROM oven/bun:latest AS base
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# install dependencies into temp directory
|
||||
# this will cache them and speed up future builds
|
||||
FROM base AS install
|
||||
RUN mkdir -p /temp/dev
|
||||
COPY frontend/package.json frontend/bun.lock /temp/dev/
|
||||
RUN cd /temp/dev && bun install --frozen-lockfile
|
||||
|
||||
# copy node_modules from temp directory
|
||||
# then copy all (non-ignored) project files into the image
|
||||
FROM base AS prerelease
|
||||
COPY --from=install /temp/dev/node_modules node_modules
|
||||
COPY frontend .
|
||||
|
||||
# [optional] tests & build
|
||||
ENV NODE_ENV=production
|
||||
RUN bun run build
|
||||
|
||||
# copy production dependencies and source code into final image
|
||||
FROM oven/bun:alpine AS release
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
ENV GO_ENV=production
|
||||
COPY start_server.sh .
|
||||
COPY --from=prerelease /usr/src/app/build .
|
||||
COPY --from=gobuild /usr/src/app/custom_pocketbase .
|
||||
COPY backend/pb_migrations ./pb_migrations
|
||||
|
||||
# run the app
|
||||
EXPOSE 8090
|
||||
ENTRYPOINT [ "./start_server.sh" ]
|
38
README.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# sv
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npx sv create
|
||||
|
||||
# create a new project in my-app
|
||||
npx sv create my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
15
TODO.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Choses qu'il me reste à faire pour une 100% parité avec l'ancienne version
|
||||
|
||||
- [x] création de decks
|
||||
- [x] Backend
|
||||
- [x] Frontend
|
||||
- [ ] affichage des top commandants
|
||||
- [ ] backend (créer le cache commandant)
|
||||
- [ ] frontend (créer les page avec slug)
|
||||
- [x] Filtrer les cache par pourcentage d'utilisation
|
||||
- [x] Affichage des stats par carte commandants
|
||||
- [x] Backend
|
||||
- [x] Frontend
|
||||
- [ ] Affichage des stats par carte normale
|
||||
- [ ] Backend
|
||||
- [ ] Frontend
|
295
backend/cache.go
Normal file
|
@ -0,0 +1,295 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
)
|
||||
|
||||
type CacheBrawlsetListItem struct {
|
||||
Name string
|
||||
SanitizedName string
|
||||
IconsSvgUri []string
|
||||
}
|
||||
|
||||
type CacheCarteListItem struct {
|
||||
Name string
|
||||
Url string
|
||||
Layout string
|
||||
SmallImage string
|
||||
SmallImageBack string
|
||||
NormalImage string
|
||||
NormalImageBack string
|
||||
Price float64
|
||||
CardmarketUri string
|
||||
NumberOfDecks int
|
||||
NumberOfPossibleDecks int
|
||||
PercentageOfDecks float64
|
||||
Synergy float64
|
||||
}
|
||||
|
||||
type CacheCarteListItemWithSynergy struct {
|
||||
MainCard CacheCarteListItem
|
||||
CanBeCommander bool
|
||||
Cards map[string][]CacheCarteListItem
|
||||
}
|
||||
|
||||
type CacheCarteSearch struct {
|
||||
Name string
|
||||
Url string
|
||||
SetName string
|
||||
}
|
||||
|
||||
type CacheBrawlsetData struct {
|
||||
Name string
|
||||
SanitizedName string
|
||||
Cards map[string][]CacheCarteListItem
|
||||
}
|
||||
|
||||
func (app *application) SetupCache() {
|
||||
app.pb.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
|
||||
if err := e.Next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
GenerateCache(e.App)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func GenerateCache(pb core.App) {
|
||||
log.Println("Creating json data cache...")
|
||||
defer timer("Generating cache")()
|
||||
var totalSize int64
|
||||
|
||||
brawlsets := []Brawlset{}
|
||||
mtgSetsQuery := []MtgSet{}
|
||||
mtgSets := map[string]MtgSet{}
|
||||
cardsQuery := []Carte{}
|
||||
cards := map[string]Carte{}
|
||||
cacheCardsSearch := []CacheCarteSearch{}
|
||||
cardsBySet := map[string][]Carte{}
|
||||
decks := []Deck{}
|
||||
decksByBset := map[string][]Deck{}
|
||||
|
||||
err := pb.DB().
|
||||
NewQuery("SELECT * FROM brawlset").
|
||||
All(&brawlsets)
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v", err))
|
||||
}
|
||||
|
||||
err = pb.DB().
|
||||
NewQuery("SELECT * FROM mtg_set").
|
||||
All(&mtgSetsQuery)
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v", err))
|
||||
}
|
||||
|
||||
err = pb.DB().
|
||||
NewQuery("SELECT * FROM deck").
|
||||
All(&decks)
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v", err))
|
||||
}
|
||||
|
||||
for _, v := range decks {
|
||||
decksByBset[v.Brawlset] = append(decksByBset[v.Brawlset], v)
|
||||
}
|
||||
|
||||
err = pb.DB().
|
||||
NewQuery("SELECT * FROM carte").
|
||||
All(&cardsQuery)
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v", err))
|
||||
}
|
||||
|
||||
for _, v := range mtgSetsQuery {
|
||||
mtgSets[v.ID] = v
|
||||
}
|
||||
|
||||
for _, v := range cardsQuery {
|
||||
cards[v.ID] = v
|
||||
cardsBySet[v.MtgSet] = append(cardsBySet[v.MtgSet], v)
|
||||
cacheCardsSearch = append(cacheCardsSearch, CacheCarteSearch{ Name: v.Name, Url: fmt.Sprintf("/card/%s-%s", v.SetCode,v.SanitizedName), SetName: mtgSets[v.MtgSet].Name})
|
||||
}
|
||||
|
||||
totalSize += int64(unsafe.Sizeof(cacheCardsSearch))
|
||||
pb.Store().Set("searchData", cacheCardsSearch)
|
||||
|
||||
cacheBrawlsetList := []CacheBrawlsetListItem{}
|
||||
for _, v := range brawlsets {
|
||||
setIconList := []string{}
|
||||
numberOfDecksPerColorIdentity := map[string]int{}
|
||||
cacheBrawlsetData := CacheBrawlsetData{Name: v.Name, SanitizedName: v.SanitizedName, Cards: map[string][]CacheCarteListItem{}}
|
||||
numberOfDecksPerCard := map[string]int{}
|
||||
synergyPerCards := map[string]map[string]int{}
|
||||
|
||||
for _, d := range decksByBset[v.ID] {
|
||||
|
||||
possibleColorIdentities := GetAllColorCombination(d.ColorIdentity)
|
||||
for _, color := range possibleColorIdentities {
|
||||
if _, ok := numberOfDecksPerColorIdentity[color]; ok {
|
||||
numberOfDecksPerColorIdentity[color]++
|
||||
} else {
|
||||
numberOfDecksPerColorIdentity[color] += 1
|
||||
}
|
||||
}
|
||||
// Increment number of deck for commander
|
||||
if _, ok := numberOfDecksPerCard[fmt.Sprintf("c-%s",d.Commander)]; ok {
|
||||
numberOfDecksPerCard[fmt.Sprintf("c-%s",d.Commander)]++
|
||||
} else {
|
||||
numberOfDecksPerCard[fmt.Sprintf("c-%s",d.Commander)] = 1
|
||||
}
|
||||
|
||||
// Increment number of deck for each card
|
||||
for _, c := range d.Cards {
|
||||
if _, ok := synergyPerCards[fmt.Sprintf("c-%s",d.Commander)]; !ok {
|
||||
synergyPerCards[fmt.Sprintf("c-%s", d.Commander)] = map[string]int{}
|
||||
}
|
||||
if _, ok := synergyPerCards[fmt.Sprintf("c-%s",d.Commander)][c.ID]; ok {
|
||||
synergyPerCards[fmt.Sprintf("c-%s",d.Commander)][c.ID]++
|
||||
} else {
|
||||
synergyPerCards[fmt.Sprintf("c-%s",d.Commander)][c.ID] = 1
|
||||
}
|
||||
|
||||
// Add number of decks per card
|
||||
if _, ok := numberOfDecksPerCard[c.ID]; ok {
|
||||
numberOfDecksPerCard[c.ID]++
|
||||
} else {
|
||||
numberOfDecksPerCard[c.ID] = 1
|
||||
}
|
||||
|
||||
// Add number of decks with the two same cards for synergy
|
||||
for _, tc := range d.Cards {
|
||||
if _, ok := synergyPerCards[c.ID]; !ok {
|
||||
synergyPerCards[c.ID] = map[string]int{}
|
||||
}
|
||||
|
||||
if _, ok := synergyPerCards[c.ID][tc.ID]; ok {
|
||||
synergyPerCards[c.ID][tc.ID]++
|
||||
} else {
|
||||
synergyPerCards[c.ID][tc.ID] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range v.Sets {
|
||||
setIconList = append(setIconList, mtgSets[s].IconUri)
|
||||
for _, c := range cardsBySet[s] {
|
||||
obj := CreateCardData(c, decksByBset, numberOfDecksPerColorIdentity, numberOfDecksPerCard, v.ID)
|
||||
cacheBrawlsetData.Cards[c.CardType] = append(cacheBrawlsetData.Cards[c.CardType], obj)
|
||||
|
||||
if c.CanBeCommander {
|
||||
obj.NumberOfDecks = numberOfDecksPerCard[fmt.Sprintf("c-%s",c.ID)]
|
||||
obj.Url = fmt.Sprintf("/commander/%s-%s", c.SetCode,c.SanitizedName)
|
||||
cacheBrawlsetData.Cards["commander"] = append(cacheBrawlsetData.Cards["commander"], obj)
|
||||
|
||||
detailsObj := CacheCarteListItemWithSynergy{
|
||||
MainCard: obj,
|
||||
CanBeCommander: true,
|
||||
Cards: map[string][]CacheCarteListItem{},
|
||||
}
|
||||
|
||||
// Add each card that already appeared in a deck
|
||||
for k := range synergyPerCards[fmt.Sprintf("c-%s",c.ID)] {
|
||||
synergyObj := CreateCardData(cards[k], decksByBset, numberOfDecksPerColorIdentity, numberOfDecksPerCard, v.ID)
|
||||
|
||||
synergy := 0 - synergyObj.PercentageOfDecks
|
||||
if numberOfDecksPerCard[fmt.Sprintf("c-%s",c.ID)] != 0 {
|
||||
synergy = (float64(synergyPerCards[fmt.Sprintf("c-%s",c.ID)][k]) / float64(numberOfDecksPerCard[fmt.Sprintf("c-%s",c.ID)])) - synergyObj.PercentageOfDecks
|
||||
}
|
||||
synergyObj.Synergy = synergy
|
||||
|
||||
detailsObj.Cards[cards[k].CardType] = append(detailsObj.Cards[cards[k].CardType], synergyObj)
|
||||
}
|
||||
|
||||
for k := range detailsObj.Cards {
|
||||
sort.Slice(detailsObj.Cards[k], func(i, j int) bool {
|
||||
if detailsObj.Cards[k][i].Synergy == detailsObj.Cards[k][j].Synergy {
|
||||
return detailsObj.Cards[k][i].PercentageOfDecks > detailsObj.Cards[k][j].PercentageOfDecks
|
||||
}
|
||||
return detailsObj.Cards[k][i].Synergy > detailsObj.Cards[k][j].Synergy
|
||||
})
|
||||
}
|
||||
|
||||
totalSize += int64(unsafe.Sizeof(detailsObj))
|
||||
pb.Store().Set(fmt.Sprintf("json/commander/%s-%s", c.SetCode, c.SanitizedName), detailsObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k := range cacheBrawlsetData.Cards {
|
||||
if k == "commander" {
|
||||
sort.Slice(cacheBrawlsetData.Cards[k], func(i, j int) bool { return cacheBrawlsetData.Cards[k][i].NumberOfDecks > cacheBrawlsetData.Cards[k][j].NumberOfDecks})
|
||||
} else {
|
||||
sort.Slice(cacheBrawlsetData.Cards[k], func(i, j int) bool {
|
||||
if cacheBrawlsetData.Cards[k][i].PercentageOfDecks == cacheBrawlsetData.Cards[k][j].PercentageOfDecks {
|
||||
return cacheBrawlsetData.Cards[k][i].NumberOfDecks > cacheBrawlsetData.Cards[k][j].NumberOfDecks
|
||||
}
|
||||
return cacheBrawlsetData.Cards[k][i].PercentageOfDecks > cacheBrawlsetData.Cards[k][j].PercentageOfDecks
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cacheBrawlsetList = append(cacheBrawlsetList, CacheBrawlsetListItem{Name: v.Name, SanitizedName: v.SanitizedName, IconsSvgUri: setIconList})
|
||||
|
||||
totalSize += int64(unsafe.Sizeof(cacheBrawlsetData))
|
||||
pb.Store().Set("json/brawlset/" + v.SanitizedName, cacheBrawlsetData)
|
||||
}
|
||||
|
||||
totalSize += int64(unsafe.Sizeof(cacheBrawlsetList))
|
||||
pb.Store().Set("json/misc/brawlsets", cacheBrawlsetList)
|
||||
|
||||
log.Println(fmt.Sprintf("Total cache size : %d", totalSize))
|
||||
}
|
||||
|
||||
func GetAllColorCombination(s []string) []string {
|
||||
res := []string{strings.Join(s,"")}
|
||||
for i := 1; i < len(s); i++ {
|
||||
combinations := CreateCombination(s, i)
|
||||
res = append(res, combinations...)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func CreateCardData(c Carte, decksByBset map[string][]Deck, numberOfDecksPerColorIdentity map[string]int, numberOfDecksPerCard map[string]int, bsetID string) CacheCarteListItem {
|
||||
price, err := strconv.ParseFloat(c.Price, 64)
|
||||
if err != nil {
|
||||
price = 0.0
|
||||
}
|
||||
|
||||
numberOfPossibleDecks := 0
|
||||
if len(c.ColorIdentity) == 0 {
|
||||
numberOfPossibleDecks = len(decksByBset[bsetID])
|
||||
} else {
|
||||
numberOfPossibleDecks = numberOfDecksPerColorIdentity[strings.Join(c.ColorIdentity,"")]
|
||||
}
|
||||
|
||||
percentageOfDecks := 0.0
|
||||
if numberOfPossibleDecks != 0 {
|
||||
percentageOfDecks = float64(numberOfDecksPerCard[c.ID]) / float64(numberOfPossibleDecks)
|
||||
}
|
||||
|
||||
return CacheCarteListItem{
|
||||
Name: c.Name,
|
||||
Url: fmt.Sprintf("/card/%s-%s", c.SetCode,c.SanitizedName),
|
||||
Layout: c.Layout,
|
||||
SmallImage: c.SmallImage,
|
||||
SmallImageBack: c.SmallImageBack,
|
||||
NormalImage: c.NormalImage,
|
||||
NormalImageBack: c.NormalImageBack,
|
||||
Price: price,
|
||||
CardmarketUri: c.CardmarketUri,
|
||||
NumberOfDecks: numberOfDecksPerCard[c.ID],
|
||||
NumberOfPossibleDecks: numberOfPossibleDecks,
|
||||
PercentageOfDecks: percentageOfDecks,
|
||||
}
|
||||
}
|
70
backend/crons.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (app *application) SetupCrons() {
|
||||
app.pb.Cron().MustAdd("update_sets_and_cards", "0 3 * * *", func() {
|
||||
log.Println("Started updating sets and cards...")
|
||||
|
||||
scryfallSets := fetchApiSets()
|
||||
|
||||
insertQuery := CreateBulkSetsInsertQuery(scryfallSets)
|
||||
_, err := app.pb.DB().
|
||||
NewQuery(insertQuery).
|
||||
Execute()
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v",err))
|
||||
}
|
||||
log.Println(fmt.Sprintf("Updated %d sets", len(scryfallSets)))
|
||||
|
||||
setsCodesQuery := []MtgSet{}
|
||||
err = app.pb.DB().
|
||||
NewQuery("SELECT id, code FROM mtg_set").
|
||||
All(&setsCodesQuery)
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v",err))
|
||||
}
|
||||
|
||||
setsCodes := map[string]string{}
|
||||
for _,v := range setsCodesQuery {
|
||||
setsCodes[v.ID] = v.Code
|
||||
}
|
||||
|
||||
selectedSets := []Brawlset{}
|
||||
selectedSetsCodes := []string{}
|
||||
err = app.pb.DB().
|
||||
NewQuery("SELECT sets FROM brawlset").
|
||||
All(&selectedSets)
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v",err))
|
||||
}
|
||||
for _, v := range selectedSets {
|
||||
for _, set := range v.Sets {
|
||||
selectedSetsCodes = append(selectedSetsCodes, setsCodes[set])
|
||||
}
|
||||
}
|
||||
|
||||
log.Println(fmt.Sprintf("Fetching %d sets...", len(selectedSetsCodes)))
|
||||
allCards := []ScryfallCard{}
|
||||
for _, v := range selectedSetsCodes {
|
||||
url := "https://api.scryfall.com/cards/search?q=(game%3Apaper)+set%3A" + v
|
||||
allCards = fetchApiCards(url, allCards)
|
||||
}
|
||||
|
||||
upsertQuery := CreateBulkCardsUpsertQuery(allCards)
|
||||
_, err = app.pb.DB().
|
||||
NewQuery(upsertQuery).
|
||||
Execute()
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[ERROR] %v",err))
|
||||
}
|
||||
log.Println(fmt.Sprintf("Updated %d cards", len(allCards)))
|
||||
})
|
||||
|
||||
app.pb.Cron().MustAdd("regenerate_cache_json", "30 3 * * *", func() {
|
||||
GenerateCache(app.pb.App)
|
||||
})
|
||||
}
|
BIN
backend/custom_pocketbase
Executable file
47
backend/go.mod
Normal file
|
@ -0,0 +1,47 @@
|
|||
module brawlset
|
||||
|
||||
go 1.24.1
|
||||
|
||||
require (
|
||||
github.com/labstack/echo v3.3.10+incompatible
|
||||
github.com/pocketbase/pocketbase v0.26.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/lithammer/fuzzysearch v1.1.8 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.27 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/pocketbase/dbx v1.11.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
golang.org/x/image v0.25.0 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/oauth2 v0.28.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.36.3 // indirect
|
||||
)
|
164
backend/go.sum
Normal file
|
@ -0,0 +1,164 @@
|
|||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
|
||||
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU=
|
||||
github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU=
|
||||
github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.26.6 h1:ya+D2QK5DP3ynntCEJPj5Sc6hl9KZ+ZsfxVKp9UCB4o=
|
||||
github.com/pocketbase/pocketbase v0.26.6/go.mod h1:Pd+NfdYGBHXJOi9OI5WHS/Shn7J0iDSv5rNcCZ93LJM=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
||||
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
||||
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
|
||||
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
|
||||
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
|
||||
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
|
||||
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
|
||||
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.36.3 h1:qYMYlFR+rtLDUzuXoST1SDIdEPbX8xzuhdF90WsX1ss=
|
||||
modernc.org/sqlite v1.36.3/go.mod h1:ADySlx7K4FdY5MaJcEv86hTJ0PjedAloTUuif0YS3ws=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
52
backend/main.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"log"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
)
|
||||
|
||||
// Copied from https://github.com/s-petr/longhabit/blob/main/backend/main.go
|
||||
|
||||
// application holds the core application state and configuration.
|
||||
type application struct {
|
||||
pb *pocketbase.PocketBase
|
||||
config appConfig
|
||||
}
|
||||
|
||||
// appConfig holds the application's configuration settings.
|
||||
type appConfig struct {
|
||||
dbDir string
|
||||
}
|
||||
|
||||
// newApplication creates and initializes a new application instance.
|
||||
func newApplication() *application {
|
||||
dbDir := getEnvOrDefault("DB_DIR", "pb_data")
|
||||
|
||||
return &application{
|
||||
pb: pocketbase.NewWithConfig(pocketbase.Config{DefaultDataDir: dbDir}),
|
||||
config: appConfig{
|
||||
dbDir: dbDir,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := newApplication()
|
||||
|
||||
app.SetupCache()
|
||||
app.SetupCrons()
|
||||
app.SetupRoutes()
|
||||
|
||||
log.Fatal(app.pb.Start())
|
||||
}
|
||||
|
||||
// getEnvOrDefault retrieves the value of an environment variable by key.
|
||||
// If the environment variable is empty or not set, it returns the defaultValue.
|
||||
func getEnvOrDefault(key, defaultValue string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
178
backend/pb_migrations/1744049420_created_carte.js
Normal file
|
@ -0,0 +1,178 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = new Collection({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3273110370",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "sanitized_name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3520360348",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "released_at",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text976907234",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "layout",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"exceptDomains": null,
|
||||
"hidden": false,
|
||||
"id": "url1456686396",
|
||||
"name": "small_image",
|
||||
"onlyDomains": null,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "url"
|
||||
},
|
||||
{
|
||||
"exceptDomains": null,
|
||||
"hidden": false,
|
||||
"id": "url2615033119",
|
||||
"name": "small_image_back",
|
||||
"onlyDomains": null,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "url"
|
||||
},
|
||||
{
|
||||
"exceptDomains": null,
|
||||
"hidden": false,
|
||||
"id": "url2291853061",
|
||||
"name": "normal_image",
|
||||
"onlyDomains": null,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "url"
|
||||
},
|
||||
{
|
||||
"exceptDomains": null,
|
||||
"hidden": false,
|
||||
"id": "url2961008824",
|
||||
"name": "normal_image_back",
|
||||
"onlyDomains": null,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "url"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text2363381545",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "type",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "select3054531206",
|
||||
"maxSelect": 2,
|
||||
"name": "color_identity",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "select",
|
||||
"values": [
|
||||
"B",
|
||||
"W",
|
||||
"R",
|
||||
"G",
|
||||
"U"
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "autodate3332085495",
|
||||
"name": "updated",
|
||||
"onCreate": true,
|
||||
"onUpdate": true,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
}
|
||||
],
|
||||
"id": "pbc_1905410326",
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"name": "carte",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
});
|
||||
|
||||
return app.save(collection);
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326");
|
||||
|
||||
return app.delete(collection);
|
||||
})
|
101
backend/pb_migrations/1744049617_created_set.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = new Collection({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3273110370",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "sanitized_name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1997877400",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "code",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "date3520360348",
|
||||
"max": "",
|
||||
"min": "",
|
||||
"name": "released_at",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "date"
|
||||
},
|
||||
{
|
||||
"exceptDomains": null,
|
||||
"hidden": false,
|
||||
"id": "url659239397",
|
||||
"name": "icon_uri",
|
||||
"onlyDomains": null,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "url"
|
||||
}
|
||||
],
|
||||
"id": "pbc_3912384429",
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"name": "set",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
});
|
||||
|
||||
return app.save(collection);
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429");
|
||||
|
||||
return app.delete(collection);
|
||||
})
|
78
backend/pb_migrations/1744049690_created_brawlset.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = new Collection({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3273110370",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "sanitized_name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_3912384429",
|
||||
"hidden": false,
|
||||
"id": "relation2492286417",
|
||||
"maxSelect": 999,
|
||||
"minSelect": 0,
|
||||
"name": "sets",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
}
|
||||
],
|
||||
"id": "pbc_749385185",
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"name": "brawlset",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
});
|
||||
|
||||
return app.save(collection);
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_749385185");
|
||||
|
||||
return app.delete(collection);
|
||||
})
|
45
backend/pb_migrations/1744049710_updated_carte.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("text3520360348")
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(10, new Field({
|
||||
"hidden": false,
|
||||
"id": "date3520360348",
|
||||
"max": "",
|
||||
"min": "",
|
||||
"name": "released_at",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "date"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(3, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3520360348",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "released_at",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("date3520360348")
|
||||
|
||||
return app.save(collection)
|
||||
})
|
94
backend/pb_migrations/1744049818_updated_carte.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(11, new Field({
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_3912384429",
|
||||
"hidden": false,
|
||||
"id": "relation3860080092",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "set",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
}))
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(12, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3805467153",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "set_code",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(13, new Field({
|
||||
"hidden": false,
|
||||
"id": "number3402113753",
|
||||
"max": null,
|
||||
"min": null,
|
||||
"name": "price",
|
||||
"onlyInt": false,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "number"
|
||||
}))
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(14, new Field({
|
||||
"exceptDomains": null,
|
||||
"hidden": false,
|
||||
"id": "url518645060",
|
||||
"name": "cardmarket_url",
|
||||
"onlyDomains": null,
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "url"
|
||||
}))
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(15, new Field({
|
||||
"hidden": false,
|
||||
"id": "bool1734659578",
|
||||
"name": "can_be_commander",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "bool"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("relation3860080092")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("text3805467153")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("number3402113753")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("url518645060")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("bool1734659578")
|
||||
|
||||
return app.save(collection)
|
||||
})
|
140
backend/pb_migrations/1744049951_created_deck.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = new Collection({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "select3054531206",
|
||||
"maxSelect": 2,
|
||||
"name": "color_identity",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "select",
|
||||
"values": [
|
||||
"B",
|
||||
"R",
|
||||
"G",
|
||||
"U",
|
||||
"W"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "_pb_users_auth_",
|
||||
"hidden": false,
|
||||
"id": "relation3479234172",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "owner",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
},
|
||||
{
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_1905410326",
|
||||
"hidden": false,
|
||||
"id": "relation3635975509",
|
||||
"maxSelect": 999,
|
||||
"minSelect": 0,
|
||||
"name": "cartes",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
},
|
||||
{
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_1905410326",
|
||||
"hidden": false,
|
||||
"id": "relation1121130682",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "commander",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
},
|
||||
{
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_749385185",
|
||||
"hidden": false,
|
||||
"id": "relation1826942456",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "brawlset",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "autodate2990389176",
|
||||
"name": "created",
|
||||
"onCreate": true,
|
||||
"onUpdate": false,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "autodate3332085495",
|
||||
"name": "updated",
|
||||
"onCreate": true,
|
||||
"onUpdate": true,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
}
|
||||
],
|
||||
"id": "pbc_1755402631",
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"name": "deck",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
});
|
||||
|
||||
return app.save(collection);
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1755402631");
|
||||
|
||||
return app.delete(collection);
|
||||
})
|
42
backend/pb_migrations/1744049967_updated_brawlset.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_749385185")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": true,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_749385185")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
74
backend/pb_migrations/1744049979_updated_carte.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": true,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(12, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3805467153",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "set_code",
|
||||
"pattern": "",
|
||||
"presentable": true,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(12, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text3805467153",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "set_code",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
42
backend/pb_migrations/1744049986_updated_deck.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1755402631")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": true,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1755402631")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
42
backend/pb_migrations/1744049999_updated_set.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": true,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(1, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text1579384326",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "name",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
28
backend/pb_migrations/1744051259_updated_set.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update collection data
|
||||
unmarshal({
|
||||
"createRule": "",
|
||||
"deleteRule": "",
|
||||
"listRule": "",
|
||||
"updateRule": "",
|
||||
"viewRule": ""
|
||||
}, collection)
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update collection data
|
||||
unmarshal({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"listRule": null,
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
}, collection)
|
||||
|
||||
return app.save(collection)
|
||||
})
|
20
backend/pb_migrations/1744119600_updated_set.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update collection data
|
||||
unmarshal({
|
||||
"name": "mtg_set"
|
||||
}, collection)
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update collection data
|
||||
unmarshal({
|
||||
"name": "set"
|
||||
}, collection)
|
||||
|
||||
return app.save(collection)
|
||||
})
|
42
backend/pb_migrations/1744119800_updated_deck.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1755402631")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(0, new Field({
|
||||
"autogeneratePattern": "[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 36,
|
||||
"min": 36,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9\\-]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1755402631")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(0, new Field({
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
42
backend/pb_migrations/1744119839_updated_mtg_set.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(0, new Field({
|
||||
"autogeneratePattern": "[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 36,
|
||||
"min": 36,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9\\-]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(0, new Field({
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
29
backend/pb_migrations/1744125643_updated_mtg_set.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(6, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text2363381545",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "type",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("text2363381545")
|
||||
|
||||
return app.save(collection)
|
||||
})
|
42
backend/pb_migrations/1744126008_updated_mtg_set.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(6, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text2363381545",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "type",
|
||||
"pattern": "",
|
||||
"presentable": true,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_3912384429")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(6, new Field({
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text2363381545",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "type",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
95
backend/pb_migrations/1744128064_created_posts.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = new Collection({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text724990059",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "title",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "_pb_users_auth_",
|
||||
"hidden": false,
|
||||
"id": "relation3182418120",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "author",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
},
|
||||
{
|
||||
"convertURLs": false,
|
||||
"hidden": false,
|
||||
"id": "editor37359206",
|
||||
"maxSize": 0,
|
||||
"name": "article",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "editor"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "autodate2990389176",
|
||||
"name": "created",
|
||||
"onCreate": true,
|
||||
"onUpdate": false,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "autodate3332085495",
|
||||
"name": "updated",
|
||||
"onCreate": true,
|
||||
"onUpdate": true,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
}
|
||||
],
|
||||
"id": "pbc_1125843985",
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"name": "posts",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
});
|
||||
|
||||
return app.save(collection);
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1125843985");
|
||||
|
||||
return app.delete(collection);
|
||||
})
|
95
backend/pb_migrations/1744128183_deleted_posts.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1125843985");
|
||||
|
||||
return app.delete(collection);
|
||||
}, (app) => {
|
||||
const collection = new Collection({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"fields": [
|
||||
{
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"autogeneratePattern": "",
|
||||
"hidden": false,
|
||||
"id": "text724990059",
|
||||
"max": 0,
|
||||
"min": 0,
|
||||
"name": "title",
|
||||
"pattern": "",
|
||||
"presentable": false,
|
||||
"primaryKey": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "_pb_users_auth_",
|
||||
"hidden": false,
|
||||
"id": "relation3182418120",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "author",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
},
|
||||
{
|
||||
"convertURLs": false,
|
||||
"hidden": false,
|
||||
"id": "editor37359206",
|
||||
"maxSize": 0,
|
||||
"name": "article",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "editor"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "autodate2990389176",
|
||||
"name": "created",
|
||||
"onCreate": true,
|
||||
"onUpdate": false,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
},
|
||||
{
|
||||
"hidden": false,
|
||||
"id": "autodate3332085495",
|
||||
"name": "updated",
|
||||
"onCreate": true,
|
||||
"onUpdate": true,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
}
|
||||
],
|
||||
"id": "pbc_1125843985",
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"name": "posts",
|
||||
"system": false,
|
||||
"type": "base",
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
});
|
||||
|
||||
return app.save(collection);
|
||||
})
|
42
backend/pb_migrations/1744133653_updated_carte.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(0, new Field({
|
||||
"autogeneratePattern": "[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 36,
|
||||
"min": 36,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9\\-]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(0, new Field({
|
||||
"autogeneratePattern": "[a-z0-9]{15}",
|
||||
"hidden": false,
|
||||
"id": "text3208210256",
|
||||
"max": 15,
|
||||
"min": 15,
|
||||
"name": "id",
|
||||
"pattern": "^[a-z0-9]+$",
|
||||
"presentable": false,
|
||||
"primaryKey": true,
|
||||
"required": true,
|
||||
"system": true,
|
||||
"type": "text"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
40
backend/pb_migrations/1744140479_updated_carte.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(11, new Field({
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_3912384429",
|
||||
"hidden": false,
|
||||
"id": "relation3860080092",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "mtg_set",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// update field
|
||||
collection.fields.addAt(11, new Field({
|
||||
"cascadeDelete": false,
|
||||
"collectionId": "pbc_3912384429",
|
||||
"hidden": false,
|
||||
"id": "relation3860080092",
|
||||
"maxSelect": 1,
|
||||
"minSelect": 0,
|
||||
"name": "set",
|
||||
"presentable": false,
|
||||
"required": false,
|
||||
"system": false,
|
||||
"type": "relation"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
25
backend/pb_migrations/1744149166_updated_carte.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// remove field
|
||||
collection.fields.removeById("autodate3332085495")
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1905410326")
|
||||
|
||||
// add field
|
||||
collection.fields.addAt(16, new Field({
|
||||
"hidden": false,
|
||||
"id": "autodate3332085495",
|
||||
"name": "updated",
|
||||
"onCreate": true,
|
||||
"onUpdate": true,
|
||||
"presentable": false,
|
||||
"system": false,
|
||||
"type": "autodate"
|
||||
}))
|
||||
|
||||
return app.save(collection)
|
||||
})
|
28
backend/pb_migrations/1744150791_updated_deck.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1755402631")
|
||||
|
||||
// update collection data
|
||||
unmarshal({
|
||||
"createRule": "@request.auth.id != \"\"",
|
||||
"deleteRule": "owner ?= @request.auth.id",
|
||||
"listRule": "owner ?= @request.auth.id",
|
||||
"updateRule": "owner ?= @request.auth.id",
|
||||
"viewRule": "owner ?= @request.auth.id"
|
||||
}, collection)
|
||||
|
||||
return app.save(collection)
|
||||
}, (app) => {
|
||||
const collection = app.findCollectionByNameOrId("pbc_1755402631")
|
||||
|
||||
// update collection data
|
||||
unmarshal({
|
||||
"createRule": null,
|
||||
"deleteRule": null,
|
||||
"listRule": null,
|
||||
"updateRule": null,
|
||||
"viewRule": null
|
||||
}, collection)
|
||||
|
||||
return app.save(collection)
|
||||
})
|
176
backend/routes.go
Normal file
|
@ -0,0 +1,176 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
"os"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
)
|
||||
|
||||
const frontEndDevPort = "5173"
|
||||
const frontEndProdPort = "3000"
|
||||
|
||||
type DeckImportCard struct {
|
||||
Name string `json:"name"`
|
||||
Amount int `json:"amount"`
|
||||
}
|
||||
|
||||
|
||||
type DeckImport struct {
|
||||
Name string `json:"name"`
|
||||
Url string `json:"url"`
|
||||
SelectedBset string `json:"selected_bset"`
|
||||
Commander string `json:"commander_name"`
|
||||
Cards []DeckImportCard `json:"cards"`
|
||||
}
|
||||
|
||||
func (app *application) SetupRoutes() {
|
||||
app.pb.OnServe().BindFunc(func(se *core.ServeEvent) error {
|
||||
mode := os.Getenv("GO_ENV")
|
||||
path := ""
|
||||
if mode == "" {
|
||||
log.Fatal("You must the env variable GO_ENV to either 'dev' or 'production'")
|
||||
}
|
||||
|
||||
if mode == "dev" {
|
||||
path = fmt.Sprintf("http://localhost:%s", frontEndDevPort)
|
||||
} else if mode == "production" {
|
||||
path = fmt.Sprintf("http://localhost:%s", frontEndProdPort)
|
||||
} else {
|
||||
log.Fatal(fmt.Sprintf("Error, unrecognized GO_ENV : %s\nSet it to either 'dev' or 'production'", mode))
|
||||
}
|
||||
|
||||
target, err := url.Parse(path)
|
||||
if err != nil {
|
||||
log.Println("[ERROR] failed to parse proxy target URL: %w", err)
|
||||
}
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(target)
|
||||
|
||||
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
http.Error(w, fmt.Sprintf("proxy error: %v", err), http.StatusBadGateway)
|
||||
}
|
||||
|
||||
// Cache Route
|
||||
se.Router.GET("/json/{path...}", func(re *core.RequestEvent) error {
|
||||
path := fmt.Sprintf("json/%s",re.Request.PathValue("path"))
|
||||
|
||||
cacheVal := app.pb.Store().Get(path)
|
||||
if cacheVal != nil {
|
||||
return re.JSON(http.StatusOK, cacheVal)
|
||||
} else {
|
||||
return re.JSON(http.StatusNotFound, map[string]string{"message": "json not found in cache"})
|
||||
}
|
||||
})
|
||||
|
||||
// Search API
|
||||
se.Router.GET("/api/search", func(re *core.RequestEvent) error {
|
||||
searchData := app.pb.Store().Get("searchData").([]CacheCarteSearch)
|
||||
search := re.Request.URL.Query().Get("q")
|
||||
|
||||
resultData := filter(searchData, func(card CacheCarteSearch) bool { return strings.Contains(strings.ToLower(card.Name), strings.ToLower(search)) })
|
||||
return re.JSON(http.StatusOK, resultData)
|
||||
})
|
||||
|
||||
// Create deck API
|
||||
se.Router.POST("/api/deck/create", func(re *core.RequestEvent) error {
|
||||
authRecord := re.Auth
|
||||
|
||||
data := DeckImport{}
|
||||
if err := re.BindBody(&data); err != nil {
|
||||
log.Println(err)
|
||||
return re.BadRequestError("Failed to read request data", err)
|
||||
}
|
||||
|
||||
selectedBrawlset := Brawlset{}
|
||||
err := app.pb.DB().
|
||||
NewQuery(fmt.Sprintf("SELECT id, sets FROM brawlset WHERE sanitized_name = '%v'", data.SelectedBset)).
|
||||
One(&selectedBrawlset)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return re.BadRequestError("No brawlsets with this id", err)
|
||||
}
|
||||
|
||||
possibleCards := []Carte{}
|
||||
setsIds := []string{}
|
||||
for _, v := range selectedBrawlset.Sets {
|
||||
setsIds = append(setsIds, fmt.Sprintf("'%s'", v))
|
||||
}
|
||||
query := ""
|
||||
if len(selectedBrawlset.Sets) > 1 {
|
||||
query = fmt.Sprintf("SELECT id, name, color_identity FROM carte WHERE mtg_set IN (%s)", strings.Join(setsIds, ", "))
|
||||
} else {
|
||||
query = fmt.Sprintf("SELECT id, name, color_identity FROM carte WHERE mtg_set = %s", setsIds[0])
|
||||
}
|
||||
err = app.pb.DB().
|
||||
NewQuery(query).
|
||||
All(&possibleCards)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return re.BadRequestError("Error with cards query", err)
|
||||
}
|
||||
|
||||
collection, err := app.pb.FindCollectionByNameOrId("deck")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record := core.NewRecord(collection)
|
||||
record.Set("name", data.Name)
|
||||
record.Set("url", data.Url)
|
||||
record.Set("brawlset", selectedBrawlset.ID)
|
||||
record.Set("owner", authRecord.Id)
|
||||
|
||||
for _, c := range possibleCards {
|
||||
if data.Commander == strings.Split(c.Name, " // ")[0] {
|
||||
record.Set("commander", c.ID)
|
||||
record.Set("color_identity", c.ColorIdentity)
|
||||
}
|
||||
}
|
||||
|
||||
cardInDeck := []DeckCard{}
|
||||
for _, v := range data.Cards {
|
||||
cardId := ""
|
||||
for _, c := range possibleCards {
|
||||
if v.Name == strings.Split(c.Name, " // ")[0] {
|
||||
cardId = c.ID
|
||||
}
|
||||
}
|
||||
if cardId == "" {
|
||||
log.Println(fmt.Sprintf("Card not found : %s",v.Name))
|
||||
}
|
||||
cardInDeck = append(cardInDeck, DeckCard{ID: cardId, Amount: v.Amount})
|
||||
}
|
||||
record.Set("cartes", cardInDeck)
|
||||
|
||||
err = app.pb.Save(record)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
re.BadRequestError("Problem with creating deck", err)
|
||||
}
|
||||
return re.JSON(http.StatusOK, map[string]string{"message": "deck created"})
|
||||
}).Bind(apis.RequireAuth())
|
||||
|
||||
// Proxy to svelte app
|
||||
se.Router.Any("/{path...}", func(re *core.RequestEvent) error {
|
||||
proxy.ServeHTTP(re.Response, re.Request)
|
||||
return nil
|
||||
})
|
||||
|
||||
return se.Next()
|
||||
})
|
||||
}
|
||||
|
||||
func filter(ss []CacheCarteSearch, test func(CacheCarteSearch) bool) (ret []CacheCarteSearch) {
|
||||
for _, s := range ss {
|
||||
if test(s) {
|
||||
ret = append(ret, s)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
252
backend/scryfall_api.go
Normal file
|
@ -0,0 +1,252 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ScryfallCard struct {
|
||||
Object string `json:"object"`
|
||||
ID string `json:"id"`
|
||||
OracleID string `json:"oracle_id"`
|
||||
MultiverseIds []int `json:"multiverse_ids"`
|
||||
MtgoID int `json:"mtgo_id"`
|
||||
MtgoFoilID int `json:"mtgo_foil_id"`
|
||||
TcgplayerID int `json:"tcgplayer_id"`
|
||||
CardmarketID int `json:"cardmarket_id"`
|
||||
Name string `json:"name"`
|
||||
Lang string `json:"lang"`
|
||||
ReleasedAt string `json:"released_at"`
|
||||
URI string `json:"uri"`
|
||||
ScryfallURI string `json:"scryfall_uri"`
|
||||
Layout string `json:"layout"`
|
||||
HighresImage bool `json:"highres_image"`
|
||||
ImageStatus string `json:"image_status"`
|
||||
ImageUris struct {
|
||||
Small string `json:"small"`
|
||||
Normal string `json:"normal"`
|
||||
Large string `json:"large"`
|
||||
Png string `json:"png"`
|
||||
ArtCrop string `json:"art_crop"`
|
||||
BorderCrop string `json:"border_crop"`
|
||||
} `json:"image_uris"`
|
||||
CardFaces []struct {
|
||||
Object string `json:"object"`
|
||||
Name string `json:"name"`
|
||||
ManaCost string `json:"mana_cost"`
|
||||
TypeLine string `json:"type_line"`
|
||||
OracleText string `json:"oracle_text"`
|
||||
Colors []string `json:"colors"`
|
||||
Power string `json:"power"`
|
||||
Toughness string `json:"toughness"`
|
||||
Artist string `json:"artist"`
|
||||
ArtistID string `json:"artist_id"`
|
||||
IllustrationID string `json:"illustration_id"`
|
||||
ImageUris struct {
|
||||
Small string `json:"small"`
|
||||
Normal string `json:"normal"`
|
||||
Large string `json:"large"`
|
||||
Png string `json:"png"`
|
||||
ArtCrop string `json:"art_crop"`
|
||||
BorderCrop string `json:"border_crop"`
|
||||
} `json:"image_uris"`
|
||||
ColorIndicator []string `json:"color_indicator,omitempty"`
|
||||
} `json:"card_faces"`
|
||||
ManaCost string `json:"mana_cost"`
|
||||
Cmc float32 `json:"cmc"`
|
||||
TypeLine string `json:"type_line"`
|
||||
OracleText string `json:"oracle_text"`
|
||||
Power string `json:"power"`
|
||||
Toughness string `json:"toughness"`
|
||||
Colors []string `json:"colors"`
|
||||
ColorIdentity []string `json:"color_identity"`
|
||||
Keywords []string `json:"keywords"`
|
||||
Legalities struct {
|
||||
Standard string `json:"standard"`
|
||||
Future string `json:"future"`
|
||||
Historic string `json:"historic"`
|
||||
Timeless string `json:"timeless"`
|
||||
Gladiator string `json:"gladiator"`
|
||||
Pioneer string `json:"pioneer"`
|
||||
Explorer string `json:"explorer"`
|
||||
Modern string `json:"modern"`
|
||||
Legacy string `json:"legacy"`
|
||||
Pauper string `json:"pauper"`
|
||||
Vintage string `json:"vintage"`
|
||||
Penny string `json:"penny"`
|
||||
Commander string `json:"commander"`
|
||||
Oathbreaker string `json:"oathbreaker"`
|
||||
Standardbrawl string `json:"standardbrawl"`
|
||||
Brawl string `json:"brawl"`
|
||||
Alchemy string `json:"alchemy"`
|
||||
Paupercommander string `json:"paupercommander"`
|
||||
Duel string `json:"duel"`
|
||||
Oldschool string `json:"oldschool"`
|
||||
Premodern string `json:"premodern"`
|
||||
Predh string `json:"predh"`
|
||||
} `json:"legalities"`
|
||||
Games []string `json:"games"`
|
||||
Reserved bool `json:"reserved"`
|
||||
GameChanger bool `json:"game_changer"`
|
||||
Foil bool `json:"foil"`
|
||||
Nonfoil bool `json:"nonfoil"`
|
||||
Finishes []string `json:"finishes"`
|
||||
Oversized bool `json:"oversized"`
|
||||
Promo bool `json:"promo"`
|
||||
Reprint bool `json:"reprint"`
|
||||
Variation bool `json:"variation"`
|
||||
SetID string `json:"set_id"`
|
||||
Set string `json:"set"`
|
||||
SetName string `json:"set_name"`
|
||||
SetType string `json:"set_type"`
|
||||
SetURI string `json:"set_uri"`
|
||||
SetSearchURI string `json:"set_search_uri"`
|
||||
ScryfallSetURI string `json:"scryfall_set_uri"`
|
||||
RulingsURI string `json:"rulings_uri"`
|
||||
PrintsSearchURI string `json:"prints_search_uri"`
|
||||
CollectorNumber string `json:"collector_number"`
|
||||
Digital bool `json:"digital"`
|
||||
Rarity string `json:"rarity"`
|
||||
CardBackID string `json:"card_back_id"`
|
||||
Artist string `json:"artist"`
|
||||
ArtistIds []string `json:"artist_ids"`
|
||||
IllustrationID string `json:"illustration_id"`
|
||||
BorderColor string `json:"border_color"`
|
||||
Frame string `json:"frame"`
|
||||
FullArt bool `json:"full_art"`
|
||||
Textless bool `json:"textless"`
|
||||
Booster bool `json:"booster"`
|
||||
StorySpotlight bool `json:"story_spotlight"`
|
||||
EdhrecRank int `json:"edhrec_rank"`
|
||||
PennyRank int `json:"penny_rank"`
|
||||
Prices struct {
|
||||
Usd string `json:"usd"`
|
||||
UsdFoil string `json:"usd_foil"`
|
||||
UsdEtched interface{} `json:"usd_etched"`
|
||||
Eur string `json:"eur"`
|
||||
EurFoil string `json:"eur_foil"`
|
||||
Tix string `json:"tix"`
|
||||
} `json:"prices"`
|
||||
RelatedUris struct {
|
||||
Gatherer string `json:"gatherer"`
|
||||
TcgplayerInfiniteArticles string `json:"tcgplayer_infinite_articles"`
|
||||
TcgplayerInfiniteDecks string `json:"tcgplayer_infinite_decks"`
|
||||
Edhrec string `json:"edhrec"`
|
||||
} `json:"related_uris"`
|
||||
PurchaseUris struct {
|
||||
Tcgplayer string `json:"tcgplayer"`
|
||||
Cardmarket string `json:"cardmarket"`
|
||||
Cardhoarder string `json:"cardhoarder"`
|
||||
} `json:"purchase_uris"`
|
||||
}
|
||||
|
||||
type ScryfallCardAPI struct {
|
||||
Object string `json:"object"`
|
||||
TotalCards int `json:"total_cards"`
|
||||
HasMore bool `json:"has_more"`
|
||||
NextPage string `json:"next_page"`
|
||||
Data []ScryfallCard `json:"data"`
|
||||
}
|
||||
|
||||
type ScryfallSet struct {
|
||||
Object string `json:"object"`
|
||||
ID string `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Uri string `json:"uri"`
|
||||
ScryfallUri string `json:"scryfall_uri"`
|
||||
SearchUri string `json:"search_uri"`
|
||||
ReleasedAt string `json:"released_at"`
|
||||
SetType string `json:"set_type"`
|
||||
CardCount int `json:"card_count"`
|
||||
ParentSetCode string `json:"parent_set_code"`
|
||||
Digital bool `json:"digital"`
|
||||
NonfoilOnly bool `json:"nonfoil_only"`
|
||||
FoilOnly bool `json:"foil_only"`
|
||||
IconSvgUri string `json:"icon_svg_uri"`
|
||||
}
|
||||
|
||||
type ScryfallSetAPI struct {
|
||||
Object string `json:"object"`
|
||||
HasMore bool `json:"has_more"`
|
||||
Data []ScryfallSet `json:"data"`
|
||||
}
|
||||
|
||||
func fetchApiCards(url string, cards []ScryfallCard) []ScryfallCard {
|
||||
reqClient := http.Client{
|
||||
Timeout: time.Second * 30, // Timeout after 2 seconds
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", "brawlset")
|
||||
|
||||
res, err := reqClient.Do(req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var scryfallData ScryfallCardAPI
|
||||
err = json.Unmarshal(body, &scryfallData)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cards = append(cards, scryfallData.Data...)
|
||||
if scryfallData.HasMore {
|
||||
return fetchApiCards(scryfallData.NextPage, cards)
|
||||
} else {
|
||||
return cards
|
||||
}
|
||||
}
|
||||
|
||||
func fetchApiSets() []ScryfallSet {
|
||||
url := "https://api.scryfall.com/sets"
|
||||
|
||||
reqClient := http.Client{
|
||||
Timeout: time.Second * 30, // Timeout after 2 seconds
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", "brawlset")
|
||||
|
||||
res, err := reqClient.Do(req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var scryFallData ScryfallSetAPI
|
||||
err = json.Unmarshal(body, &scryFallData)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return scryFallData.Data
|
||||
}
|
56
backend/types.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
type MtgSet struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
Code string `db:"code" json:"code"`
|
||||
Name string `db:"name" json:"name"`
|
||||
SanitizedName string `db:"sanitized_name" json:"sanitized_name"`
|
||||
ReleasedAt string `db:"release_at" json:"released_at"`
|
||||
IconUri string `db:"icon_uri" json:"icon_uri"`
|
||||
SetType string `db:"type" json:"type"`
|
||||
}
|
||||
|
||||
type Brawlset struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
SanitizedName string `db:"sanitized_name" json:"sanitized_name"`
|
||||
Sets types.JSONArray[string] `db:"sets" json:"sets"`
|
||||
}
|
||||
|
||||
type Carte struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
SanitizedName string `db:"sanitized_name" json:"sanitized_name"`
|
||||
Layout string `db:"layout" json:"layout"`
|
||||
SmallImage string `db:"small_image" json:"small_image"`
|
||||
SmallImageBack string `db:"small_image_back" json:"small_image_back"`
|
||||
NormalImage string `db:"normal_image" json:"normal_image"`
|
||||
NormalImageBack string `db:"normal_image_back" json:"normal_image_back"`
|
||||
CardType string `db:"type" json:"type"`
|
||||
ColorIdentity types.JSONArray[string] `db:"color_identity" json:"color_identity"`
|
||||
ReleasedAt string `db:"released_at" json:"released_at"`
|
||||
MtgSet string `db:"mtg_set" json:"mtg_set"`
|
||||
SetCode string `db:"set_code" json:"set_code"`
|
||||
Price string `db:"price" json:"price"`
|
||||
CardmarketUri string `db:"cardmarket_url" json:"cardmarket_url"`
|
||||
CanBeCommander bool `db:"can_be_commander" json:"can_be_commander"`
|
||||
}
|
||||
|
||||
type DeckCard struct {
|
||||
ID string `json:"id"`
|
||||
Amount int `json:"amount"`
|
||||
}
|
||||
|
||||
type Deck struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
ColorIdentity types.JSONArray[string] `db:"color_identity"`
|
||||
Owner string `db:"owner"`
|
||||
Commander string `db:"commander"`
|
||||
Brawlset string `db:"brawlset"`
|
||||
Cards types.JSONArray[DeckCard] `db:"cartes"`
|
||||
}
|
273
backend/utils.go
Normal file
|
@ -0,0 +1,273 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"unicode/utf8"
|
||||
"slices"
|
||||
"strings"
|
||||
"sort"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// https://stackoverflow.com/a/75996347
|
||||
var defaultDiacriticsRemovalMap = []struct {
|
||||
base string
|
||||
letters string
|
||||
}{
|
||||
{"A", "\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F"},
|
||||
{"AA", "\uA732"},
|
||||
{"AE", "\u00C6\u01FC\u01E2"},
|
||||
{"AO", "\uA734"},
|
||||
{"AU", "\uA736"},
|
||||
{"AV", "\uA738\uA73A"},
|
||||
{"AY", "\uA73C"},
|
||||
{"B", "\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181"},
|
||||
{"C", "\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E"},
|
||||
{"D", "\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0"},
|
||||
{"DZ", "\u01F1\u01C4"},
|
||||
{"Dz", "\u01F2\u01C5"},
|
||||
{"E", "\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E"},
|
||||
{"F", "\u0046\u24BB\uFF26\u1E1E\u0191\uA77B"},
|
||||
{"G", "\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E"},
|
||||
{"H", "\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"},
|
||||
{"I", "\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"},
|
||||
{"J", "\u004A\u24BF\uFF2A\u0134\u0248"},
|
||||
{"K", "\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"},
|
||||
{"L", "\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"},
|
||||
{"LJ", "\u01C7"},
|
||||
{"Lj", "\u01C8"},
|
||||
{"M", "\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C"},
|
||||
{"N", "\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4"},
|
||||
{"NJ", "\u01CA"},
|
||||
{"Nj", "\u01CB"},
|
||||
{"O", "\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C"},
|
||||
{"OI", "\u01A2"},
|
||||
{"OO", "\uA74E"},
|
||||
{"OU", "\u0222"},
|
||||
{"OE", "\u008C\u0152"},
|
||||
{"oe", "\u009C\u0153"},
|
||||
{"P", "\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"},
|
||||
{"Q", "\u0051\u24C6\uFF31\uA756\uA758\u024A"},
|
||||
{"R", "\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"},
|
||||
{"S", "\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"},
|
||||
{"T", "\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"},
|
||||
{"TZ", "\uA728"},
|
||||
{"U", "\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244"},
|
||||
{"V", "\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"},
|
||||
{"VY", "\uA760"},
|
||||
{"W", "\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"},
|
||||
{"X", "\u0058\u24CD\uFF38\u1E8A\u1E8C"},
|
||||
{"Y", "\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"},
|
||||
{"Z", "\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"},
|
||||
{"a", "\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250"},
|
||||
{"aa", "\uA733"},
|
||||
{"ae", "\u00E6\u01FD\u01E3"},
|
||||
{"ao", "\uA735"},
|
||||
{"au", "\uA737"},
|
||||
{"av", "\uA739\uA73B"},
|
||||
{"ay", "\uA73D"},
|
||||
{"b", "\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253"},
|
||||
{"c", "\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184"},
|
||||
{"d", "\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A"},
|
||||
{"dz", "\u01F3\u01C6"},
|
||||
{"e", "\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD"},
|
||||
{"f", "\u0066\u24D5\uFF46\u1E1F\u0192\uA77C"},
|
||||
{"g", "\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F"},
|
||||
{"h", "\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"},
|
||||
{"hv", "\u0195"},
|
||||
{"i", "\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"},
|
||||
{"j", "\u006A\u24D9\uFF4A\u0135\u01F0\u0249"},
|
||||
{"k", "\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"},
|
||||
{"l", "\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747"},
|
||||
{"lj", "\u01C9"},
|
||||
{"m", "\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"},
|
||||
{"n", "\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5"},
|
||||
{"nj", "\u01CC"},
|
||||
{"o", "\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275"},
|
||||
{"oi", "\u01A3"},
|
||||
{"ou", "\u0223"},
|
||||
{"oo", "\uA74F"},
|
||||
{"p", "\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755"},
|
||||
{"q", "\u0071\u24E0\uFF51\u024B\uA757\uA759"},
|
||||
{"r", "\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"},
|
||||
{"s", "\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B"},
|
||||
{"t", "\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"},
|
||||
{"tz", "\uA729"},
|
||||
{"u", "\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289"},
|
||||
{"v", "\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"},
|
||||
{"vy", "\uA761"},
|
||||
{"w", "\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"},
|
||||
{"x", "\u0078\u24E7\uFF58\u1E8B\u1E8D"},
|
||||
{"y", "\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"},
|
||||
{"z", "\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"},
|
||||
}
|
||||
|
||||
var diacriticsMap = map[rune]string{}
|
||||
|
||||
func removeDiacritics(str string) string {
|
||||
for _, mapping := range defaultDiacriticsRemovalMap {
|
||||
letters := mapping.letters
|
||||
for _, letter := range letters {
|
||||
diacriticsMap[letter] = mapping.base
|
||||
}
|
||||
}
|
||||
|
||||
reg := regexp.MustCompile("[^\u0000-\u007E]")
|
||||
return reg.ReplaceAllStringFunc(str, func(a string) string {
|
||||
r, _ := utf8.DecodeRuneInString(a)
|
||||
if replacement, ok := diacriticsMap[rune(r)]; ok {
|
||||
return replacement
|
||||
}
|
||||
return a
|
||||
})
|
||||
}
|
||||
|
||||
func SanitizeName(str string) string {
|
||||
re := regexp.MustCompile(`[^a-zA-Z0-9]+`)
|
||||
return strings.ToLower(re.ReplaceAllString(removeDiacritics(str), "-"))
|
||||
}
|
||||
|
||||
|
||||
// Function to create a SQL query to Upsert cards
|
||||
// Used in : crons.go
|
||||
func CreateBulkCardsUpsertQuery(data []ScryfallCard) string {
|
||||
totalCards := len(data)
|
||||
twoFacedLayouts := []string{"transform","modal_dfc","double_faced_token","reversible_card"}
|
||||
values := make([]string, totalCards)
|
||||
for i := 0; i < totalCards; i++ {
|
||||
id := data[i].ID
|
||||
name := data[i].Name
|
||||
sanitizedName := SanitizeName(data[i].Name) // Sanitized Name
|
||||
layout := data[i].Layout
|
||||
smallImage := ""
|
||||
smallImageBack := ""
|
||||
normalImage := ""
|
||||
normalImageBack := ""
|
||||
// Two Faced
|
||||
if slices.Contains(twoFacedLayouts,data[i].Layout) {
|
||||
smallImage = data[i].CardFaces[0].ImageUris.Small
|
||||
smallImageBack = data[i].CardFaces[0].ImageUris.Normal
|
||||
normalImage = data[i].CardFaces[1].ImageUris.Small
|
||||
normalImageBack = data[i].CardFaces[1].ImageUris.Normal
|
||||
} else {
|
||||
smallImage = data[i].ImageUris.Small
|
||||
normalImage = data[i].ImageUris.Normal
|
||||
}
|
||||
// Type
|
||||
cardTypeLine := strings.ToLower(data[i].TypeLine)
|
||||
cardType := ""
|
||||
if strings.Contains(cardTypeLine, "creature") {
|
||||
cardType = "creature"
|
||||
} else if strings.Contains(cardTypeLine, "planeswalker") {
|
||||
cardType = "planeswalker"
|
||||
} else if strings.Contains(cardTypeLine, "artifact") {
|
||||
cardType = "artifact"
|
||||
} else if strings.Contains(cardTypeLine, "instant") {
|
||||
cardType = "instant"
|
||||
} else if strings.Contains(cardTypeLine, "enchantment") {
|
||||
cardType = "enchantment"
|
||||
} else if strings.Contains(cardTypeLine, "sorcery") {
|
||||
cardType = "sorcery"
|
||||
} else if strings.Contains(cardTypeLine, "land") {
|
||||
cardType = "land"
|
||||
} else {
|
||||
cardType = "unknown"
|
||||
}
|
||||
colorIdentityBytes, err := json.Marshal(data[i].ColorIdentity)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
colorIdentity := string(colorIdentityBytes)
|
||||
releasedAt := data[i].ReleasedAt
|
||||
setId := data[i].SetID
|
||||
setCode := data[i].Set
|
||||
price := data[i].Prices.Eur
|
||||
cardmarketUri := data[i].PurchaseUris.Cardmarket
|
||||
canBeCommander := (strings.Contains(cardTypeLine, "legendary") && cardType == "creature") || cardType == "planeswalker"
|
||||
|
||||
values[i] = fmt.Sprintf(`("%v", "%s", "%v", "%v", "%v", "%v", "%v", "%v", "%v", '%v', "%v", "%v", "%v", "%v", "%v", "%v")`,id, name, sanitizedName, layout, smallImage, smallImageBack, normalImage, normalImageBack, cardType, colorIdentity, releasedAt, setId, setCode, price, cardmarketUri, canBeCommander)
|
||||
}
|
||||
|
||||
upsertQuery := fmt.Sprintf("INSERT INTO carte(id, name, sanitized_name, layout, small_image, small_image_back, normal_image, normal_image_back, type, color_identity, released_at, mtg_set, set_code, price, cardmarket_url, can_be_commander) VALUES %s ON CONFLICT (id) DO UPDATE SET price = excluded.price", strings.Join(values, ", "))
|
||||
|
||||
return upsertQuery
|
||||
}
|
||||
|
||||
// Function to create a SQL query to Insert sets
|
||||
// Used in : crons.go
|
||||
func CreateBulkSetsInsertQuery(data []ScryfallSet) string {
|
||||
totalSets := len(data)
|
||||
values := make([]string, totalSets)
|
||||
for i := 0; i < totalSets; i++ {
|
||||
values[i] = fmt.Sprintf(`("%v", "%v", "%v", "%v", "%v", "%v", "%v")`,data[i].ID, data[i].Name, SanitizeName(data[i].Name), data[i].Code, data[i].IconSvgUri, data[i].SetType, data[i].ReleasedAt)
|
||||
}
|
||||
|
||||
insertQuery := fmt.Sprintf("INSERT OR IGNORE INTO mtg_set(id, name, sanitized_name, code, icon_uri, type, released_at) VALUES %s", strings.Join(values, ", "))
|
||||
|
||||
return insertQuery
|
||||
}
|
||||
|
||||
// Timer used to time a function
|
||||
// Used in : cache.go
|
||||
func timer(name string) func() {
|
||||
start := time.Now()
|
||||
return func() {
|
||||
log.Printf("%s took %v\n", name, time.Since(start))
|
||||
}
|
||||
}
|
||||
|
||||
// Function to create all possible combinations of an array with a said length
|
||||
// Used in : cache.go
|
||||
// Source (in java) : https://hmkcode.com/calculate-find-all-possible-combinations-of-an-array-using-java/
|
||||
func CreateCombination(s []string, k int) []string {
|
||||
res := []string{}
|
||||
ignore := make([]int, len(s) - k)
|
||||
combination := make([]string, k)
|
||||
for w := 0; w < len(ignore); w++ {
|
||||
ignore[w] = len(s) - 1 - w
|
||||
}
|
||||
// Edit fonction above to make it ascending by default
|
||||
sort.Slice(ignore, func(i, j int) bool { return ignore[i] < ignore[j]})
|
||||
|
||||
i := 0
|
||||
r := 0
|
||||
g := 0
|
||||
|
||||
terminate := false
|
||||
for !terminate {
|
||||
for i < len(s) && r < k {
|
||||
if i != ignore[g] {
|
||||
combination[r] = s[i];
|
||||
r++
|
||||
i++
|
||||
} else {
|
||||
if g != len(ignore) - 1 {
|
||||
g++
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
i = 0
|
||||
r = 0
|
||||
g = 0
|
||||
|
||||
res = append(res, strings.Join(combination,""))
|
||||
terminate = true
|
||||
|
||||
for w := 0; w < len(ignore); w++ {
|
||||
if ignore[w] > w {
|
||||
ignore[w]--
|
||||
|
||||
if w > 0 {
|
||||
ignore[w-1] = ignore[w]-1
|
||||
}
|
||||
terminate = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
1
frontend/.npmrc
Normal file
|
@ -0,0 +1 @@
|
|||
engine-strict=true
|
290
frontend/bun.lock
Normal file
|
@ -0,0 +1,290 @@
|
|||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "brawlset-rewrite",
|
||||
"dependencies": {
|
||||
"pocketbase": "^0.25.2",
|
||||
"svelte-adapter-bun": "^0.5.2",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^4.0.0",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.2.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@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.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.2", "", { "os": "android", "cpu": "arm" }, "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.2", "", { "os": "android", "cpu": "x64" }, "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.2", "", { "os": "linux", "cpu": "arm" }, "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.2", "", { "os": "linux", "cpu": "x64" }, "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.2", "", { "os": "none", "cpu": "arm64" }, "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.2", "", { "os": "none", "cpu": "x64" }, "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.2", "", { "os": "win32", "cpu": "x64" }, "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.39.0", "", { "os": "android", "cpu": "arm" }, "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.39.0", "", { "os": "android", "cpu": "arm64" }, "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.39.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.39.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.39.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.39.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.39.0", "", { "os": "linux", "cpu": "arm" }, "sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.39.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA=="],
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw=="],
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.39.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.39.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.39.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.39.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.39.0", "", { "os": "win32", "cpu": "x64" }, "sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug=="],
|
||||
|
||||
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="],
|
||||
|
||||
"@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@4.0.0", "", { "dependencies": { "import-meta-resolve": "^4.1.0" }, "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-kmuYSQdD2AwThymQF0haQhM8rE5rhutQXG4LNbnbShwhMO4qQGnKaaTy+88DuNSuoQDi58+thpq8XpHc1+oEKQ=="],
|
||||
|
||||
"@sveltejs/kit": ["@sveltejs/kit@2.20.5", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-zT/97KvVUo19jEGZa972ls7KICjPCB53j54TVxnEFT5VEwL16G+YFqRVwJbfxh7AmS7/Ptr1rKF7Qt4FBMDNlw=="],
|
||||
|
||||
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.0.3", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.0", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.15", "vitefu": "^1.0.4" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw=="],
|
||||
|
||||
"@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="],
|
||||
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.3", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.29.2", "tailwindcss": "4.1.3" } }, "sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA=="],
|
||||
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.3", "@tailwindcss/oxide-darwin-arm64": "4.1.3", "@tailwindcss/oxide-darwin-x64": "4.1.3", "@tailwindcss/oxide-freebsd-x64": "4.1.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.3", "@tailwindcss/oxide-linux-arm64-musl": "4.1.3", "@tailwindcss/oxide-linux-x64-gnu": "4.1.3", "@tailwindcss/oxide-linux-x64-musl": "4.1.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.3", "@tailwindcss/oxide-win32-x64-msvc": "4.1.3" } }, "sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ=="],
|
||||
|
||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.3", "", { "os": "android", "cpu": "arm64" }, "sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg=="],
|
||||
|
||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.3", "", { "os": "linux", "cpu": "arm" }, "sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.3", "", { "os": "linux", "cpu": "x64" }, "sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.3", "", { "os": "win32", "cpu": "x64" }, "sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA=="],
|
||||
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.3", "", { "dependencies": { "@tailwindcss/node": "4.1.3", "@tailwindcss/oxide": "4.1.3", "tailwindcss": "4.1.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-lUI/QaDxLtlV52Lho6pu07CG9pSnRYLOPmKGIQjyHdTBagemc6HmgZxyjGAQ/5HMPrNeWBfTVIpQl0/jLXvWHQ=="],
|
||||
|
||||
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
|
||||
|
||||
"acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="],
|
||||
|
||||
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
|
||||
|
||||
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
|
||||
|
||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
|
||||
"cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="],
|
||||
|
||||
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
||||
|
||||
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
|
||||
|
||||
"devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="],
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.2", "@esbuild/android-arm": "0.25.2", "@esbuild/android-arm64": "0.25.2", "@esbuild/android-x64": "0.25.2", "@esbuild/darwin-arm64": "0.25.2", "@esbuild/darwin-x64": "0.25.2", "@esbuild/freebsd-arm64": "0.25.2", "@esbuild/freebsd-x64": "0.25.2", "@esbuild/linux-arm": "0.25.2", "@esbuild/linux-arm64": "0.25.2", "@esbuild/linux-ia32": "0.25.2", "@esbuild/linux-loong64": "0.25.2", "@esbuild/linux-mips64el": "0.25.2", "@esbuild/linux-ppc64": "0.25.2", "@esbuild/linux-riscv64": "0.25.2", "@esbuild/linux-s390x": "0.25.2", "@esbuild/linux-x64": "0.25.2", "@esbuild/netbsd-arm64": "0.25.2", "@esbuild/netbsd-x64": "0.25.2", "@esbuild/openbsd-arm64": "0.25.2", "@esbuild/openbsd-x64": "0.25.2", "@esbuild/sunos-x64": "0.25.2", "@esbuild/win32-arm64": "0.25.2", "@esbuild/win32-ia32": "0.25.2", "@esbuild/win32-x64": "0.25.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ=="],
|
||||
|
||||
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
|
||||
|
||||
"esrap": ["esrap@1.4.6", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw=="],
|
||||
|
||||
"fdir": ["fdir@6.4.3", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"globalyzer": ["globalyzer@0.1.0", "", {}, "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="],
|
||||
|
||||
"globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"import-meta-resolve": ["import-meta-resolve@4.1.0", "", {}, "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw=="],
|
||||
|
||||
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
|
||||
|
||||
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||
|
||||
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
||||
|
||||
"lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="],
|
||||
|
||||
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="],
|
||||
|
||||
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="],
|
||||
|
||||
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg=="],
|
||||
|
||||
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.2", "", { "os": "linux", "cpu": "arm" }, "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg=="],
|
||||
|
||||
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ=="],
|
||||
|
||||
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ=="],
|
||||
|
||||
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg=="],
|
||||
|
||||
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w=="],
|
||||
|
||||
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw=="],
|
||||
|
||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="],
|
||||
|
||||
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||
|
||||
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
|
||||
|
||||
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"pocketbase": ["pocketbase@0.25.2", "", {}, "sha512-ONZl1+qHJMnhR2uacBlBJ90lm7njtL/zy0606+1ROfK9hSL4LRBRc8r89rMcNRzPzRqCNyoFTh2Qg/lYXdEC1w=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
||||
"rollup": ["rollup@4.39.0", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.39.0", "@rollup/rollup-android-arm64": "4.39.0", "@rollup/rollup-darwin-arm64": "4.39.0", "@rollup/rollup-darwin-x64": "4.39.0", "@rollup/rollup-freebsd-arm64": "4.39.0", "@rollup/rollup-freebsd-x64": "4.39.0", "@rollup/rollup-linux-arm-gnueabihf": "4.39.0", "@rollup/rollup-linux-arm-musleabihf": "4.39.0", "@rollup/rollup-linux-arm64-gnu": "4.39.0", "@rollup/rollup-linux-arm64-musl": "4.39.0", "@rollup/rollup-linux-loongarch64-gnu": "4.39.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.39.0", "@rollup/rollup-linux-riscv64-gnu": "4.39.0", "@rollup/rollup-linux-riscv64-musl": "4.39.0", "@rollup/rollup-linux-s390x-gnu": "4.39.0", "@rollup/rollup-linux-x64-gnu": "4.39.0", "@rollup/rollup-linux-x64-musl": "4.39.0", "@rollup/rollup-win32-arm64-msvc": "4.39.0", "@rollup/rollup-win32-ia32-msvc": "4.39.0", "@rollup/rollup-win32-x64-msvc": "4.39.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g=="],
|
||||
|
||||
"sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
|
||||
|
||||
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
|
||||
|
||||
"sirv": ["sirv@3.0.1", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"svelte": ["svelte@5.25.10", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^1.4.6", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-tOUlvm3goAhmELYKWYX3SchYeqlVlIcUfKA4qIgd6Urm7qDw3KiZP/wJtoRv3ZeRUHPorM9f6+lOlbFxUN8QoA=="],
|
||||
|
||||
"svelte-adapter-bun": ["svelte-adapter-bun@0.5.2", "", { "dependencies": { "tiny-glob": "^0.2.9" } }, "sha512-xEtFgaal6UgrCwwkSIcapO9kopoFNUYCYqyKCikdqxX9bz2TDYnrWQZ7qBnkunMxi1HOIERUCvTcebYGiarZLA=="],
|
||||
|
||||
"svelte-check": ["svelte-check@4.1.5", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-Gb0T2IqBNe1tLB9EB1Qh+LOe+JB8wt2/rNBDGvkxQVvk8vNeAoG+vZgFB/3P5+zC7RWlyBlzm9dVjZFph/maIg=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="],
|
||||
|
||||
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
|
||||
|
||||
"tiny-glob": ["tiny-glob@0.2.9", "", { "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg=="],
|
||||
|
||||
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"vite": ["vite@6.2.6", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "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", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw=="],
|
||||
|
||||
"vitefu": ["vitefu@1.0.6", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA=="],
|
||||
|
||||
"zimmerframe": ["zimmerframe@1.1.2", "", {}, "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w=="],
|
||||
}
|
||||
}
|
29
frontend/package.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "brawlset-rewrite",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^4.0.0",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.2.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"pocketbase": "^0.25.2",
|
||||
"svelte-adapter-bun": "^0.5.2"
|
||||
}
|
||||
}
|
34
frontend/src/app.css
Normal file
|
@ -0,0 +1,34 @@
|
|||
@import 'tailwindcss';
|
||||
|
||||
@font-face {
|
||||
font-family: "Beleren";
|
||||
src: url("/fonts/Beleren2016-Bold.woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter-Tight-Normal";
|
||||
src: url("/fonts/inter-tight-latin-400-normal.ttf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter-Tight-Italic";
|
||||
src: url("/fonts/inter-tight-latin-400-italic.ttf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter-Tight-Bold";
|
||||
src: url("/fonts/inter-tight-latin-800-normal.ttf");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter-Tight-Bold-Italic";
|
||||
src: url("/fonts/inter-tight-latin-800-italic.ttf");
|
||||
}
|
||||
|
||||
.font-beleren {
|
||||
font-family: 'Beleren';
|
||||
}
|
||||
|
||||
.font-inter-tight {
|
||||
font-family: 'Inter-Tight-Normal';
|
||||
}
|
13
frontend/src/app.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
12
frontend/src/app.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
17
frontend/src/lib/components/Card.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
let { name = "", url = "#", sanitizedName = "", smallImage = "", normalImage="", price = 0, cardmarketUri = "", numberOfDecks = 0, numberOfPossibleDecks = undefined, synergy = undefined } = $props()
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full gap-0">
|
||||
<a class="w-full" href={url}><img src={normalImage} alt={"Scan de carte pour " + name} class="w-full rounded-md aspect-[488/680]" loading="lazy"/></a>
|
||||
<a href={cardmarketUri} target="_blank" class="text-xs w-full text-center mt-2">{price}€</a>
|
||||
<span class="w-full text-center text-xs">{name}</span>
|
||||
{#if numberOfPossibleDecks == undefined}
|
||||
<span class="w-full text-center">{numberOfDecks} Decks</span>
|
||||
{:else}
|
||||
<span class="w-full text-center">{numberOfDecks} Decks sur {numberOfPossibleDecks} ({numberOfPossibleDecks != 0 ? Math.round(100 * (numberOfDecks / numberOfPossibleDecks)) : 0}%)</span>
|
||||
{/if}
|
||||
{#if synergy != undefined}
|
||||
<span class="w-full text-center">Synergy {synergy > 0 ? "+" + Math.round(100*synergy).toString() : Math.round(100*synergy).toString()}%</span>
|
||||
{/if}
|
||||
</div>
|
7
frontend/src/lib/components/CardGrid.svelte
Normal file
|
@ -0,0 +1,7 @@
|
|||
<script>
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<div class="grid grid-cols-1 pl-4 pr-4 md:grid-cols-3 lg:grid-cols-5 gap-4 w-full max-w-6xl">
|
||||
{@render children()}
|
||||
</div>
|
38
frontend/src/lib/components/CardSearch.svelte
Normal file
|
@ -0,0 +1,38 @@
|
|||
<script>
|
||||
import Input from "./base/Input.svelte";
|
||||
|
||||
let { dialog = $bindable() } = $props()
|
||||
|
||||
let searchQuery = $state("")
|
||||
let searchResult = $state([])
|
||||
|
||||
async function search() {
|
||||
searchResult = []
|
||||
if(searchQuery.length > 3) {
|
||||
fetch("/api/search?q=" + searchQuery)
|
||||
.then( response => response.json() )
|
||||
.then( data => { searchResult = data; console.log(data) } )
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<dialog class="max-w-96 w-full backdrop:backdrop-blur-sm backdrop:bg-black/30 p-4 rounded-md"
|
||||
style="margin: auto; width: calc(100% - 20px);"
|
||||
bind:this={dialog}
|
||||
onclick={(e) => { if (e.target === dialog) dialog.close(); }}>
|
||||
<div>
|
||||
<Input type="text" placeholder="Rechercher des cartes" bind:value={searchQuery} oninput={search} focus/>
|
||||
<div class="mt-4 flex flex-col gap-2 h-64 overflow-y-scroll items-center">
|
||||
{#if searchResult.length == 0}
|
||||
<span class="mt-8 text-xs">Pas de résultat...</span>
|
||||
{:else}
|
||||
{#each searchResult as result}
|
||||
<a class="flex flex-col gap-0 w-full" href={result.Url}>
|
||||
<span>{result.Name}</span>
|
||||
<span class="text-xs">{result.SetName}</span>
|
||||
</a>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
3
frontend/src/lib/components/Footer.svelte
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div class="w-full flex flex-row justify-center text-xs text-center p-4">
|
||||
<span>Brawlset is unofficial Fan Content permitted under the Fan Content Policy. Not approved/endorsed by Wizards. Portions of the materials used are property of Wizards of the Coast. ©Wizards of the Coast LLC.</span>
|
||||
</div>
|
226
frontend/src/lib/components/Navbar.svelte
Normal file
|
@ -0,0 +1,226 @@
|
|||
<script>
|
||||
import { getContext, onMount } from "svelte";
|
||||
import Blue from "./icons/Blue.svelte";
|
||||
import White from "./icons/White.svelte";
|
||||
import Black from "./icons/Black.svelte";
|
||||
import Colorless from "./icons/Colorless.svelte";
|
||||
import Red from "./icons/Red.svelte";
|
||||
import Green from "./icons/Green.svelte";
|
||||
import IconBase from "./icons/IconBase.svelte";
|
||||
import CardSearch from "./CardSearch.svelte";
|
||||
import SearchIcon from "./icons/SearchIcon.svelte";
|
||||
import DeckIcon from "./icons/DeckIcon.svelte";
|
||||
import MenuIcon from "./icons/MenuIcon.svelte";
|
||||
|
||||
let dialog
|
||||
|
||||
let username = $state("")
|
||||
|
||||
let brawlsets = $state([])
|
||||
let isLoggedIn = $state(false)
|
||||
|
||||
onMount( async () => {
|
||||
const storageData = window.localStorage.getItem("pocketbase_auth")
|
||||
if (storageData != null) {
|
||||
const jsonData = JSON.parse(storageData)
|
||||
username = jsonData.record.name
|
||||
isLoggedIn = true
|
||||
}
|
||||
|
||||
fetch("/json/misc/brawlsets")
|
||||
.then( response => response.json() )
|
||||
.then( data => { brawlsets = data; console.log(data) } )
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div class="font-inter-tight flex flex-row justify-between w-screen p-4 h-16">
|
||||
<a class="flex flex-row gap-2 items-center" href="/">
|
||||
<img alt="brawlset website logo" src="/assets/logo.png" class="h-8" />
|
||||
<span class="font-beleren text-3xl mt-2 bg-gradient-to-r from-black to-orange-500 bg-clip-text text-transparent">BrawlSet</span>
|
||||
</a>
|
||||
<div class="hidden flex-row gap-4 items-center md:flex">
|
||||
<details class="dropdown w-0 md:w-fit">
|
||||
<summary role="button">
|
||||
<a class="cursor-pointer text-stone-500">Commandants</a>
|
||||
</summary>
|
||||
<ul>
|
||||
<li>Top commandants</li>
|
||||
<li>
|
||||
<div>Mono</div>
|
||||
<ul>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><White/><span>Blanc</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><Blue/><span>Bleu</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><Black/><span>Noir</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><Red/><span>Rouge</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><Green/><span>Vert</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><Colorless/><span>Incolor</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<div>2 couleurs</div>
|
||||
<ul>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><White/><Blue/></div><span>Azorius</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Blue/><Black/></div><span>Dimir</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Black/><Red/></div><span>Rakdos</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Red/><Green/></div><span>Gruul</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Green/><White/></div><span>Selesnya</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><White/><Black/></div><span>Orzhov</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Blue/><Red/></div><span>Izzet</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Black/><Green/></div><span>Golgari</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Red/><White/></div><span>Boros</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Green/><Blue/></div><span>Simic</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<div>3 couleurs</div>
|
||||
<ul>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><White/><Blue/><Black/></div><span>Esper</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Blue/><Black/><Red/></div><span>Grixis</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Black/><Red/><Green/></div><span>Jund</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Red/><Green/><White/></div><span>Naya</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Green/><White/><Blue/></div><span>Bant</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><White/><Black/><Green/></div><span>Abzan</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Blue/><Red/><White/></div><span>Jeskai</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Black/><Green/><Blue/></div><span>Sultai</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Red/><White/><Black/></div><span>Mardu</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Green/><Blue/><Red/></div><span>Temur</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<div>4+ couleurs</div>
|
||||
<ul>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><White/><Blue/><Black/><Red/></div><span>Yore-Tiller</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Blue/><Black/><Red/><Green/></div><span>Glint-Eye</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Black/><Red/><Green/><White/></div><span>Dune-Brood</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Red/><Green/><White/><Blue/></div><span>Ink-Treader</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><Green/><White/><Blue/><Black/></div><span>Witch-Maw</span></a></li>
|
||||
<li><a class="flex flex-row items-center gap-2" href="#"><div class="flex flex-row gap-0"><White/><Blue/><Black/><Red/><Green/></div><span>5 couleurs</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
<details class="dropdown">
|
||||
<summary role="button">
|
||||
<a class="cursor-pointer text-stone-500">BSets</a>
|
||||
</summary>
|
||||
<ul>
|
||||
{#each brawlsets.slice(0,5) as brawlset}
|
||||
<li>
|
||||
<a class="flex flex-row gap-2 items-center" href={"/bset/" + brawlset.SanitizedName}>
|
||||
<div class="flex flex-row gap-1">
|
||||
{#each brawlset.IconsSvgUri as icon}
|
||||
<IconBase src={icon} alt="brawlset icon"/>
|
||||
{/each}
|
||||
</div>
|
||||
{brawlset.Name}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
<li><a href="/bset/all">Plus de BSets...</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<a class="cursor-pointer text-stone-500" href="/regles">Règles</a>
|
||||
<a class="cursor-pointer text-stone-500" href="/faq">F.A.Q</a>
|
||||
</div>
|
||||
<div class="flex flex-row gap-4 items-center text-stone-500">
|
||||
<button class="flex flex-row items-center" onclick={() => dialog.showModal()}>
|
||||
<SearchIcon class="visible w-fit md:invisible md:w-0" />
|
||||
<span class="invisible w-0 md:w-fit md:visible">Rechercher</span>
|
||||
</button>
|
||||
{#if isLoggedIn}
|
||||
<a class="cursor-pointer flex flex-row items-center" href="/decks">
|
||||
<DeckIcon class="visible w-fit md:invisible md:w-0" />
|
||||
<span class="invisible w-0 md:w-fit md:visible">Decks</span>
|
||||
</a>
|
||||
<a class="cursor-pointer hidden md:inline" href="/profil">
|
||||
<span class="invisible w-0 md:w-fit md:visible">{username}</span>
|
||||
</a>
|
||||
{:else}
|
||||
<a class="cursor-pointer" href="/connexion">Connexion</a>
|
||||
<a class="cursor-pointer" href="#">Inscription</a>
|
||||
{/if}
|
||||
<details class="dropdown inline md:hidden">
|
||||
<summary role="button">
|
||||
<a class="cursor-pointer"><MenuIcon /></a>
|
||||
</summary>
|
||||
<ul>
|
||||
{#each brawlsets.slice(0,5) as brawlset}
|
||||
<li>
|
||||
<a class="flex flex-row gap-2 items-center" href={"/bset/" + brawlset.SanitizedName}>
|
||||
<div class="flex flex-row gap-1">
|
||||
{#each brawlset.IconsSvgUri as icon}
|
||||
<IconBase src={icon} alt="brawlset icon"/>
|
||||
{/each}
|
||||
</div>
|
||||
{brawlset.Name}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
<li><a href="/bset/all">Plus de BSets...</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CardSearch bind:dialog={dialog} />
|
||||
|
||||
<style>
|
||||
/* Close the dropdown with outside clicks */
|
||||
.dropdown > summary::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dropdown[open] > summary::before {
|
||||
content: ' ';
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dropdown summary {
|
||||
list-style: none;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.dropdown ul {
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
z-index: 2;
|
||||
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #D3D3D3;
|
||||
box-shadow: 0px 4px 5px #D3D3D3;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.dropdown li {
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown ul ul {
|
||||
display: none;
|
||||
left: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.dropdown li:hover {
|
||||
background-color: hsl(240 4.8% 95.9%);
|
||||
}
|
||||
|
||||
.dropdown li:hover > ul {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
8
frontend/src/lib/components/base/Button.svelte
Normal file
|
@ -0,0 +1,8 @@
|
|||
<script>
|
||||
|
||||
let { children, ...restProps } = $props()
|
||||
</script>
|
||||
|
||||
<button class="bg-orange-500 cursor-pointer text-white rounded-md p-2" {...restProps}>
|
||||
{@render children()}
|
||||
</button>
|
5
frontend/src/lib/components/base/Input.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
let { type, placeholder = "", name = "", value = $bindable(), ...restProps} = $props()
|
||||
</script>
|
||||
|
||||
<input type={type} placeholder={placeholder} name={name} class="flex h-auto min-h-9 w-full border-l-orange-500 border-l-4 bg-transparent px-3 py-1 text-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50" bind:value {...restProps} />
|
5
frontend/src/lib/components/icons/Black.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import IconBase from "./IconBase.svelte";
|
||||
</script>
|
||||
|
||||
<IconBase src="https://svgs.scryfall.io/card-symbols/B.svg" alt="Black mana icon"/>
|
5
frontend/src/lib/components/icons/Blue.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import IconBase from "./IconBase.svelte";
|
||||
</script>
|
||||
|
||||
<IconBase src="https://svgs.scryfall.io/card-symbols/U.svg" alt="Blue mana icon"/>
|
5
frontend/src/lib/components/icons/Colorless.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import IconBase from "./IconBase.svelte";
|
||||
</script>
|
||||
|
||||
<IconBase src="https://svgs.scryfall.io/card-symbols/C.svg" alt="Colorless mana icon"/>
|
6
frontend/src/lib/components/icons/DeckIcon.svelte
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" {...$$props}>
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
<path d="M3 9a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2M3 11h3c.8 0 1.6.3 2.1.9l1.1.9c1.6 1.6 4.1 1.6 5.7 0l1.1-.9c.5-.5 1.3-.9 2.1-.9H21" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 399 B |
5
frontend/src/lib/components/icons/Green.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import IconBase from "./IconBase.svelte";
|
||||
</script>
|
||||
|
||||
<IconBase src="https://svgs.scryfall.io/card-symbols/G.svg" alt="Green mana icon"/>
|
5
frontend/src/lib/components/icons/IconBase.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
let { src, alt } = $props();
|
||||
</script>
|
||||
|
||||
<img src={src} alt={alt} loading="lazy" class="min-h-4 min-w-4 size-4" />
|
3
frontend/src/lib/components/icons/MenuIcon.svelte
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" {...$$props}>
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 12h16M4 6h16M4 18h16" />
|
||||
</svg>
|
After Width: | Height: | Size: 240 B |
5
frontend/src/lib/components/icons/Red.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import IconBase from "./IconBase.svelte";
|
||||
</script>
|
||||
|
||||
<IconBase src="https://svgs.scryfall.io/card-symbols/R.svg" alt="Red mana icon"/>
|
6
frontend/src/lib/components/icons/SearchIcon.svelte
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" {...$$props}>
|
||||
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<path d="m21 21l-4.3-4.3" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 279 B |
5
frontend/src/lib/components/icons/White.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import IconBase from "./IconBase.svelte";
|
||||
</script>
|
||||
|
||||
<IconBase src="https://svgs.scryfall.io/card-symbols/W.svg" alt="White mana icon"/>
|
1
frontend/src/lib/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
// place files you want to import through the `$lib` alias in this folder.
|
15
frontend/src/routes/+layout.svelte
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import Navbar from '$lib/components/Navbar.svelte';
|
||||
import Footer from '$lib/components/Footer.svelte';
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<div class="w-screen min-h-screen flex flex-col gap-0">
|
||||
<Navbar />
|
||||
<div class="mt-8 font-inter-tight grow">
|
||||
{@render children()}
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
6
frontend/src/routes/+page.svelte
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div class="flex flex-col w-full items-center mt-8 md:mt-32 p-4 text-center">
|
||||
<p class="mb-12 text-3xl text-orange-500">CE SITE EST EN COURS DE DEVELOPPEMENT - NE SAUVEGARDEZ PAS VOS DONNÉES UNIQUEMENT SUR BRAWLSET</p>
|
||||
<h1 class="text-8xl font-beleren">The BrawlSet</h1>
|
||||
<p class="text-center text-stone-500 mt-12">Un système de règles MTG basé sur le mode de jeu commander et inventé à Rennes, pays de la galette saucisse.<br />
|
||||
Pour plus d'informations allez voir les <a href="/rules" class="text-orange-500">règles</a> ou la <a href="/faq" class="text-orange-500">FAQ</a>.</p>
|
||||
</div>
|
95
frontend/src/routes/bset/[slug]/+page.svelte
Normal file
|
@ -0,0 +1,95 @@
|
|||
<script lang="ts">
|
||||
import Card from '$lib/components/Card.svelte';
|
||||
import CardGrid from '$lib/components/CardGrid.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import type { PageProps } from './$types';
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
let commander = $state([])
|
||||
let creature = $state([])
|
||||
let instant = $state([])
|
||||
let planeswalker = $state([])
|
||||
let artifact = $state([])
|
||||
let sorcery = $state([])
|
||||
let enchantment = $state([])
|
||||
let land = $state([])
|
||||
let slug = $derived(data.slug)
|
||||
let test = $state("")
|
||||
|
||||
$effect(() => {
|
||||
commander = creature = instant = planeswalker = artifact = sorcery = enchantment = []
|
||||
|
||||
fetch("/json/brawlset/"+slug)
|
||||
.then( response => response.json() )
|
||||
.then( data => {
|
||||
commander = data.Cards.commander
|
||||
creature = data.Cards.creature
|
||||
sorcery = data.Cards.sorcery
|
||||
instant = data.Cards.instant
|
||||
land = data.Cards.land
|
||||
enchantment = data.Cards.enchantment
|
||||
artifact = data.Cards.artifact
|
||||
planeswalker = data.Cards.planeswalker
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full items-center">
|
||||
<h1>{slug}</h1>
|
||||
|
||||
<h2>Commandants</h2>
|
||||
<CardGrid>
|
||||
{#each commander as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks}/>
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Planeswalker</h2>
|
||||
<CardGrid>
|
||||
{#each planeswalker as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Creature</h2>
|
||||
<CardGrid>
|
||||
{#each creature as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Rituels</h2>
|
||||
<CardGrid>
|
||||
{#each sorcery as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Artefacts</h2>
|
||||
<CardGrid>
|
||||
{#each artifact as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Éphémères</h2>
|
||||
<CardGrid>
|
||||
{#each instant as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Enchantements</h2>
|
||||
<CardGrid>
|
||||
{#each enchantment as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Terrains</h2>
|
||||
<CardGrid>
|
||||
{#each land as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
</div>
|
6
frontend/src/routes/bset/[slug]/+page.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = ({ params }) => {
|
||||
console.log("test")
|
||||
return {slug: params.slug, test: "yeeeeheeee"}
|
||||
};
|
29
frontend/src/routes/bset/all/+page.svelte
Normal file
|
@ -0,0 +1,29 @@
|
|||
<script>
|
||||
import Input from "$lib/components/base/Input.svelte";
|
||||
import IconBase from "$lib/components/icons/IconBase.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let brawlsets = $state([])
|
||||
onMount(async () => {
|
||||
fetch("/json/misc/brawlsets")
|
||||
.then( response => response.json() )
|
||||
.then( data => { brawlsets = data; console.log(data) } )
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<div class="m-auto mt-16 max-w-4xl flex flex-col gap-4">
|
||||
<Input type="text" placeholder="Rechercher des brawlsets" />
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
{#each brawlsets as brawlset}
|
||||
<a class="flex flex-row gap-2 items-center" href={"/bset/" + brawlset.SanitizedName}>
|
||||
<div class="flex flex-row items-center">
|
||||
{#each brawlset.IconsSvgUri as icon}
|
||||
<IconBase src={icon} alt={"Set icon for " + brawlset.Name} />
|
||||
{/each}
|
||||
</div>
|
||||
<span>{brawlset.Name}</span>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
90
frontend/src/routes/commander/[slug]/+page.svelte
Normal file
|
@ -0,0 +1,90 @@
|
|||
<script lang="ts">
|
||||
import Card from '$lib/components/Card.svelte';
|
||||
import CardGrid from '$lib/components/CardGrid.svelte';
|
||||
import type { PageProps } from './$types';
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
let creature = $state([])
|
||||
let instant = $state([])
|
||||
let planeswalker = $state([])
|
||||
let artifact = $state([])
|
||||
let sorcery = $state([])
|
||||
let enchantment = $state([])
|
||||
let land = $state([])
|
||||
let slug = $derived(data.slug)
|
||||
|
||||
let mainCardData = $state({})
|
||||
|
||||
$effect(() => {
|
||||
creature = instant = planeswalker = artifact = sorcery = enchantment = []
|
||||
console.log(data)
|
||||
|
||||
fetch("/json/commander/"+slug)
|
||||
.then( response => response.json() )
|
||||
.then( data => {
|
||||
creature = data.Cards.creature
|
||||
sorcery = data.Cards.sorcery
|
||||
instant = data.Cards.instant
|
||||
land = data.Cards.land
|
||||
enchantment = data.Cards.enchantment
|
||||
artifact = data.Cards.artifact
|
||||
planeswalker = data.Cards.planeswalker
|
||||
mainCardData = data.MainCard
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full items-center">
|
||||
<div class="w-full max-w-64">
|
||||
<Card class="" normalImage={mainCardData.NormalImage} name={mainCardData.Name} price={mainCardData.Price} mainCardDatamarketUri={mainCardData.CardmarketUri} numberOfDecks={mainCardData.NumberOfDecks} />
|
||||
</div>
|
||||
|
||||
<h2>Planeswalker</h2>
|
||||
<CardGrid>
|
||||
{#each planeswalker as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} synergy={card.Synergy} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Creature</h2>
|
||||
<CardGrid>
|
||||
{#each creature as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} synergy={card.Synergy} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Rituels</h2>
|
||||
<CardGrid>
|
||||
{#each sorcery as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} synergy={card.Synergy} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Artefacts</h2>
|
||||
<CardGrid>
|
||||
{#each artifact as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} synergy={card.Synergy} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Éphémères</h2>
|
||||
<CardGrid>
|
||||
{#each instant as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} synergy={card.Synergy} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Enchantements</h2>
|
||||
<CardGrid>
|
||||
{#each enchantment as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} synergy={card.Synergy} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
|
||||
<h2>Terrains</h2>
|
||||
<CardGrid>
|
||||
{#each land as card}
|
||||
<Card normalImage={card.NormalImage} url={card.Url} name={card.Name} price={card.Price} cardmarketUri={card.CardmarketUri} numberOfDecks={card.NumberOfDecks} numberOfPossibleDecks={card.NumberOfPossibleDecks} synergy={card.Synergy} />
|
||||
{/each}
|
||||
</CardGrid>
|
||||
</div>
|
6
frontend/src/routes/commander/[slug]/+page.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = ({ params }) => {
|
||||
console.log("test")
|
||||
return {slug: params.slug, test: "yeeeeheeee"}
|
||||
};
|
34
frontend/src/routes/connexion/+page.svelte
Normal file
|
@ -0,0 +1,34 @@
|
|||
<script>
|
||||
import PocketBase from 'pocketbase';
|
||||
import Input from '$lib/components/base/Input.svelte';
|
||||
import { setContext } from 'svelte';
|
||||
|
||||
const pb = new PocketBase('http://localhost:8090');
|
||||
|
||||
async function login(form) {
|
||||
const formData = new FormData(form.target)
|
||||
const data = {};
|
||||
for (let field of formData) {
|
||||
const [key, value] = field;
|
||||
data[key] = value;
|
||||
}
|
||||
console.log(data)
|
||||
try {
|
||||
const authData = await pb.collection('users').authWithPassword(data.email, data.password);
|
||||
console.log(authData)
|
||||
console.log(pb.authStore.token);
|
||||
window.location.href = "/"
|
||||
} catch (err) {
|
||||
console.log("Failed to log");
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-center mt-32 h-full">
|
||||
<form class="flex flex-col gap-4 w-lg" on:submit|preventDefault={(e) => login(e)}>
|
||||
<Input name="email" placeholder="email" type="email" />
|
||||
<Input name="password" placeholder="password" type="password" />
|
||||
<button class="border rounded p-2 bg-gray-800 text-white hover:bg-gray-700">Connexion</button>
|
||||
</form>
|
||||
</div>
|
104
frontend/src/routes/decks/+page.svelte
Normal file
|
@ -0,0 +1,104 @@
|
|||
<script>
|
||||
import Button from "$lib/components/base/Button.svelte";
|
||||
import Input from "$lib/components/base/Input.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let brawlsets = $state([])
|
||||
let deckImporter = $state("")
|
||||
let selectedBset = $state("")
|
||||
let deckName = $state("")
|
||||
let deckUrl = $state("")
|
||||
let commander = $state("")
|
||||
let token = $state("")
|
||||
|
||||
onMount( async () => {
|
||||
const storageData = window.localStorage.getItem("pocketbase_auth")
|
||||
if (storageData != null) {
|
||||
const jsonData = JSON.parse(storageData)
|
||||
token = jsonData.token
|
||||
}
|
||||
|
||||
fetch("/json/misc/brawlsets")
|
||||
.then( response => response.json() )
|
||||
.then( data => {
|
||||
let sortedData = data
|
||||
sortedData.sort((a,b) => a.Name.localeCompare(b.Name))
|
||||
brawlsets = sortedData
|
||||
})
|
||||
})
|
||||
|
||||
function setCommander(txt) {
|
||||
let lines = txt.split("\n")
|
||||
commander = lines[lines.length - 1].slice(1)
|
||||
}
|
||||
|
||||
function getDataFromLine(line){
|
||||
if(line != "") {
|
||||
const data = line.split(" ")
|
||||
const amount = parseInt(data[0])
|
||||
const name = data.slice(1).join(" ").split(" // ")[0].split("/")[0]
|
||||
return {"name":name, "amount":amount}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function importDeck(){
|
||||
const deckText = deckImporter
|
||||
let lines = deckText.split("\n")
|
||||
lines = lines.filter((line) => line.match(/[0-9]+\s[\w]+/) != undefined)
|
||||
const dataToSend = { name: deckName, url: deckUrl, selected_bset: selectedBset,commander_name: getDataFromLine(commander).name, cards: [] }
|
||||
lines.slice(0, lines.length - 1).forEach((line) => {
|
||||
const data = getDataFromLine(line)
|
||||
if(data != null) {
|
||||
dataToSend.cards.push(data)
|
||||
}
|
||||
});
|
||||
|
||||
console.log(dataToSend)
|
||||
|
||||
fetch('/api/deck/create', {
|
||||
method: "POST",
|
||||
headers: {Authorization: token, "Content-Type": "application/json"},
|
||||
body: JSON.stringify(dataToSend)
|
||||
}).then((res) => {
|
||||
if(res.status == 200) {
|
||||
res.json().then((apiData) => {
|
||||
deckImporter = ""
|
||||
selectedBset = ""
|
||||
deckName = ""
|
||||
deckUrl = ""
|
||||
commander = ""
|
||||
console.log(apiData)
|
||||
})
|
||||
} else if (res.status == 401) {
|
||||
res.json().then((apiData) => {
|
||||
console.log(apiData)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full items-center p-4">
|
||||
<div class="flex flex-col-reverse md:flex-row max-w-4xl w-full gap-4">
|
||||
<div class="flex flex-col w-full">
|
||||
<textarea placeholder="Deck list dans le format MTGO" class="h-60" bind:value={deckImporter} oninput={(e) => setCommander(e.target.value)}></textarea>
|
||||
<span>Commandant : {commander}</span>
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-4">
|
||||
<Input type="text" placeholder="Nom du deck" bind:value={deckName} />
|
||||
<Input type="text" placeholder="Url du deck (facultatif)" bind:value={deckUrl} />
|
||||
<select bind:value={selectedBset}>
|
||||
<option value="0">Selectionnez un Brawlset...</option>
|
||||
{#each brawlsets as brawlset}
|
||||
<option value={brawlset.SanitizedName}>
|
||||
{brawlset.Name}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
<Button onclick={importDeck}>Importer</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
4
frontend/src/routes/faq/+page.svelte
Normal file
|
@ -0,0 +1,4 @@
|
|||
<div class="flex flex-col mt-16 w-full items-center">
|
||||
<h1>F.A.Q</h1>
|
||||
<p>Coming soon...</p>
|
||||
</div>
|
13
frontend/src/routes/profil/+page.svelte
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
import Button from "$lib/components/base/Button.svelte";
|
||||
|
||||
function removeAuth() {
|
||||
window.localStorage.removeItem("pocketbase_auth")
|
||||
window.location.href = "/"
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-center mt-16">
|
||||
<Button onclick={removeAuth}>Deconnexion</Button>
|
||||
</div>
|
31
frontend/src/routes/regles/+page.svelte
Normal file
|
@ -0,0 +1,31 @@
|
|||
<div class="flex flex-col items-center">
|
||||
<div class="flex flex-col items-center w-full">
|
||||
<h1 class="text-3xl">BrawlSet Canon Règles Officielles</h1>
|
||||
<h2>BrawlSet Committee</h2>
|
||||
<h2>17 Octobre 2022</h2>
|
||||
</div>
|
||||
<div class="flex flex-col max-w-5xl gap-4 mt-8 mb-32">
|
||||
<h2 class="font-bold">903.BS. Le mode de jeu BrawlSet</h2>
|
||||
<ul class="flex flex-col gap-4">
|
||||
<li><strong>903.BS.1</strong> Le BrawlSet est une variante du Commander. Cette variante utilise les règles classiques du Commander avec les modifications suivantes.</li>
|
||||
<li><strong>903.BS.2</strong> La Règle d’Or du format est d’utiliser des cartes provenant du même set. Pour des raisons de niveau des cartes et/ou d’histoire, certains sets sont regroupés en « BSet »</li>
|
||||
<li><strong>903.BS.3</strong> La liste des BSets est disponible dans le document List_BSet_FR.pdf</li>
|
||||
<li><strong>903.BS.4</strong> Une carte fait partie d’un BSet si elle a été imprimée au moins une fois avec le symbole d’édition d’un des sets qui composent le BSet. La liste complète des symboles d’édition peut être trouvée dans la section Card Set Archive du site Magic de Wizard of the Coast (<a href="https://magic.wizards.com/en/products/card-set-archive">lien</a>)</li>
|
||||
<li>Exemple : <em>Cela prend en compte les cartes Timeshifted pour Time Spiral, les cartes de Brawl Decks, de Planeswalker Decks et de Theme Boosters, ainsi que les cartes de Buy a Box. Cela ne prend pas en compte les cartes des Masterpiece series (Explorer d’Ixalan, Expeditions de Zendikar, Inventions de Kaladesh, Invocations de Amonkhet, et Planeswalker Mythic Editions de Guilds of Ravnica, Ravnica Allegeance et War of the Spark).</em></li>
|
||||
<li><strong>903.BS.5</strong> Il n’y a pas de sideboard pour modifier son deck entre deux parties de BrawlSet. Cependant, comme certaines cartes permettent d’amener des cartes dans la partie depuis l’extérieur du jeu, les joueur·euses peuvent avoir un « wishboard ». Le nombre maximum de cartes d’un wishboard est 15, il n’y pas de nombre minimum de cartes.</li>
|
||||
<li><strong>903.BS.6</strong> Les cartes des wishboard sont hors de la partie, ainsi aucun effet de la partie ne peut permettre à un·e joueur·euse de regarder ou rechercher dans le wishboard d’un·e autre joueur·euse. Un·e joueur·euse ne peut amener une carte hors de la partie dans la partie sauf si cette carte vient de son wishboard ou d’une partie principale d’une sous-partie. Il n’y a pas de restriction sur l’identité colorée des cartes qu’un·e joueur·euse peut amener dans la partie depuis l’extérieur du jeu, ceci est une modification de la règle 903.11.</li>
|
||||
<li>Exemple : <em>Léon lance Emrakul, the Promised End pour prendre le contrôle de l’adversaire ciblé durant son prochain tour et prend le contrôle du prochain tour de Dylan. Léon peut faire en sorte que Dylan lance Granted, l’aventure de Fae of Wishes pendant qu’il contrôle le tour de Dylan. Léon ne pourra pas chercher ou trouver quoi que ce soit dans le wishboard de Dylan. Parce que l’effet demande de chercher dans le wishboard du joueur / de la joueuse lançant cette carte, Léon ne peut pas chercher dans son wishboard. Aucune carte ne sera amenée dans la partie.</em></li>
|
||||
<li><strong>903.BS.7</strong> Un·e joueur·euse désigne comme commandant un Planeswalker légendaire ou une créature légendaire. Ceci est une modification de la règle 903.3</li>
|
||||
<li><strong>903.BS.8</strong> Si un deck de BrawlSet utilise un·e compagnon·ne, le/la compagnon·ne doit respecter l’identité colorée du commandant.</li>
|
||||
<li><strong>903.BS.9</strong> La règle de construction en singleton du Commander s’applique à la combinaison du deck et du wishboard. Ceci est une modification de la règle 903.5b</li>
|
||||
<li><strong>903.BS.10</strong> Toutes les cartes d’un deck de BrawlSet doivent faire partie du même BSet. Cette règle s’applique à la combinaison du deck et du wishboard. Cette règle s’applique aux terrains de base. Ce BSet est le BSet du deck.</li>
|
||||
<li><strong>903.BS.11</strong> Une carte avec un type de terrain de base ne peut être inclue dans un deck que si elle ne produit que du mana de l’identité colorée du commandant. Si aucun terrain de base faisant partie du BSet de ce deck ne vérifie cette propriété, cette règle ne s’applique pas pour les terrains de base pour ce deck. Ceci est une modification de la règle 903.5d.</li>
|
||||
<li>Exemple : <em>Paul veut construire un deck de BrawlSet War of the Spark avec Karn, the Great Creator en commandant. Comme l’identité colorée de Karn est incolore et que les Wastes n’ont pas été éditées dans War of the Spark, Paul peut utiliser n’importe quel terrain de base édité dans War of the Spark pour construire son deck, par exemple une Forest, huit Islands, neuf Mountains, treize Plains et quinze Swamps.</em></li>
|
||||
<li><strong>903.BS.12</strong> La taille minimum d’un deck de BrawlSet est 60, il n’y a pas de taille maximum de deck. Ceci est une modification de la règle 903.5a.</li>
|
||||
<li><strong>903.BS.13</strong> Dans une partie de BrawlSet, le nombre de point de vie de départ est 20. Ceci est une modification de la règle 119.1c</li>
|
||||
<li><strong>903.BS.14</strong> Les parties de BrawlSet n’utilisent pas la règle des blessures de commandant, ainsi l’action décrite dans la règle 704.5v, qui fait perdre un·e joueur·euse qui a subi 21 blessures de combat ou plus d’un commandant ne s’applique pas. Ceci est une modification de la règle 704.5v.</li>
|
||||
<li><strong>903.BS.15</strong> Au début d’un match, chaque joueur·euse doit déclarer son BSet, il ne peut pas être changé entre les parties d’un même match.</li>
|
||||
<li><strong>903.BS.16</strong> Le format de BrawlSet utilise la règle du commander swap. Cela signifie que n’importe quel joueur·euse peut changer de commandant entre deux parties d’un match. Le nouveau commandant doit être une carte du deck, l’ancien commandant devient une carte normale du deck. Le commandant du deck reste secret jusqu’à ce qu’il soit révélé au début de la partie.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
38
frontend/static/assets/artifact.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="600"
|
||||
height="849.88568"
|
||||
id="svg3234">
|
||||
<defs
|
||||
id="defs3236" />
|
||||
<metadata
|
||||
id="metadata3239">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-209.32562,77.669905)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 277.30227,767.01932 c -14.98382,-4.60496 -20.64186,-12.00446 -17.72072,-23.17455 2.54286,-9.72384 25.17485,-17.24278 60.09182,-19.96423 17.63669,-1.37448 37.91459,-4.62606 45.06184,-7.22544 37.25354,-13.54849 73.6648,-41.33741 82.79446,-63.18741 2.40778,-5.76203 6.99974,-43.7987 10.86075,-89.95941 6.1682,-73.74185 6.311,-80.39439 1.83471,-85.34071 -2.67002,-2.95053 -24.65509,-15.2711 -48.8556,-27.37918 C 372.66032,431.42116 364.58431,426.03025 344.2126,405.95958 323.19716,385.25499 319.73422,380.09259 306.75918,350.12703 290.92799,313.56525 263.72307,233.30669 255.45209,198.76349 250.4907,178.04213 248.79634,175.1888 231.38891,158.24067 217.33102,144.5539 212.143,137.20262 210.57731,128.75229 c -3.7542,-20.26282 0.63506,-32.423269 17.27292,-47.854696 l 15.18709,-14.08577 -2.14895,-61.0241488 c -2.08752,-59.2802402 -1.96714,-61.2551122 4.20972,-69.1076892 3.49724,-4.445957 11.36244,-9.473279 17.47826,-11.171974 15.25642,-4.237222 478.24875,-4.237222 493.50479,0 6.11602,1.698695 14.01192,6.756348 17.54646,11.239605 6.24525,7.921151 6.36243,9.719126 4.15075,63.68249188 C 776.52651,30.972325 775.65258,58.5171 775.83626,61.640761 c 0.18274,3.123662 7.04458,11.903485 15.24605,19.510969 16.3485,15.163915 20.73304,27.4421 16.99806,47.60056 -1.56757,8.46032 -6.76369,15.81122 -20.91841,29.59218 -17.48429,17.02274 -19.21595,19.92429 -24.18224,40.52263 -8.56807,35.53582 -35.54297,115.43249 -51.06935,151.25993 -12.98144,29.95501 -16.45739,35.13531 -37.46529,55.83255 -20.3719,20.07067 -28.4479,25.46158 -67.15712,44.82881 -24.20051,12.10808 -46.18539,24.42865 -48.85541,27.37918 -4.47647,4.94632 -4.33273,11.63051 1.84149,85.74461 3.7606,45.14059 8.48368,84.69115 10.77316,90.21299 8.72218,21.03653 45.99719,49.15212 82.87508,62.51128 7.14726,2.58902 27.63596,5.93366 45.52999,7.43229 35.25983,2.95335 57.12094,10.20403 59.62405,19.77603 3.01214,11.51936 -2.67134,18.50347 -19.00533,23.35408 -22.89442,6.79911 -440.58943,6.63691 -462.76872,-0.17897 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7117"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
21
frontend/static/assets/commander.svg
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
width="196.8"
|
||||
height="313.92001"
|
||||
viewBox="0 0 196.8 313.92001"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
id="g1">
|
||||
<path
|
||||
style="display:inline;fill:#000000"
|
||||
d="M 96.320001,313.40138 C 95.076773,312.62187 81.49991,295.60736 80.997053,294.19868 l -0.442949,-1.24086 17.681525,-48.57366 c 9.724841,-26.71552 17.628161,-48.62183 17.562951,-48.68071 -0.35562,-0.32102 -44.593783,-24.28395 -45.05205,-24.40379 -0.398576,-0.10423 -2.71562,2.38823 -8.526912,9.17245 -4.388789,5.12356 -8.019833,9.49241 -8.068986,9.70854 -0.04915,0.21614 2.218848,9.13697 5.040001,19.82407 2.821152,10.6871 5.129368,19.61729 5.129368,19.84486 0,0.67091 -7.611897,21.35883 -8.174903,22.21809 -0.516408,0.78813 -2.229594,1.69234 -3.206458,1.69234 -0.287054,0 -1.017772,-0.2353 -1.623817,-0.52289 -0.897986,-0.42612 -1.652705,-1.44763 -4.078312,-5.52 C 25.682028,211.52918 11.152081,171.83985 4.3462228,130.56001 1.6197832,114.02322 0,95.660031 0,81.28766 0,75.078203 0.04263351,74.592113 0.65559264,73.812862 1.6837009,72.505834 96.232205,0.60704129 97.390241,0.25162984 98.163133,0.01442256 98.703079,0.05252569 99.531845,0.40275926 101.46605,1.220148 195.61007,73.16182 196.26493,74.32291 c 0.53622,0.950725 0.56848,1.636703 0.38742,8.237094 -0.49091,17.895296 -1.92443,33.081656 -4.6518,49.280006 -1.50352,8.92965 -2.43272,13.11567 -3.11571,14.03627 -0.92574,1.2478 -2.81622,1.79919 -4.24473,1.23805 -1.65348,-0.6495 -42.83099,-35.30468 -43.40168,-36.52705 -0.25352,-0.543 -3.68019,-12.839587 -7.61482,-27.325745 -3.93463,-14.486158 -7.20557,-26.376247 -7.26874,-26.422419 -0.25098,-0.183427 -34.012768,-12.007881 -34.083517,-11.937132 -0.195052,0.195051 -37.639624,61.515706 -37.768065,61.850426 -0.08113,0.21142 25.483777,21.8881 57.317352,48.59981 31.60509,26.51999 57.62644,48.52205 57.82522,48.89347 0.74334,1.38895 0.37554,2.9055 -1.99701,8.23432 -9.99817,22.45617 -22.91518,44.41087 -38.02711,64.63366 -5.70912,7.63994 -28.06775,35.27685 -29.19434,36.08634 -1.1768,0.84557 -2.941955,0.93211 -4.107399,0.20137 z"
|
||||
id="path1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
38
frontend/static/assets/creature.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="600.00006"
|
||||
height="533.4812"
|
||||
id="svg3208">
|
||||
<defs
|
||||
id="defs3210" />
|
||||
<metadata
|
||||
id="metadata3213">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-510.31037,-331.03141)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 713.85991,852.97324 c -13.24237,-13.24237 -14.84693,-23.54582 -7.09008,-45.53094 6.99159,-19.81635 16.57282,-30.21975 46.99885,-51.03259 15.37837,-10.51951 42.36291,-30.01837 59.96548,-43.3307 30.71662,-23.23012 46.24631,-32.88718 138.57862,-86.17383 67.21712,-38.79226 157.99762,-74.97988 157.99762,-62.98235 0,5.72718 -21.6024,21.17322 -51.8605,37.08105 -38.8505,20.42524 -148.00006,94.34145 -180.46523,122.21143 -25.57402,21.9543 -59.52308,58.95089 -95.23194,103.78065 -32.31156,40.56494 -48.28299,46.58727 -68.89282,25.97728 z M 582.44653,816.20576 c -8.45298,-9.07328 -10.25942,-20.87627 -6.1929,-40.46499 5.2375,-25.22816 4.44304,-50.05388 -2.02527,-63.29429 -4.62779,-9.47312 -9.75636,-13.42386 -30.8275,-23.74688 -13.90181,-6.81075 -27.06754,-14.83324 -29.25718,-17.82777 -8.88347,-12.14885 -1.85438,-42.35067 16.19924,-69.60247 15.03429,-22.6943 70.08906,-84.7188 103.21529,-116.28207 34.27584,-32.65888 56.12645,-47.6048 82.96195,-56.74722 20.31794,-6.9218 32.05522,-12.39753 98.21751,-45.81973 78.12883,-39.46719 156.03835,-62.44863 156.03835,-46.0273 0,2.79086 -15.37038,11.06447 -42.01036,22.61341 -58.01571,25.15103 -67.51638,30.78852 -109.88679,65.20542 -20.43225,16.59679 -52.72358,41.95507 -71.75852,56.35162 -36.37515,27.5111 -64.18822,55.36967 -93.04461,93.19691 -37.09377,48.6251 -41.04109,58.81668 -29.87389,77.13251 3.29473,5.40382 5.94112,13.84359 5.99037,18.75463 0.11904,11.89398 5.92237,8.12016 11.5416,3.70876 8.32595,-6.53631 22.8854,-19.75439 46.97278,-42.4296 63.70864,-59.9738 148.65491,-122.48685 207.54269,-152.73336 37.96748,-19.50115 139.96581,-61.43062 168.98981,-69.46828 26.6216,-7.37234 42.0707,-8.09195 42.0707,-1.95939 0,5.34202 -7.4131,9.84589 -70.7112,42.96168 -87.20664,45.62406 -123.09569,71.60314 -191.85365,138.87721 -37.24738,36.4438 -103.39288,96.203 -150.30449,135.79298 -5.41638,4.57104 -24.86797,25.80313 -43.2257,47.1823 -18.35757,21.37917 -36.85635,41.60758 -41.10811,44.95205 -9.97667,7.84768 -20.15683,7.72767 -27.66012,-0.32613 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7130"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
38
frontend/static/assets/enchantment.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="600"
|
||||
height="470.37875"
|
||||
id="svg3193">
|
||||
<defs
|
||||
id="defs3195" />
|
||||
<metadata
|
||||
id="metadata3198">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-74.617828,-93.966166)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="M 227.47403,561.75843 C 207.24579,558.40482 79.908114,529.25417 76.620024,527.22197 c -4.4587,-2.75567 0.63436,-6.37383 11.94276,-8.48412 9.97287,-1.86114 82.172696,-20.26915 112.536416,-28.69223 13.22825,-3.66957 19.03248,-12.07303 14.36399,-20.7963 -2.70246,-5.04959 -66.2607,-60.97927 -123.865836,-108.99867 -17.4482,-14.54494 -20.99596,-20.17028 -12.72047,-20.17028 2.49562,0 41.615306,14.96527 86.932496,33.25621 45.31731,18.29081 84.80719,32.79907 87.75534,32.24037 12.29295,-2.32957 8.13469,-17.7239 -30.48361,-112.85687 -36.69419,-90.39306 -42.61293,-108.76388 -33.37597,-103.59465 2.37278,1.32796 33.44868,41.23856 69.05753,88.69028 65.01878,86.64283 70.75428,92.55169 79.54961,81.95408 2.10247,-2.53346 9.05782,-56.11536 16.80808,-129.48607 13.49588,-127.76175 14.71997,-136.317554 19.50335,-136.317554 4.34971,0 5.27361,6.636194 19.16919,137.690004 13.71054,129.30808 14.97592,135.29299 27.7473,131.23949 3.14139,-0.99699 35.22173,-40.97928 71.28978,-88.84954 36.06792,-47.87026 66.73875,-87.03675 68.15723,-87.03675 5.88502,0 0.85671,15.01798 -33.70527,100.66907 -19.95652,49.45557 -37.46987,93.80604 -38.91862,98.55659 -3.15267,10.33757 1.03675,19.876 8.72994,19.876 2.94199,0 40.37442,-14.35605 83.18303,-31.90223 77.0726,-31.59011 94.34154,-37.44717 94.34154,-31.99762 0,1.54671 -20.5133,20.27107 -45.58507,41.60991 -99.32162,84.53292 -101.26842,86.50973 -95.60896,97.08439 3.63533,6.79275 6.01606,7.57393 78.16486,25.6479 66.48498,16.65536 64.76143,16.10807 61.2801,19.4563 -4.07799,3.92193 -104.24375,26.84943 -163.46883,37.41742 -14.61264,2.60731 -16.35991,-1.26179 -16.4407,-36.40478 -0.0616,-26.69068 -1.29076,-35.41639 -7.00754,-49.73205 -9.69782,-24.28443 -34.12561,-51.39814 -59.91009,-62.87234 -34.77689,-15.47576 -73.57113,-14.51621 -103.07505,-0.0244 -47.33861,23.25102 -71.40325,66.16517 -67.37271,119.91724 1.67751,22.37059 1.20421,24.74863 -3.96604,27.76294 -8.05186,4.69324 -17.16443,0.84312 -24.15377,-0.3157 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7143"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
38
frontend/static/assets/instant.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="600"
|
||||
height="798.29449"
|
||||
id="svg3260">
|
||||
<defs
|
||||
id="defs3262" />
|
||||
<metadata
|
||||
id="metadata3265">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-126.2445,-111.90626)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 371.57707,908.61481 c -0.98691,-0.9867 -0.94614,-4.0257 0.09,-6.7534 1.03667,-2.7275 39.21124,-63.714 84.8321,-135.5256 45.6207,-71.8114 84.60551,-133.6678 86.63266,-137.4585 5.863,-10.9625 3.04531,-25.2559 -5.97086,-30.2919 -7.10708,-3.9695 -24.22149,-1.7812 -193.59847,24.7552 -102.19094,16.0103 -189.33421,29.0708 -193.65129,29.0234 -12.63035,-0.1393 -23.66671,-10.7845 -23.66671,-22.8293 0,-12.7751 13.70899,-39.2564 96.33389,-186.08678 76.14904,-135.32228 74.83463,-130.01779 34.29302,-138.38284 -13.28704,-2.74159 -18.94621,-12.09393 -15.53722,-25.67637 2.92691,-11.66213 79.52303,-137.50094 91.12775,-149.71292 5.66664,-5.96322 15.43242,-12.37896 21.70173,-14.2573 14.40509,-4.31589 326.25013,-4.83092 337.49053,-0.55733 11.073,4.21007 14.825,12.9869 10.1836,23.82282 -2.0915,4.88238 -78.06728,85.99788 -168.83526,180.25652 -90.76781,94.25884 -166.69058,174.54354 -168.71654,178.41048 -2.96548,5.65984 -2.88683,8.12082 0.40223,12.61897 3.93336,5.37923 8.10248,4.7774 111.68733,-16.12173 59.18105,-11.94037 112.66675,-21.69884 118.85742,-21.68576 14.92691,0.0323 20.99833,6.6442 29.31161,31.92359 15.48761,47.09528 20.46141,50.82765 63.56401,47.70085 32.041,-2.32424 40.7414,0.87122 37.5031,13.7744 -1.003,3.9957 -25.1768,30.1217 -53.7198,58.0577 -28.5429,27.9363 -89.04025,87.3578 -134.43826,132.048 -162.15269,159.625 -160.61628,158.2083 -165.8766,152.9478 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7156"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
38
frontend/static/assets/land.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="600"
|
||||
height="470.40985"
|
||||
id="svg3167">
|
||||
<defs
|
||||
id="defs3169" />
|
||||
<metadata
|
||||
id="metadata3172">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-109.58004,-73.095985)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="M 328.63936,541.67929 C 246.53884,533.77761 165.84388,512.6966 132.07303,490.32766 96.641563,466.85884 102.10545,442.36571 155.33678,386.04328 c 47.79682,-50.57247 69.78599,-92.9501 100.81797,-194.29796 20.38021,-66.55995 39.18723,-108.401257 51.90149,-115.468842 19.63437,-10.914083 33.19725,4.882525 59.18602,68.933912 27.62365,68.08066 51.2835,109.36882 80.49105,140.46283 8.81695,9.38627 17.39024,15.77384 21.17158,15.77384 7.47226,0 18.42198,-13.08595 38.06261,-45.48852 15.90054,-26.23243 28.05191,-34.47776 46.56017,-31.59338 17.13916,2.6709 30.08009,19.69425 45.28907,59.57568 7.13786,18.71712 17.37737,42.81959 22.75449,53.56078 10.08757,20.15073 35.72363,57.03791 39.7181,57.14976 4.60422,0.12868 39.1318,34.82074 43.89588,44.10456 14.44499,28.14975 -6.88892,53.0083 -61.48392,71.64177 -65.61796,22.39567 -124.91599,31.36027 -217.5119,32.88281 -38.00751,0.62508 -81.90503,-0.0957 -97.55003,-1.60123 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7169"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
BIN
frontend/static/assets/logo.png
Normal file
After Width: | Height: | Size: 67 KiB |
61
frontend/static/assets/planeswalker.svg
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="600"
|
||||
height="1204.1633"
|
||||
id="svg3570">
|
||||
<defs
|
||||
id="defs3572">
|
||||
<clipPath
|
||||
id="clipPath3783">
|
||||
<path
|
||||
d="M 0,300 147,300 147,0 0,0 0,300 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3785" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata3575">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-128.125,398.84217)"
|
||||
id="layer1">
|
||||
<g
|
||||
transform="matrix(4.0816327,0,0,-4.0816327,128.125,815.48356)"
|
||||
id="g3777">
|
||||
<g
|
||||
id="g3779">
|
||||
<g
|
||||
clip-path="url(#clipPath3783)"
|
||||
id="g3781">
|
||||
<g
|
||||
transform="translate(145.458,184.2598)"
|
||||
id="g3787">
|
||||
<path
|
||||
d="m 0,0 c -1.245,32.734 -4.061,45.164 -5.927,45.164 -1.894,0 -2.49,-18.131 -4.979,-34.153 -2.49,-15.985 -6.874,-34.113 -6.874,-34.113 l -11.204,4.268 c 0,0 -3.141,23.131 -4.385,50.851 -1.216,27.721 -2.164,51.931 -5.63,51.931 -3.382,0.029 -4.031,-22.762 -5.276,-52.296 -1.246,-29.517 -5.601,-45.865 -5.601,-45.865 l -10.283,1.433 c 0,0 -4.98,25.602 -6.848,103.807 -0.433,18.509 -4.951,22.223 -4.951,22.223 0,0 -4.52,-3.714 -4.953,-22.223 -1.866,-78.205 -6.874,-103.807 -6.874,-103.807 l -10.257,-1.433 c 0,0 -4.382,16.348 -5.627,45.865 -1.245,29.534 -1.869,52.325 -5.276,52.296 -3.438,0 -4.386,-24.21 -5.659,-51.931 -1.216,-27.72 -4.33,-50.851 -4.33,-50.851 l -11.204,-4.268 c 0,0 -4.382,18.128 -6.872,34.113 -2.489,16.022 -3.113,34.153 -4.979,34.153 -1.868,0 -4.681,-12.43 -5.927,-45.164 -1.245,-32.693 -1.542,-39.084 -1.542,-39.084 0,0 36.777,-15.67 51.093,-56.223 14.343,-40.529 17.969,-75.72 18.077,-79.627 0.188,-6.064 4.33,-6.836 4.33,-6.836 0,0 3.6,0.772 4.33,6.836 0.459,3.879 3.734,39.098 18.075,79.627 14.318,40.553 51.095,56.223 51.095,56.223 0,0 -0.299,6.391 -1.542,39.084"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3789"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
38
frontend/static/assets/sorcery.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="600"
|
||||
height="758.45209"
|
||||
id="svg3338">
|
||||
<defs
|
||||
id="defs3340" />
|
||||
<metadata
|
||||
id="metadata3343">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-248.75759,103.7998)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 549.35881,651.15793 c -7.26111,-3.30528 -9.75906,-6.38344 -9.75906,-12.02521 0,-9.63732 8.08597,-14.82133 32.81288,-21.03582 10.615,-2.66807 21.08723,-6.33414 23.27159,-8.14697 6.81083,-5.65252 4.49888,-16.5977 -5.23635,-24.78929 -23.09774,-19.43541 -67.63066,-21.56509 -115.4088,-5.51909 -36.947,12.4082 -52.50696,14.06376 -79.62666,8.47176 -34.64907,-7.14427 -67.84003,-25.03721 -93.95261,-50.64833 -26.21188,-25.70856 -39.07084,-47.2129 -47.17177,-78.88733 -13.77915,-53.87651 -1.31183,-108.98633 31.84244,-140.75376 22.18432,-21.25618 63.3297,-33.24003 73.21822,-21.32512 3.03843,3.66117 1.3796,5.78081 -9.81608,12.54327 -38.97877,23.54405 -42.44669,77.09646 -7.39267,114.16076 29.4188,31.10591 66.36486,43.04256 133.33259,43.07667 77.97133,0.0397 108.53348,6.46944 138.17357,29.06853 15.91748,12.1362 33.35102,35.33256 37.51949,49.92138 5.0202,17.56954 7.82356,20.67854 15.123,16.77202 9.13048,-4.88654 17.30572,-26.03103 17.38026,-44.95259 0.17058,-43.53187 -29.41295,-86.80809 -73.86362,-108.04745 -17.36811,-8.29885 -26.87761,-10.32104 -98.17715,-20.87833 -23.04844,-3.41301 -33.22998,-7.90698 -48.71307,-21.50106 -11.7892,-10.35119 -19.40549,-22.99003 -19.40549,-32.20276 0,-8.91341 3.13517,-9.47539 23.06736,-4.13482 14.85755,3.98106 19.78241,4.20141 27.00777,1.20854 13.29452,-5.5067 20.36543,-19.68263 20.42174,-40.94091 0.11216,-42.38594 -35.18535,-71.20981 -114.03762,-93.1233 C 356.52243,185.39467 317.72545,156.03943 301.5472,122.99917 284.34055,87.85892 279.29745,39.536552 288.96328,2.4264521 306.88472,-66.378407 371.02643,-108.50168 450.07709,-103.38006 c 35.58306,2.30541 62.68734,13.967959 58.74366,25.276943 -0.4129,1.184015 -14.26332,2.339288 -30.77877,2.567351 -19.8892,0.274798 -34.59065,2.122206 -43.54098,5.471189 -43.63514,16.327808 -61.94402,50.84462 -49.67719,93.654906 7.33612,25.603172 28.66824,44.991379 77.06305,70.040047 48.43336,25.068764 50.03238,26.213994 89.59182,64.170704 37.99478,36.45512 51.65803,44.90072 72.63941,44.90072 48.47589,0 64.72472,-58.86938 28.19389,-102.14586 C 642.01314,88.355472 633.86991,84.008945 592.149,68.443608 565.01575,58.320717 558.94683,54.937385 558.15912,49.494938 c -1.87638,-12.964572 19.99622,-15.887338 58.8897,-7.869829 45.31432,9.341259 94.90108,38.511196 137.35432,80.800391 40.53175,40.37475 65.35563,84.30293 80.83521,143.04448 35.48117,134.64419 -0.2748,268.71238 -90.85178,340.65077 -22.29018,17.70367 -59.43089,35.45314 -87.67712,41.90131 -31.36972,7.1611 -94.45921,9.00407 -107.35064,3.13587 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7218"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
BIN
frontend/static/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
frontend/static/favicon.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
frontend/static/fonts/Beleren2016-Bold.woff
Normal file
BIN
frontend/static/fonts/GeistMonoVF.woff
Normal file
BIN
frontend/static/fonts/GeistVF.woff
Normal file
BIN
frontend/static/fonts/inter-tight-latin-400-italic.ttf
Normal file
BIN
frontend/static/fonts/inter-tight-latin-400-normal.ttf
Normal file
BIN
frontend/static/fonts/inter-tight-latin-800-italic.ttf
Normal file
BIN
frontend/static/fonts/inter-tight-latin-800-normal.ttf
Normal file
31
frontend/svelte.config.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import adapter from "svelte-adapter-bun";
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://svelte.dev/docs/kit/integrations
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||
adapter: adapter({
|
||||
out: "build",
|
||||
assets: true,
|
||||
envPrefix: "BRAWLSET_",
|
||||
development: true,
|
||||
// precompress: true,
|
||||
precompress: {
|
||||
brotli: true,
|
||||
gzip: true,
|
||||
files: ["htm", "html"],
|
||||
},
|
||||
dynamic_origin: true,
|
||||
xff_depth: 1,
|
||||
}),
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
19
frontend/tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
12
frontend/vite.config.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import tailwindcss from '@tailwindcss/vite';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [tailwindcss(), sveltekit()],
|
||||
server: {
|
||||
watch: {
|
||||
ignored: ["**/backend/**"],
|
||||
},
|
||||
},
|
||||
});
|
4
start_server.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
bun run start </dev/null &>/dev/null &
|
||||
./custom_pocketbase serve --http=0.0.0.0:8090
|