90 Commits

Author SHA1 Message Date
574e241c8a fix: migrations 2026-04-15 13:42:36 +02:00
5ebf21c559 Merge remote-tracking branch 'origin/main' into front-styles 2026-04-15 12:08:59 +02:00
84b4c70ffb Merge pull request 'bugfix' (#70) from countries_bugfix into main
Reviewed-on: #70
Reviewed-by: Wiktor Dudzic <dudzic_wiktor@ma-al.com>
2026-04-15 10:00:41 +00:00
Daniel Goc
2fd9472db1 bugfix 2026-04-15 11:48:29 +02:00
66df535317 Merge pull request 'expand_carts' (#69) from expand_carts into main
Reviewed-on: #69
Reviewed-by: Wiktor Dudzic <dudzic_wiktor@ma-al.com>
2026-04-15 09:19:16 +00:00
5663c4e126 fix: addresses 2026-04-14 15:57:45 +02:00
Daniel Goc
e0a86febc4 add missing permission 2026-04-14 15:52:45 +02:00
1d257d82d3 Merge remote-tracking branch 'origin/main' into front-styles 2026-04-14 15:45:36 +02:00
Daniel Goc
40154ec861 Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into expand_carts 2026-04-14 15:43:44 +02:00
Daniel Goc
bb507036db change add-product endpoint + remove-product 2026-04-14 15:42:30 +02:00
80a1314dc0 Merge pull request 'some small fixes' (#68) from small_fixes into main
Reviewed-on: #68
2026-04-14 13:16:17 +00:00
Daniel Goc
100a9f57d4 some small fixes 2026-04-14 14:08:57 +02:00
773e7d3c20 Merge pull request 'feat: lookup by id in customer search' (#61) from cust-search into main
Reviewed-on: #61
2026-04-14 11:42:56 +00:00
03a0e5ea64 Merge branch 'main' into cust-search 2026-04-14 11:39:18 +00:00
ce8c19f715 Merge pull request 'feat: make routing per role, add unlogged role' (#67) from routing-per-role into main
Reviewed-on: #67
Reviewed-by: goc_daniel <goc_daniel@ma-al.com>
2026-04-14 11:39:13 +00:00
4edcb0a852 Merge branch 'main' into cust-search 2026-04-14 11:22:00 +00:00
a4120dafa2 Merge branch 'main' into routing-per-role 2026-04-14 11:21:53 +00:00
5e1a8e898c Merge pull request 'orders' (#58) from orders into main
Reviewed-on: #58
Reviewed-by: Wiktor Dudzic <dudzic_wiktor@ma-al.com>
2026-04-14 11:20:05 +00:00
8e3e41d6fe Merge branch 'main' into cust-search 2026-04-14 11:16:42 +00:00
b33da9d072 Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into routing-per-role 2026-04-14 13:15:51 +02:00
ab783b599d chore: add favorite field to base product query 2026-04-14 11:07:55 +02:00
d173af29fe fix: actually add the unlogged role to migration 2026-04-14 10:18:12 +02:00
f14d60d67b chore: swap permission string in handler to consts 2026-04-14 10:17:05 +02:00
967b101f9b feat: make routing per role, add unlogged role 2026-04-14 09:54:37 +02:00
059808665f Merge remote-tracking branch 'origin/translate' into front-styles 2026-04-14 08:58:32 +02:00
b54645830f fix: store customer-product 2026-04-14 08:55:53 +02:00
97ca510b99 Merge branch 'main' into cust-search 2026-04-14 06:26:47 +00:00
1973189525 Merge remote-tracking branch 'origin/main' into front-styles 2026-04-14 08:18:19 +02:00
83b7cd49dd feat: lookup by id in customer search 2026-04-13 14:43:18 +02:00
5d97d537cd Merge remote-tracking branch 'origin/main' into front-styles 2026-04-13 08:22:35 +02:00
f1a2f4c0b2 fix: fix storage file 2026-04-10 11:38:36 +02:00
bfd20aaa7b Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-10 10:44:47 +02:00
1fb2a33cfd fix: create component StorageFileBrowser 2026-04-09 16:00:36 +02:00
0d2bf3a27f Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-09 08:28:47 +02:00
c7692bc817 fix: page serchUsers 2026-04-08 13:51:10 +02:00
8824796846 Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-08 10:09:40 +02:00
9eb8fc6625 fix: page usersList 2026-04-07 16:06:36 +02:00
a290a72d1d fix: style 2026-04-07 13:54:08 +02:00
b0d0338d23 Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-07 13:40:51 +02:00
849b18c4db Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-07 12:55:50 +02:00
a874a063d8 fix: page usersList 2026-04-07 10:06:36 +02:00
11dab263fa Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-07 08:03:23 +02:00
5bda48b94a Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-07 08:02:32 +02:00
2f4ccbaf92 fix: import 2026-04-07 08:01:21 +02:00
fb910b9ac6 Merge remote-tracking branch 'origin/main' into front-styles 2026-04-03 16:33:32 +02:00
4c505c0520 Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-03 15:54:23 +02:00
2f7e313c95 fix: user info 2026-04-03 15:53:31 +02:00
110946a924 Merge remote-tracking branch 'origin/main' into front-styles 2026-04-03 14:35:29 +02:00
3083330fcd Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-03 11:32:10 +02:00
b7c4b6e3fd fix: store 2026-04-03 11:32:04 +02:00
e9016baf5b Merge remote-tracking branch 'origin/product-procedures' into front-styles 2026-04-03 11:31:35 +02:00
68f31952da Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-03 10:56:21 +02:00
c1efcf1b86 fix: style 2026-04-03 10:55:12 +02:00
5cab7573a8 Merge remote-tracking branch 'origin/product-procedures' into front-styles 2026-04-03 10:54:35 +02:00
5f5c3641f9 Merge remote-tracking branch 'origin/product-procedures' into front-styles 2026-04-03 09:23:51 +02:00
d655e22173 chore: add bruno endpoints 2026-04-03 09:22:58 +02:00
5255ece1b4 Merge remote-tracking branch 'origin/translate' into front-styles 2026-04-03 08:57:10 +02:00
e82279926f erditor on product 2026-04-03 08:56:13 +02:00
855721b4b1 fix: tabs 2026-04-03 08:51:45 +02:00
9fcecfb209 Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-03 08:24:31 +02:00
ee375b7cbd Merge remote-tracking branch 'origin/translate' into front-styles 2026-04-02 16:15:00 +02:00
f58abda5cd fix: style 2026-04-02 16:07:15 +02:00
c20cdf2b63 fix: editor 2026-04-02 15:55:00 +02:00
2ce2556685 fix: tabs 2026-04-02 15:53:27 +02:00
e961967a49 Merge remote-tracking branch 'refs/remotes/origin/front-styles' into front-styles 2026-04-02 15:28:00 +02:00
Daniel Goc
a4eb3b52cf change incoming HTML to HTML4 2026-04-02 15:24:34 +02:00
7c69d56a48 fix: style 2026-04-02 14:24:00 +02:00
1494af985a Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-02 11:42:43 +02:00
9513feba37 fix: style 2026-04-02 11:42:12 +02:00
551b5ef77d fix: translations 2026-04-02 11:41:44 +02:00
a7f69c854a Merge remote-tracking branch 'refs/remotes/origin/front-styles' into front-styles 2026-04-02 11:32:26 +02:00
Daniel Goc
2bfe97f6fe bugfix 2026-04-02 10:38:19 +02:00
7e8e9897e1 fix: button showProduct 2026-04-02 09:01:26 +02:00
9c8ce43998 Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-02 08:56:55 +02:00
3652a78783 fix: button showProduct 2026-04-02 08:56:31 +02:00
ecf51e92e8 fix: button showProduct 2026-04-02 08:56:05 +02:00
d0c055a819 fix: select for languages 2026-04-02 08:52:29 +02:00
272c6066fb Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-01 16:19:36 +02:00
79730eb826 fix: save product descriptions 2026-04-01 16:19:02 +02:00
6846ffc0dc fix: sidebar 2026-04-01 16:16:03 +02:00
d8f71bd8ff Merge remote-tracking branch 'origin/translate' into front-styles 2026-04-01 13:42:00 +02:00
aa57d38bd6 fix: selects 2026-04-01 13:41:21 +02:00
f9ae1e491e fix: translate 2026-04-01 13:40:56 +02:00
8bf5a1cf8b Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-01 10:53:49 +02:00
b48a143b40 fix: default lang 2026-04-01 10:52:34 +02:00
729b54ca1a fix: currency/county 2026-04-01 10:52:08 +02:00
980fb1543b Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-04-01 09:36:56 +02:00
b829bf2185 fix: translate 2026-04-01 09:36:01 +02:00
d6066e39ce Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate 2026-03-31 12:49:25 +02:00
12f6249721 fix: requests 2026-03-31 12:22:21 +02:00
97 changed files with 4252 additions and 7370 deletions

View File

@@ -28,7 +28,7 @@ tmp_dir = "tmp"
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
stop_on_error = true
[color]
app = ""

View File

@@ -7,17 +7,18 @@ import (
"time"
"git.ma-al.com/goc_daniel/b2b/app/config"
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
"git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/service/authService"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
"github.com/gofiber/fiber/v3"
)
// AuthMiddleware creates authentication middleware
func AuthMiddleware() fiber.Handler {
func Authenticate() fiber.Handler {
authService := authService.NewAuthService()
return func(c fiber.Ctx) error {
// Get token from Authorization header
authHeader := c.Get("Authorization")
@@ -25,17 +26,13 @@ func AuthMiddleware() fiber.Handler {
// Try to get from cookie
authHeader = c.Cookies("access_token")
if authHeader == "" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "authorization token required",
})
return c.Next()
}
} else {
// Extract token from "Bearer <token>"
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "invalid authorization header format",
})
return c.Next()
}
authHeader = parts[1]
}
@@ -43,24 +40,18 @@ func AuthMiddleware() fiber.Handler {
// Validate token
claims, err := authService.ValidateToken(authHeader)
if err != nil {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "invalid or expired token",
})
return c.Next()
}
// Get user from database
user, err := authService.GetUserByID(claims.UserID)
if err != nil {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "user not found",
})
return c.Next()
}
// Check if user is active
if !user.IsActive {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
"error": "user account is inactive",
})
return c.Next()
}
// Create locale. LangID is overwritten by auth Token
@@ -78,10 +69,8 @@ func AuthMiddleware() fiber.Handler {
}
// We now populate the target user
if model.CustomerRole(user.Role.Name) != model.RoleAdmin {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
"error": "admin access required",
})
if !userLocale.OriginalUser.HasPermission(perms.Teleport) {
return c.Next()
}
targetUserID, err := strconv.Atoi(targetUserIDAttribute)
@@ -114,6 +103,18 @@ func AuthMiddleware() fiber.Handler {
}
}
func Authorize() fiber.Handler {
return func(c fiber.Ctx) error {
_, ok := localeExtractor.GetUserID(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "not authenticated",
})
}
return c.Next()
}
}
// Webdav
func Webdav() fiber.Handler {
authService := authService.NewAuthService()

View File

@@ -14,4 +14,5 @@ const (
SearchCreateIndex Permission = "search.create_index"
OrdersViewAll Permission = "orders.view_all"
OrdersModifyAll Permission = "orders.modify_all"
Teleport Permission = "teleport"
)

View File

@@ -49,7 +49,7 @@ func AuthHandlerRoutes(r fiber.Router) fiber.Router {
r.Get("/google", handler.GoogleLogin)
r.Get("/google/callback", handler.GoogleCallback)
authProtected := r.Group("", middleware.AuthMiddleware())
authProtected := r.Group("", middleware.Authorize())
authProtected.Get("/me", handler.Me)
authProtected.Post("/update-choice", handler.UpdateJWTToken)

View File

@@ -2,6 +2,7 @@ package public
import (
"git.ma-al.com/goc_daniel/b2b/app/service/menuService"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
@@ -31,12 +32,21 @@ func RoutingHandlerRoutes(r fiber.Router) fiber.Router {
}
func (h *RoutingHandler) GetRouting(c fiber.Ctx) error {
lang_id, ok := localeExtractor.GetLangID(c)
langId, ok := localeExtractor.GetLangID(c)
if !ok {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
}
menu, err := h.menuService.GetRoutes(lang_id)
var roleId uint
customer, ok := localeExtractor.GetCustomer(c)
if !ok {
roleId = constdata.UNLOGGED_USER_ROLE_ID
} else {
roleId = customer.RoleID
}
menu, err := h.menuService.GetRoutes(langId, roleId)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(err)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))

View File

@@ -29,10 +29,12 @@ func CartsHandlerRoutes(r fiber.Router) fiber.Router {
handler := NewCartsHandler()
r.Get("/add-new-cart", handler.AddNewCart)
r.Delete("/remove-cart", handler.RemoveCart)
r.Get("/change-cart-name", handler.ChangeCartName)
r.Get("/retrieve-carts-info", handler.RetrieveCartsInfo)
r.Get("/retrieve-cart", handler.RetrieveCart)
r.Get("/add-product-to-cart", handler.AddProduct)
r.Delete("/remove-product-from-cart", handler.RemoveProduct)
return r
}
@@ -53,6 +55,29 @@ func (h *CartsHandler) AddNewCart(c fiber.Ctx) error {
return c.JSON(response.Make(&new_cart, 0, i18n.T_(c, response.Message_OK)))
}
func (h *CartsHandler) RemoveCart(c fiber.Ctx) error {
userID, ok := localeExtractor.GetUserID(c)
if !ok {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
}
cart_id_attribute := c.Query("cart_id")
cart_id, err := strconv.Atoi(cart_id_attribute)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
}
err = h.cartsService.RemoveCart(userID, uint(cart_id))
if err != nil {
return c.Status(responseErrors.GetErrorStatus(err)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
}
return c.JSON(response.Make(nullable.GetNil(""), 0, i18n.T_(c, response.Message_OK)))
}
func (h *CartsHandler) ChangeCartName(c fiber.Ctx) error {
userID, ok := localeExtractor.GetUserID(c)
if !ok {
@@ -117,6 +142,7 @@ func (h *CartsHandler) RetrieveCart(c fiber.Ctx) error {
return c.JSON(response.Make(cart, 0, i18n.T_(c, response.Message_OK)))
}
// adds or sets given amount of products to the cart
func (h *CartsHandler) AddProduct(c fiber.Ctx) error {
userID, ok := localeExtractor.GetUserID(c)
if !ok {
@@ -159,7 +185,59 @@ func (h *CartsHandler) AddProduct(c fiber.Ctx) error {
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
}
err = h.cartsService.AddProduct(userID, uint(cart_id), uint(product_id), product_attribute_id, uint(amount))
set_amount_attribute := c.Query("set_amount")
set_amount, err := strconv.ParseBool(set_amount_attribute)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
}
err = h.cartsService.AddProduct(userID, uint(cart_id), uint(product_id), product_attribute_id, amount, set_amount)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(err)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
}
return c.JSON(response.Make(nullable.GetNil(""), 0, i18n.T_(c, response.Message_OK)))
}
// removes product from the cart.
func (h *CartsHandler) RemoveProduct(c fiber.Ctx) error {
userID, ok := localeExtractor.GetUserID(c)
if !ok {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
}
cart_id_attribute := c.Query("cart_id")
cart_id, err := strconv.Atoi(cart_id_attribute)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
}
product_id_attribute := c.Query("product_id")
product_id, err := strconv.Atoi(product_id_attribute)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
}
product_attribute_id_attribute := c.Query("product_attribute_id")
var product_attribute_id *uint
if product_attribute_id_attribute == "" {
product_attribute_id = nil
} else {
val, err := strconv.Atoi(product_attribute_id_attribute)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
}
uval := uint(val)
product_attribute_id = &uval
}
err = h.cartsService.RemoveProduct(userID, uint(cart_id), uint(product_id), product_attribute_id)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(err)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))

View File

@@ -3,6 +3,7 @@ package restricted
import (
"strconv"
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware"
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
"git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/service/customerService"
@@ -30,7 +31,7 @@ func CustomerHandlerRoutes(r fiber.Router) fiber.Router {
handler := NewCustomerHandler()
r.Get("", handler.customerData)
r.Get("/list", handler.listCustomers)
r.Get("/list", middleware.Require(perms.UserReadAny), handler.listCustomers)
return r
}
@@ -75,10 +76,6 @@ func (h *customerHandler) listCustomers(fc fiber.Ctx) error {
return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute)))
}
if !user.HasPermission(perms.UserReadAny) {
return fc.Status(fiber.StatusForbidden).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
}
p, filt, err := query_params.ParseFilters[model.Customer](fc, columnMappingListUsers)
if err != nil {
@@ -87,12 +84,6 @@ func (h *customerHandler) listCustomers(fc fiber.Ctx) error {
}
search := fc.Query("search")
if search != "" {
if !user.HasPermission(perms.UserReadAny) {
return fc.Status(fiber.StatusForbidden).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
}
}
customer, err := h.service.Find(user.LangID, p, filt, search)
if err != nil {

View File

@@ -86,9 +86,10 @@ func (s *Server) Setup() error {
// API routes
s.api = s.app.Group("/api/v1")
s.api.Use(middleware.Authenticate())
s.public = s.api.Group("/public")
s.restricted = s.api.Group("/restricted")
s.restricted.Use(middleware.AuthMiddleware())
s.restricted.Use(middleware.Authorize())
s.webdav = s.api.Group("/webdav")
s.webdav.Use(middleware.Webdav())

View File

@@ -7,7 +7,6 @@ type Route struct {
Component string `gorm:"type:varchar(255);not null;comment:path to component file" json:"component"`
Meta *string `gorm:"type:longtext;default:'{}'" json:"meta,omitempty"`
Active *bool `gorm:"type:tinyint;default:1" json:"active,omitempty"`
SortOrder *int `gorm:"type:int;default:0" json:"sort_order,omitempty"`
}
func (Route) TableName() string {

View File

@@ -1,9 +1,13 @@
package cartsRepo
import (
"errors"
"git.ma-al.com/goc_daniel/b2b/app/db"
"git.ma-al.com/goc_daniel/b2b/app/model"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
"gorm.io/gorm"
)
type UICartsRepo interface {
@@ -15,7 +19,8 @@ type UICartsRepo interface {
RetrieveCartsInfo(user_id uint) ([]model.CustomerCart, error)
RetrieveCart(user_id uint, cart_id uint) (*model.CustomerCart, error)
CheckProductExists(product_id uint, product_attribute_id *uint) (bool, error)
AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount uint) error
AddProduct(cart_id uint, product_id uint, product_attribute_id *uint, amount uint, set_amount bool) error
RemoveProduct(cart_id uint, product_id uint, product_attribute_id *uint) error
}
type CartsRepo struct{}
@@ -129,14 +134,61 @@ func (repo *CartsRepo) CheckProductExists(product_id uint, product_attribute_id
}
}
func (repo *CartsRepo) AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount uint) error {
product := model.CartProduct{
CartID: cart_id,
ProductID: product_id,
ProductAttributeID: product_attribute_id,
Amount: amount,
}
err := db.DB.Create(&product).Error
func (repo *CartsRepo) AddProduct(cart_id uint, product_id uint, product_attribute_id *uint, amount uint, set_amount bool) error {
var product model.CartProduct
return err
err := db.DB.
Where(&model.CartProduct{
CartID: cart_id,
ProductID: product_id,
ProductAttributeID: product_attribute_id,
}).
First(&product).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if amount < 1 {
return responseErrors.ErrAmountMustBePositive
} else if amount > constdata.MAX_AMOUNT_OF_PRODUCT_IN_CART {
return responseErrors.ErrAmountMustBeReasonable
}
product = model.CartProduct{
CartID: cart_id,
ProductID: product_id,
ProductAttributeID: product_attribute_id,
Amount: amount,
}
return db.DB.Create(&product).Error
}
// Some other DB error
return err
}
// Product already exists in cart
if set_amount {
product.Amount = amount
} else {
product.Amount = product.Amount + amount
}
if product.Amount < 1 {
return responseErrors.ErrAmountMustBePositive
} else if product.Amount > constdata.MAX_AMOUNT_OF_PRODUCT_IN_CART {
return responseErrors.ErrAmountMustBeReasonable
}
return db.DB.Save(&product).Error
}
func (repo *CartsRepo) RemoveProduct(cart_id uint, product_id uint, product_attribute_id *uint) error {
return db.DB.
Where(&model.CartProduct{
CartID: cart_id,
ProductID: product_id,
ProductAttributeID: product_attribute_id,
}).
Delete(&model.CartProduct{}).Error
}

View File

@@ -1,6 +1,7 @@
package customerRepo
import (
"fmt"
"strings"
"git.ma-al.com/goc_daniel/b2b/app/db"
@@ -80,13 +81,16 @@ func (repo *CustomerRepo) Find(langId uint, p find.Paging, filt *filters.Filters
for _, word := range words {
conditions = append(conditions, `
(LOWER(first_name) LIKE ? OR
(
id = ? OR
LOWER(first_name) LIKE ? OR
LOWER(last_name) LIKE ? OR
LOWER(email) LIKE ?)
`)
args = append(args, strings.ToLower(word))
for range 3 {
args = append(args, "%"+strings.ToLower(word)+"%")
args = append(args, fmt.Sprintf("%%%s%%", strings.ToLower(word)))
}
}
@@ -110,88 +114,3 @@ func (repo *CustomerRepo) Save(customer *model.Customer) error {
func (repo *CustomerRepo) Create(customer *model.Customer) error {
return db.DB.Create(customer).Error
}
// func (repo *CustomerRepo) Search(
// customerId uint,
// partnerCode string,
// p find.Paging,
// filt *filters.FiltersList,
// search string,
// ) (found find.Found[model.UserInList], err error) {
// words := strings.Fields(search)
// if len(words) > 5 {
// words = words[:5]
// }
// query := ctx.DB().
// Model(&model.Customer{}).
// Select("customer.id AS id, customer.first_name as first_name, customer.last_name as last_name, customer.phone_number AS phone_number, customer.email AS email, count(distinct investment_plan_contract.id) as iiplan_purchases, count(distinct `order`.id) as single_purchases, entity.name as entity_name").
// Where("customer.id <> ?", customerId).
// Where("(customer.id IN (SELECT id FROM customer WHERE partner_code IN (WITH RECURSIVE partners AS (SELECT code AS dst FROM partner WHERE code = ? UNION SELECT code FROM partner JOIN partners ON partners.dst = partner.superior_code) SELECT dst FROM partners)) OR customer.recommender_code = ?)", partnerCode, partnerCode).
// Scopes(view.CustomerListQuery())
// var conditions []string
// var args []interface{}
// for _, word := range words {
// conditions = append(conditions, `
// (LOWER(first_name) LIKE ? OR
// LOWER(last_name) LIKE ? OR
// phone_number LIKE ? OR
// LOWER(email) LIKE ?)
// `)
// for i := 0; i < 4; i++ {
// args = append(args, "%"+strings.ToLower(word)+"%")
// }
// }
// finalQuery := strings.Join(conditions, " AND ")
// query = query.Where(finalQuery, args...).
// Scopes(filt.All()...)
// found, err = find.Paginate[V](ctx, p, query)
// return found, errs.Recorded(span, err)
// }
// func (repo *ListRepo) ListUsers(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.UserInList], error) {
// var list []model.UserInList
// var total int64
// query := db.Get().
// Table("b2b_customers AS users").
// Select(`
// users.id AS id,
// users.email AS email,
// users.first_name AS first_name,
// users.last_name AS last_name,
// users.role AS role
// `)
// // Apply all filters
// if filt != nil {
// filt.ApplyAll(query)
// }
// // run counter first as query is without limit and offset
// err := query.Count(&total).Error
// if err != nil {
// return find.Found[model.UserInList]{}, err
// }
// err = query.
// Order("users.id DESC").
// Limit(p.Limit()).
// Offset(p.Offset()).
// Find(&list).Error
// if err != nil {
// return find.Found[model.UserInList]{}, err
// }
// return find.Found[model.UserInList]{
// Items: list,
// Count: uint(total),
// }, nil
// }

View File

@@ -3,6 +3,7 @@ package localeSelectorRepo
import (
"git.ma-al.com/goc_daniel/b2b/app/db"
"git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
)
type UILocaleSelectorRepo interface {
@@ -25,7 +26,9 @@ func (r *LocaleSelectorRepo) GetLanguages() ([]model.Language, error) {
func (r *LocaleSelectorRepo) GetCountriesAndCurrencies() ([]model.Country, error) {
var countries []model.Country
err := db.Get().
Preload("PSCurrency").
Select("*").
Preload("Currency").
Joins("LEFT JOIN " + dbmodel.TableNamePsCountryLang + " AS cl ON cl." + dbmodel.PsCountryLangCols.IDCountry.Col() + " = b2b_countries.ps_id_country AND cl." + dbmodel.PsCountryLangCols.IDLang.Col() + " = 2").
Find(&countries).Error
return countries, err
}

View File

@@ -18,7 +18,7 @@ type UIProductsRepo interface {
// GetJSON(p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity int) (*json.RawMessage, error)
Find(id_lang uint, userID uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.ProductInList], error)
GetProductVariants(langID uint, productID uint, shopID uint, customerID uint, countryID uint, quantity uint) ([]view.ProductAttribute, error)
GetBase(p_id_product, p_id_shop, p_id_lang uint) (view.Product, error)
GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error)
GetPrice(p_id_product uint, productAttributeID *uint, p_id_shop uint, p_id_customer uint, p_id_country uint, p_quantity uint) (view.Price, error)
GetVariants(p_id_product, p_id_shop, p_id_lang, p_id_customer, p_id_country, p_quantity uint) ([]view.ProductAttribute, error)
AddToFavorites(userID uint, productID uint) error
@@ -33,11 +33,11 @@ func New() UIProductsRepo {
return &ProductsRepo{}
}
func (repo *ProductsRepo) GetBase(p_id_product, p_id_shop, p_id_lang uint) (view.Product, error) {
func (repo *ProductsRepo) GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error) {
var result view.Product
err := db.DB.Raw(`CALL get_product_base(?,?,?)`,
p_id_product, p_id_shop, p_id_lang).
err := db.DB.Raw(`CALL get_product_base(?,?,?,?)`,
p_id_product, p_id_shop, p_id_lang, p_id_customer).
Scan(&result).Error
return result, err

View File

@@ -7,7 +7,7 @@ import (
)
type UIRoutesRepo interface {
GetRoutes(langId uint) ([]model.Route, error)
GetRoutes(langId uint, roleId uint) ([]model.Route, error)
GetTopMenu(id uint, roleId uint) ([]model.B2BTopMenu, error)
}
@@ -17,13 +17,18 @@ func New() UIRoutesRepo {
return &RoutesRepo{}
}
func (p *RoutesRepo) GetRoutes(langId uint) ([]model.Route, error) {
func (p *RoutesRepo) GetRoutes(langId uint, roleId uint) ([]model.Route, error) {
routes := []model.Route{}
err := db.DB.Find(&routes, model.Route{Active: nullable.GetNil(true)}).Error
if err != nil {
return nil, err
}
return routes, nil
err := db.
Get().
Model(model.Route{}).
Joins("JOIN b2b_route_roles rr ON rr.route_id = b2b_routes.id").
Where(model.Route{Active: nullable.GetNil(true)}).
Where("rr.role_id = ?", roleId).
Find(&routes).Error
return routes, err
}
func (p *RoutesRepo) GetTopMenu(langId uint, roleId uint) ([]model.B2BTopMenu, error) {

View File

@@ -74,7 +74,7 @@ func (s *CartsService) RetrieveCart(user_id uint, cart_id uint) (*model.Customer
return s.repo.RetrieveCart(user_id, cart_id)
}
func (s *CartsService) AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount uint) error {
func (s *CartsService) AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount int, set_amount bool) error {
exists, err := s.repo.UserHasCart(user_id, cart_id)
if err != nil {
return err
@@ -91,5 +91,17 @@ func (s *CartsService) AddProduct(user_id uint, cart_id uint, product_id uint, p
return responseErrors.ErrProductOrItsVariationDoesNotExist
}
return s.repo.AddProduct(user_id, cart_id, product_id, product_attribute_id, amount)
return s.repo.AddProduct(cart_id, product_id, product_attribute_id, uint(amount), set_amount)
}
func (s *CartsService) RemoveProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint) error {
exists, err := s.repo.UserHasCart(user_id, cart_id)
if err != nil {
return err
}
if !exists {
return responseErrors.ErrUserHasNoSuchCart
}
return s.repo.RemoveProduct(cart_id, product_id, product_attribute_id)
}

View File

@@ -153,6 +153,6 @@ func (s *EmailService) newUserAdminNotificationTemplate(userEmail, userName, bas
// newUserAdminNotificationTemplate returns the HTML template for admin notification
func (s *EmailService) newOrderPlacedTemplate(userID uint) string {
buf := bytes.Buffer{}
emails.EmailNewOrderPlacedWrapper(view.EmailLayout[view.EmailNewOrderPlacedData]{LangID: constdata.ADMIN_NOTIFICATION_LANGUAGE, Data: view.EmailNewOrderPlacedData{UserID: userID}}).Render(context.Background(), &buf)
// emails.EmailNewOrderPlacedWrapper(view.EmailLayout[view.EmailNewOrderPlacedData]{LangID: constdata.ADMIN_NOTIFICATION_LANGUAGE, Data: view.EmailNewOrderPlacedData{UserID: userID}}).Render(context.Background(), &buf)
return buf.String()
}

View File

@@ -102,8 +102,8 @@ func (s *MenuService) createTree(index int, all_categories *([]model.ScannedCate
return node, true
}
func (s *MenuService) GetRoutes(id_lang uint) ([]model.Route, error) {
return s.routesRepo.GetRoutes(id_lang)
func (s *MenuService) GetRoutes(id_lang, roleId uint) ([]model.Route, error) {
return s.routesRepo.GetRoutes(id_lang, roleId)
}
func (s *MenuService) scannedToNormalCategory(scanned model.ScannedCategory) model.Category {

View File

@@ -27,7 +27,7 @@ func (s *ProductService) Get(
p_id_product, p_id_lang, p_id_customer, b2b_id_country, p_quantity uint,
) (*json.RawMessage, error) {
product, err := s.productsRepo.GetBase(p_id_product, constdata.SHOP_ID, p_id_lang)
product, err := s.productsRepo.GetBase(p_id_product, constdata.SHOP_ID, p_id_lang, p_id_customer)
if err != nil {
return nil, err
}

View File

@@ -8,6 +8,7 @@ import (
"log"
"net/http"
"os"
"regexp"
"slices"
"strings"
"time"
@@ -110,8 +111,9 @@ func (s *ProductTranslationService) SaveProductDescription(userID uint, productI
// check that fields description, description_short and usage, if they exist, have a valid html format
mustBeHTML := []string{"description", "description_short", "usage"}
for i := 0; i < len(mustBeHTML); i++ {
if text, exists := updates[mustBeHTML[i]]; exists {
if !isValidXHTML(text) {
if _, exists := updates[mustBeHTML[i]]; exists {
updates[mustBeHTML[i]] = parseAutoCloseTags(updates[mustBeHTML[i]])
if !isValidXHTML(updates[mustBeHTML[i]]) {
return responseErrors.ErrInvalidXHTML
}
}
@@ -264,9 +266,17 @@ func cleanForPrompt(s string) string {
}
}
prompt += ">"
if slices.Contains(xml.HTMLAutoClose, v.Name.Local) {
prompt += "/>"
} else {
prompt += ">"
}
case xml.EndElement:
prompt += "</" + attrName(v.Name) + ">"
if !slices.Contains(xml.HTMLAutoClose, v.Name.Local) {
prompt += "</" + attrName(v.Name) + ">"
}
case xml.CharData:
prompt += string(v)
case xml.Comment:
@@ -307,6 +317,43 @@ func getStringInBetween(str string, start string, end string) (success bool, res
return true, str[s : s+e]
}
// this converts input into HTML4 format.
// this really is ad-hoc solution, but it works.
func parseAutoCloseTags(s string) string {
alts := ""
for i, name := range xml.HTMLAutoClose {
if i > 0 {
alts += "|"
}
alts += name
}
// remove closing </img> tags
reClose := regexp.MustCompile(`(?i)<\s*\/\s*(?:` + alts + `)\s*>`)
s = reClose.ReplaceAllString(s, "")
// convert <img ...> → <img ... />
// matches <img ...> that do NOT already end with />
reOpen := regexp.MustCompile(`(?i)<\s*(` + alts + `)\b([^>]*?)>`)
s = reOpen.ReplaceAllStringFunc(s, func(tag string) string {
trimmed := strings.TrimSpace(tag)
// Already self-closed: <img ... />, <br/>
if strings.HasSuffix(trimmed, "/>") {
return tag
}
// Replace final > with />
i := strings.LastIndex(tag, ">")
if i < 0 {
return tag
}
return tag[:i] + " />"
})
return s
}
// isValidXHTML checks if the string obeys the XHTML format
func isValidXHTML(s string) bool {
r := strings.NewReader(s)
@@ -382,7 +429,12 @@ func rebuildFromResponse(s_original string, s_response string) (bool, string) {
result += fmt.Sprintf(` %s="%s"`, attrName(attr.Name), attr.Value)
}
}
result += ">"
if slices.Contains(xml.HTMLAutoClose, v_original.Name.Local) {
result += "/>"
} else {
result += ">"
}
case xml.CharData:
result += string(v_response)
@@ -400,7 +452,7 @@ func rebuildFromResponse(s_original string, s_response string) (bool, string) {
return false, ""
}
if v_original.Name.Local != "img" {
if !slices.Contains(xml.HTMLAutoClose, v_original.Name.Local) {
result += "</" + attrName(v_original.Name) + ">"
}

View File

@@ -15,6 +15,7 @@ var CATEGORY_BLACKLIST = []uint{250}
const MAX_AMOUNT_OF_CARTS_PER_USER = 10
const DEFAULT_NEW_CART_NAME = "new cart"
const MAX_AMOUNT_OF_PRODUCT_IN_CART = 1024
const MAX_AMOUNT_OF_ADDRESSES_PER_USER = 10
@@ -32,3 +33,5 @@ const WEBDAV_TRIMMED_ROOT = "localhost:3000/api/v1/webdav/storage"
const NON_ALNUM_REGEX = `[^a-z0-9]+`
const MULTI_DASH_REGEX = `-+`
const SLUG_REGEX = `^[a-z0-9]+(?:-[a-z0-9]+)*$`
const UNLOGGED_USER_ROLE_ID = 4

View File

@@ -65,6 +65,8 @@ var (
ErrMaxAmtOfCartsReached = errors.New("maximal amount of carts reached")
ErrUserHasNoSuchCart = errors.New("user does not have cart with given id")
ErrProductOrItsVariationDoesNotExist = errors.New("product or its variation with given ids does not exist")
ErrAmountMustBePositive = errors.New("amount must be positive")
ErrAmountMustBeReasonable = errors.New("amount must be reasonable")
// Typed errors for orders handler
ErrEmptyCart = errors.New("the cart is empty")
@@ -205,6 +207,10 @@ func GetErrorCode(c fiber.Ctx, err error) string {
return i18n.T_(c, "error.err_user_has_no_such_cart")
case errors.Is(err, ErrProductOrItsVariationDoesNotExist):
return i18n.T_(c, "error.err_product_or_its_variation_does_not_exist")
case errors.Is(err, ErrAmountMustBePositive):
return i18n.T_(c, "error.err_amount_must_be_positive")
case errors.Is(err, ErrAmountMustBeReasonable):
return i18n.T_(c, "error.err_amount_must_be_reasonable")
case errors.Is(err, ErrEmptyCart):
return i18n.T_(c, "error.err_cart_is_empty")
@@ -292,6 +298,8 @@ func GetErrorStatus(err error) int {
errors.Is(err, ErrMaxAmtOfCartsReached),
errors.Is(err, ErrUserHasNoSuchCart),
errors.Is(err, ErrProductOrItsVariationDoesNotExist),
errors.Is(err, ErrAmountMustBePositive),
errors.Is(err, ErrAmountMustBeReasonable),
errors.Is(err, ErrEmptyCart),
errors.Is(err, ErrUserHasNoSuchOrder),
errors.Is(err, ErrInvalidReductionType),

55
bo/auto-imports.d.ts vendored
View File

@@ -7,10 +7,10 @@
export {}
declare global {
const avatarGroupInjectionKey: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useAvatarGroup.js').avatarGroupInjectionKey
const defineLocale: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineLocale.js').defineLocale
const defineShortcuts: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts.js').defineShortcuts
const extendLocale: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineLocale.js').extendLocale
const extractShortcuts: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts.js').extractShortcuts
const defineLocale: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineLocale').defineLocale
const defineShortcuts: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts').defineShortcuts
const extendLocale: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineLocale').extendLocale
const extractShortcuts: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts').extractShortcuts
const fieldGroupInjectionKey: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFieldGroup.js').fieldGroupInjectionKey
const formBusInjectionKey: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFormField.js').formBusInjectionKey
const formErrorsInjectionKey: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFormField.js').formErrorsInjectionKey
@@ -29,46 +29,17 @@ declare global {
const useAvatarGroup: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useAvatarGroup.js').useAvatarGroup
const useComponentIcons: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useComponentIcons.js').useComponentIcons
const useComponentUI: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useComponentUI.js').useComponentUI
const useContentSearch: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useContentSearch.js').useContentSearch
const useContentSearch: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useContentSearch').useContentSearch
const useEditorMenu: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useEditorMenu.js').useEditorMenu
const useFieldGroup: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFieldGroup.js').useFieldGroup
const useFileUpload: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFileUpload.js').useFileUpload
const useFormField: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFormField.js').useFormField
const useKbd: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useKbd.js').useKbd
const useFileUpload: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFileUpload').useFileUpload
const useFormField: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useFormField').useFormField
const useKbd: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useKbd').useKbd
const useLocale: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useLocale.js').useLocale
const useOverlay: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useOverlay.js').useOverlay
const useOverlay: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useOverlay').useOverlay
const usePortal: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/usePortal.js').usePortal
const useResizable: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useResizable.js').useResizable
const useScrollspy: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useScrollspy.js').useScrollspy
const useToast: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useToast.js').useToast
}
// for type re-export
declare global {
// @ts-ignore
export type { ShortcutConfig, ShortcutsConfig, ShortcutsOptions } from './node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/defineShortcuts.d')
// @ts-ignore
export type { UseComponentIconsProps } from './node_modules/@nuxt/ui/dist/runtime/composables/useComponentIcons.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useComponentIcons.d')
// @ts-ignore
export type { ThemeUI, ThemeRootContext } from './node_modules/@nuxt/ui/dist/runtime/composables/useComponentUI.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useComponentUI.d')
// @ts-ignore
export type { EditorMenuOptions } from './node_modules/@nuxt/ui/dist/runtime/composables/useEditorMenu.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useEditorMenu.d')
// @ts-ignore
export type { UseFileUploadOptions } from './node_modules/@nuxt/ui/dist/runtime/composables/useFileUpload.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useFileUpload.d')
// @ts-ignore
export type { KbdKey, KbdKeySpecific } from './node_modules/@nuxt/ui/dist/runtime/composables/useKbd.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useKbd.d')
// @ts-ignore
export type { OverlayOptions, Overlay } from './node_modules/@nuxt/ui/dist/runtime/composables/useOverlay.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useOverlay.d')
// @ts-ignore
export type { UseResizableProps, UseResizableReturn } from './node_modules/@nuxt/ui/dist/runtime/composables/useResizable.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useResizable.d')
// @ts-ignore
export type { Toast } from './node_modules/@nuxt/ui/dist/runtime/composables/useToast.d'
import('./node_modules/@nuxt/ui/dist/runtime/composables/useToast.d')
const useResizable: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useResizable').useResizable
const useScrollShadow: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useScrollShadow').useScrollShadow
const useScrollspy: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useScrollspy').useScrollspy
const useToast: typeof import('./node_modules/@nuxt/ui/dist/runtime/composables/useToast').useToast
}

View File

@@ -1,25 +1,25 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "bo",
"dependencies": {
"@nuxt/ui": "^4.5.0",
"@tailwindcss/vite": "^4.2.0",
"@nuxt/ui": "^4.6.0",
"@tailwindcss/vite": "^4.2.2",
"chart.js": "^4.5.1",
"pinia": "^3.0.4",
"tailwindcss": "^4.2.0",
"reka-ui": "^2.9.3",
"tailwindcss": "^4.2.2",
"vue": "beta",
"vue-chartjs": "^5.3.3",
"vue-i18n": "11",
"vue-router": "^5.0.2",
"vue-i18n": "^11.3.0",
"vue-router": "^5.0.4",
},
"devDependencies": {
"@tsconfig/node24": "^24.0.4",
"@types/node": "^24.10.13",
"@vitejs/plugin-vue": "^6.0.4",
"@vue/eslint-config-typescript": "^14.6.0",
"@types/node": "^24.12.0",
"@vitejs/plugin-vue": "^6.0.5",
"@vue/eslint-config-typescript": "^14.7.0",
"@vue/tsconfig": "^0.8.1",
"jiti": "^2.6.1",
"npm-run-all2": "^8.0.4",
@@ -27,8 +27,8 @@
"prettier": "3.8.1",
"typescript": "~5.9.3",
"vite": "beta",
"vite-plugin-vue-devtools": "^8.0.6",
"vue-tsc": "^3.2.4",
"vite-plugin-vue-devtools": "^8.1.1",
"vue-tsc": "^3.2.6",
},
},
},
@@ -88,9 +88,9 @@
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="],
"@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="],
"@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
"@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="],
"@babel/plugin-proposal-decorators": ["@babel/plugin-proposal-decorators@7.29.0", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-syntax-decorators": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA=="],
@@ -114,63 +114,63 @@
"@capsizecss/unpack": ["@capsizecss/unpack@4.0.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA=="],
"@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.4", "", { "os": "android", "cpu": "arm" }, "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.4", "", { "os": "android", "cpu": "arm64" }, "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.4", "", { "os": "android", "cpu": "x64" }, "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.4", "", { "os": "linux", "cpu": "arm" }, "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.4", "", { "os": "linux", "cpu": "x64" }, "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.4", "", { "os": "none", "cpu": "x64" }, "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
@@ -202,7 +202,7 @@
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
"@iconify/collections": ["@iconify/collections@1.0.659", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-gD9i7zfQpr3ZAv1BywaEri8o008KQT9iYaMw5EY4Y/y0qeEZB12FJMMyJGS3NvSeG80udu4kx8aZZLRsAdcANw=="],
"@iconify/collections": ["@iconify/collections@1.0.668", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-d4ygrDoTqb02p7YNHdNzy64y4VQG0bd3w26EH+mJ0eKAj+DSWxDJ1Qw/WdCAqhKfjb+mRp1n9+YwcELs2YWVlg=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
@@ -234,7 +234,7 @@
"@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
@@ -242,17 +242,17 @@
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@nuxt/devtools-kit": ["@nuxt/devtools-kit@3.2.3", "", { "dependencies": { "@nuxt/kit": "^4.3.1", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-5zj7Xx5CDI6P84kMalXoxGLd470buF6ncsRhiEPq8UlwdpVeR7bwi8QnparZNFBdG79bZ5KUkfi5YDXpLYPoIA=="],
"@nuxt/devtools-kit": ["@nuxt/devtools-kit@3.2.4", "", { "dependencies": { "@nuxt/kit": "^4.4.2", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-Yxy2Xgmq5hf3dQy983V0xh0OJV2mYwRZz9eVIGc3EaribdFGPDNGMMbYqX9qCty3Pbxn/bCF3J0UyPaNlHVayQ=="],
"@nuxt/fonts": ["@nuxt/fonts@0.14.0", "", { "dependencies": { "@nuxt/devtools-kit": "^3.2.1", "@nuxt/kit": "^4.2.2", "consola": "^3.4.2", "defu": "^6.1.4", "fontless": "^0.2.1", "h3": "^1.15.5", "magic-regexp": "^0.10.0", "ofetch": "^1.5.1", "pathe": "^2.0.3", "sirv": "^3.0.2", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unifont": "^0.7.4", "unplugin": "^3.0.0", "unstorage": "^1.17.4" } }, "sha512-4uXQl9fa5F4ibdgU8zomoOcyMdnwgdem+Pi8JEqeDYI5yPR32Kam6HnuRr47dTb97CstaepAvXPWQUUHMtjsFQ=="],
"@nuxt/icon": ["@nuxt/icon@2.2.1", "", { "dependencies": { "@iconify/collections": "^1.0.641", "@iconify/types": "^2.0.0", "@iconify/utils": "^3.1.0", "@iconify/vue": "^5.0.0", "@nuxt/devtools-kit": "^3.1.1", "@nuxt/kit": "^4.2.2", "consola": "^3.4.2", "local-pkg": "^1.1.2", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinyglobby": "^0.2.15" } }, "sha512-GI840yYGuvHI0BGDQ63d6rAxGzG96jQcWrnaWIQKlyQo/7sx9PjXkSHckXUXyX1MCr9zY6U25Td6OatfY6Hklw=="],
"@nuxt/kit": ["@nuxt/kit@4.3.1", "", { "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.8", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^3.0.0", "scule": "^1.3.0", "semver": "^7.7.4", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unctx": "^2.5.0", "untyped": "^2.0.0" } }, "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA=="],
"@nuxt/kit": ["@nuxt/kit@4.4.2", "", { "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.8", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "mlly": "^1.8.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^3.0.0", "scule": "^1.3.0", "semver": "^7.7.4", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unctx": "^2.5.0", "untyped": "^2.0.0" } }, "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog=="],
"@nuxt/schema": ["@nuxt/schema@4.3.1", "", { "dependencies": { "@vue/shared": "^3.5.27", "defu": "^6.1.4", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "std-env": "^3.10.0" } }, "sha512-S+wHJdYDuyk9I43Ej27y5BeWMZgi7R/UVql3b3qtT35d0fbpXW7fUenzhLRCCDC6O10sjguc6fcMcR9sMKvV8g=="],
"@nuxt/schema": ["@nuxt/schema@4.4.2", "", { "dependencies": { "@vue/shared": "^3.5.30", "defu": "^6.1.4", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "std-env": "^4.0.0" } }, "sha512-/q6C7Qhiricgi+PKR7ovBnJlKTL0memCbA1CzRT+itCW/oeYzUfeMdQ35mGntlBoyRPNrMXbzuSUhfDbSCU57w=="],
"@nuxt/ui": ["@nuxt/ui@4.5.1", "", { "dependencies": { "@floating-ui/dom": "^1.7.5", "@iconify/vue": "^5.0.0", "@internationalized/date": "^3.11.0", "@internationalized/number": "^3.6.5", "@nuxt/fonts": "^0.14.0", "@nuxt/icon": "^2.2.1", "@nuxt/kit": "^4.3.1", "@nuxt/schema": "^4.3.1", "@nuxtjs/color-mode": "^3.5.2", "@standard-schema/spec": "^1.1.0", "@tailwindcss/postcss": "^4.2.1", "@tailwindcss/vite": "^4.2.1", "@tanstack/vue-table": "^8.21.3", "@tanstack/vue-virtual": "^3.13.19", "@tiptap/core": "^3.20.0", "@tiptap/extension-bubble-menu": "^3.20.0", "@tiptap/extension-code": "^3.20.0", "@tiptap/extension-collaboration": "^3.20.0", "@tiptap/extension-drag-handle": "^3.20.0", "@tiptap/extension-drag-handle-vue-3": "^3.20.0", "@tiptap/extension-floating-menu": "^3.20.0", "@tiptap/extension-horizontal-rule": "^3.20.0", "@tiptap/extension-image": "^3.20.0", "@tiptap/extension-mention": "^3.20.0", "@tiptap/extension-node-range": "^3.20.0", "@tiptap/extension-placeholder": "^3.20.0", "@tiptap/markdown": "^3.20.0", "@tiptap/pm": "^3.20.0", "@tiptap/starter-kit": "^3.20.0", "@tiptap/suggestion": "^3.20.0", "@tiptap/vue-3": "^3.20.0", "@unhead/vue": "^2.1.10", "@vueuse/core": "^14.2.1", "@vueuse/integrations": "^14.2.1", "@vueuse/shared": "^14.2.1", "colortranslator": "^5.0.0", "consola": "^3.4.2", "defu": "^6.1.4", "embla-carousel-auto-height": "^8.6.0", "embla-carousel-auto-scroll": "^8.6.0", "embla-carousel-autoplay": "^8.6.0", "embla-carousel-class-names": "^8.6.0", "embla-carousel-fade": "^8.6.0", "embla-carousel-vue": "^8.6.0", "embla-carousel-wheel-gestures": "^8.1.0", "fuse.js": "^7.1.0", "hookable": "^5.5.3", "knitwork": "^1.3.0", "magic-string": "^0.30.21", "mlly": "^1.8.0", "motion-v": "^1.10.3", "ohash": "^2.0.11", "pathe": "^2.0.3", "reka-ui": "2.8.2", "scule": "^1.3.0", "tailwind-merge": "^3.5.0", "tailwind-variants": "^3.2.2", "tailwindcss": "^4.2.1", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unplugin": "^3.0.0", "unplugin-auto-import": "^21.0.0", "unplugin-vue-components": "^31.0.0", "vaul-vue": "0.4.1", "vue-component-type-helpers": "^3.2.5" }, "peerDependencies": { "@inertiajs/vue3": "^2.0.7", "@nuxt/content": "^3.0.0", "joi": "^18.0.0", "superstruct": "^2.0.0", "typescript": "^5.9.3", "valibot": "^1.0.0", "vue-router": "^4.5.0", "yup": "^1.7.0", "zod": "^3.24.0 || ^4.0.0" }, "optionalPeers": ["@inertiajs/vue3", "@nuxt/content", "joi", "superstruct", "valibot", "vue-router", "yup", "zod"], "bin": { "nuxt-ui": "cli/index.mjs" } }, "sha512-5hWgreVPX6EsNCZNoOd2o7m9fTA3fwUMDw+zeYTSAjhSKtAuvkZrBtmez4MUeTv+LO1gknesgvErdIvlUnElTg=="],
"@nuxt/ui": ["@nuxt/ui@4.6.0", "", { "dependencies": { "@floating-ui/dom": "^1.7.6", "@iconify/vue": "^5.0.0", "@internationalized/date": "^3.12.0", "@internationalized/number": "^3.6.5", "@nuxt/fonts": "^0.14.0", "@nuxt/icon": "^2.2.1", "@nuxt/kit": "^4.4.2", "@nuxt/schema": "^4.4.2", "@nuxtjs/color-mode": "^3.5.2", "@standard-schema/spec": "^1.1.0", "@tailwindcss/postcss": "^4.2.2", "@tailwindcss/vite": "^4.2.2", "@tanstack/vue-table": "^8.21.3", "@tanstack/vue-virtual": "^3.13.23", "@tiptap/core": "^3.20.4", "@tiptap/extension-bubble-menu": "^3.20.4", "@tiptap/extension-code": "^3.20.4", "@tiptap/extension-collaboration": "^3.20.4", "@tiptap/extension-drag-handle": "^3.20.4", "@tiptap/extension-drag-handle-vue-3": "^3.20.4", "@tiptap/extension-floating-menu": "^3.20.4", "@tiptap/extension-horizontal-rule": "^3.20.4", "@tiptap/extension-image": "^3.20.4", "@tiptap/extension-mention": "^3.20.4", "@tiptap/extension-node-range": "^3.20.4", "@tiptap/extension-placeholder": "^3.20.4", "@tiptap/markdown": "^3.20.4", "@tiptap/pm": "^3.20.4", "@tiptap/starter-kit": "^3.20.4", "@tiptap/suggestion": "^3.20.4", "@tiptap/vue-3": "^3.20.4", "@unhead/vue": "^2.1.12", "@vueuse/core": "^14.2.1", "@vueuse/integrations": "^14.2.1", "@vueuse/shared": "^14.2.1", "colortranslator": "^5.0.0", "consola": "^3.4.2", "defu": "^6.1.4", "embla-carousel-auto-height": "^8.6.0", "embla-carousel-auto-scroll": "^8.6.0", "embla-carousel-autoplay": "^8.6.0", "embla-carousel-class-names": "^8.6.0", "embla-carousel-fade": "^8.6.0", "embla-carousel-vue": "^8.6.0", "embla-carousel-wheel-gestures": "^8.1.0", "fuse.js": "^7.1.0", "hookable": "^6.1.0", "knitwork": "^1.3.0", "magic-string": "^0.30.21", "mlly": "^1.8.2", "motion-v": "^2.2.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "reka-ui": "2.9.2", "scule": "^1.3.0", "tailwind-merge": "^3.5.0", "tailwind-variants": "^3.2.2", "tailwindcss": "^4.2.2", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unplugin": "^3.0.0", "unplugin-auto-import": "^21.0.0", "unplugin-vue-components": "^31.1.0", "vaul-vue": "0.4.1", "vue-component-type-helpers": "^3.2.6" }, "peerDependencies": { "@inertiajs/vue3": "^2.0.7", "@nuxt/content": "^3.0.0", "joi": "^18.0.0", "superstruct": "^2.0.0", "typescript": "^5.6.3", "valibot": "^1.0.0", "vue-router": "^4.5.0 || ^5.0.0", "yup": "^1.7.0", "zod": "^3.24.0 || ^4.0.0" }, "optionalPeers": ["@inertiajs/vue3", "@nuxt/content", "joi", "superstruct", "valibot", "vue-router", "yup", "zod"], "bin": { "nuxt-ui": "cli/index.mjs" } }, "sha512-AcoM3bljDvxd4PGfzDbY4zyyy9Zsajfagr3il1iki7G8Ji3SG6Xsgy+weug+Hyp76YM5919oc6ciJmram5bf6A=="],
"@nuxtjs/color-mode": ["@nuxtjs/color-mode@3.5.2", "", { "dependencies": { "@nuxt/kit": "^3.13.2", "pathe": "^1.1.2", "pkg-types": "^1.2.1", "semver": "^7.6.3" } }, "sha512-cC6RfgZh3guHBMLLjrBB2Uti5eUoGM9KyauOaYS9ETmxNWBMTvpgjvSiSJp1OFljIXPIqVTJ3xtJpSNZiO3ZaA=="],
@@ -336,121 +336,121 @@
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@swc/helpers": ["@swc/helpers@0.5.19", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA=="],
"@swc/helpers": ["@swc/helpers@0.5.20", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-2egEBHUMasdypIzrprsu8g+OEVd7Vp2MM3a2eVlM/cyFYto0nGz5BX5BTgh/ShZZI9ed+ozEq+Ngt+rgmUs8tw=="],
"@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="],
"@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.2", "", { "os": "android", "cpu": "arm64" }, "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2", "", { "os": "linux", "cpu": "arm" }, "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.1", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.2", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.2", "", { "os": "win32", "cpu": "x64" }, "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA=="],
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.1", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "postcss": "^8.5.6", "tailwindcss": "4.2.1" } }, "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw=="],
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.2", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.2", "@tailwindcss/oxide": "4.2.2", "postcss": "^8.5.6", "tailwindcss": "4.2.2" } }, "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ=="],
"@tailwindcss/vite": ["@tailwindcss/vite@4.2.1", "", { "dependencies": { "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "tailwindcss": "4.2.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w=="],
"@tailwindcss/vite": ["@tailwindcss/vite@4.2.2", "", { "dependencies": { "@tailwindcss/node": "4.2.2", "@tailwindcss/oxide": "4.2.2", "tailwindcss": "4.2.2" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w=="],
"@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="],
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.21", "", {}, "sha512-ww+fmLHyCbPSf7JNbWZP3g7wl6SdNo3ah5Aiw+0e9FDErkVHLKprYUrwTm7dF646FtEkN/KkAKPYezxpmvOjxw=="],
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.23", "", {}, "sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg=="],
"@tanstack/vue-table": ["@tanstack/vue-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "vue": ">=3.2" } }, "sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw=="],
"@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.21", "", { "dependencies": { "@tanstack/virtual-core": "3.13.21" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-zneUNdQTcUhoDl6+ek+/O4S9gSZRAc2q7VLscZ4WZnFfZcHc3M7OyVCfSDC3hGuwFqzfL8Cx5bZF6zbGCYwXmw=="],
"@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.23", "", { "dependencies": { "@tanstack/virtual-core": "3.13.23" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-b5jPluAR6U3eOq6GWAYSpj3ugnAIZgGR0e6aGAgyRse0Yu6MVQQ0ZWm9SArSXWtageogn6bkVD8D//c4IjW3xQ=="],
"@tiptap/core": ["@tiptap/core@3.20.1", "", { "peerDependencies": { "@tiptap/pm": "^3.20.1" } }, "sha512-SwkPEWIfaDEZjC8SEIi4kZjqIYUbRgLUHUuQezo5GbphUNC8kM1pi3C3EtoOPtxXrEbY6e4pWEzW54Pcrd+rVA=="],
"@tiptap/core": ["@tiptap/core@3.22.0", "", { "peerDependencies": { "@tiptap/pm": "^3.22.0" } }, "sha512-EA/XFbvvz0yRyccqrgOwB9RQe6+uJ8NszjLKH9+3xPE2/+Sa2imax0IqWl7YOXkWihdQVrlpP+EpQF9APKx3jg=="],
"@tiptap/extension-blockquote": ["@tiptap/extension-blockquote@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-WzNXk/63PQI2fav4Ta6P0GmYRyu8Gap1pV3VUqaVK829iJ6Zt1T21xayATHEHWMK27VT1GLPJkx9Ycr2jfDyQw=="],
"@tiptap/extension-blockquote": ["@tiptap/extension-blockquote@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-WF7K1jtEhkhCZFOoei3QrUHMsM6i9eqXw1IuL6cAX3+CBpqVg89KbP/cJp05dYKU0SO0LJkn87biKVqcnAcN7A=="],
"@tiptap/extension-bold": ["@tiptap/extension-bold@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-fz++Qv6Rk/Hov0IYG/r7TJ1Y4zWkuGONe0UN5g0KY32NIMg3HeOHicbi4xsNWTm9uAOl3eawWDkezEMrleObMw=="],
"@tiptap/extension-bold": ["@tiptap/extension-bold@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-mPG1FzOy2DVaJHHuX/eQPIuYie0kqG07M04nElBY8QlV0oYB4/kd0Aubz+m9czqHx/F9u/L98kmMFhCh2DWk2w=="],
"@tiptap/extension-bubble-menu": ["@tiptap/extension-bubble-menu@3.20.1", "", { "dependencies": { "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-XaPvO6aCoWdFnCBus0s88lnj17NR/OopV79i8Qhgz3WMR0vrsL5zsd45l0lZuu9pSvm5VW47SoxakkJiZC1suw=="],
"@tiptap/extension-bubble-menu": ["@tiptap/extension-bubble-menu@3.22.0", "", { "dependencies": { "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-792CUdP0roO17jQJ+fflSJEWfw2cAric61nV2291a2iL7L/6mNJGP4QFim1FqZzfx3/FwHSXEI3NYT6wdUlh8w=="],
"@tiptap/extension-bullet-list": ["@tiptap/extension-bullet-list@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.1" } }, "sha512-mbrlvOZo5OF3vLhp+3fk9KuL/6J/wsN0QxF6ZFRAHzQ9NkJdtdfARcBeBnkWXGN8inB6YxbTGY1/E4lmBkOpOw=="],
"@tiptap/extension-bullet-list": ["@tiptap/extension-bullet-list@3.22.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.22.0" } }, "sha512-GUBYUXlNMxfJVpbDQnwNU54rqIBHEIQ7KyPptghSzvmnwMlr6n10OmYSGSVvNpOAIYkHkuhzkwgUDeU+YzWbjg=="],
"@tiptap/extension-code": ["@tiptap/extension-code@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-509DHINIA/Gg+eTG7TEkfsS8RUiPLH5xZNyLRT0A1oaoaJmECKfrV6aAm05IdfTyqDqz6LW5pbnX6DdUC4keug=="],
"@tiptap/extension-code": ["@tiptap/extension-code@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-JGxByyyUdR0yRt1mOxnA2dp6PmI9pr6C846UkZtuOCwhBOBLkoBGkZqW4FytLPOfWGVJpm7w5tx7h1n5uNwfag=="],
"@tiptap/extension-code-block": ["@tiptap/extension-code-block@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-vKejwBq+Nlj4Ybd3qOyDxIQKzYymdNH+8eXkKwGShk2nfLJIxq69DCyGvmuHgipIO1qcYPJ149UNpGN+YGcdmA=="],
"@tiptap/extension-code-block": ["@tiptap/extension-code-block@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-HtnYHj6yHVy2dKs02j5dyEehWQMGOGRMiZBkefY3TwSSNzGESVcFfDV+Xr87j7zDGYvY16vOtVmyRTOTqPn49A=="],
"@tiptap/extension-collaboration": ["@tiptap/extension-collaboration@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1", "@tiptap/y-tiptap": "^3.0.2", "yjs": "^13" } }, "sha512-JnwLvyzrutBffHp6YPnf0XyTnhAgqZ9D8JSUKFp0edvai+dxsb+UMlawesBrgAuoQXw3B8YZUo2VFDVdKas1xQ=="],
"@tiptap/extension-collaboration": ["@tiptap/extension-collaboration@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0", "@tiptap/y-tiptap": "^3.0.2", "yjs": "^13" } }, "sha512-S/nPIth4/Dr5wmxROk4ELWRYhBXxWt7O6cIi8Fca1rYDBdXofjgt4VDO2iCjnOF0LkIekjQudSOFLWadbM2Z+w=="],
"@tiptap/extension-document": ["@tiptap/extension-document@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-9vrqdGmRV7bQCSY3NLgu7UhIwgOCDp4sKqMNsoNRX0aZ021QQMTvBQDPkiRkCf7MNsnWrNNnr52PVnULEn3vFQ=="],
"@tiptap/extension-document": ["@tiptap/extension-document@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-ZdtuBt2KnxIYBtp/VrKiWQ5cLPw1qDKb+sieipBaDWuvhgDNi1kfr//ByEP8xPhcjJfH/C3PCdYYVwIUJwzdqQ=="],
"@tiptap/extension-drag-handle": ["@tiptap/extension-drag-handle@3.20.1", "", { "dependencies": { "@floating-ui/dom": "^1.6.13" }, "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/extension-collaboration": "^3.20.1", "@tiptap/extension-node-range": "^3.20.1", "@tiptap/pm": "^3.20.1", "@tiptap/y-tiptap": "^3.0.2" } }, "sha512-sIfu5Gt1aZVAagvzr+3Qx+8GE294eU3G6/pYjqNHvf71sDCpdN2gFpeI7WF05foVsCGsH6ieu8x/kTXf5GbNZA=="],
"@tiptap/extension-drag-handle": ["@tiptap/extension-drag-handle@3.22.0", "", { "dependencies": { "@floating-ui/dom": "^1.6.13" }, "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/extension-collaboration": "^3.22.0", "@tiptap/extension-node-range": "^3.22.0", "@tiptap/pm": "^3.22.0", "@tiptap/y-tiptap": "^3.0.2" } }, "sha512-OdOCqdgprFrvVhbLCCGX1D0hXo/2SL8o1o50Gy0l1lgiH9vqi/B2LjUJZwYYneQa1K0ME1J4dL4Vp89V4jej0A=="],
"@tiptap/extension-drag-handle-vue-3": ["@tiptap/extension-drag-handle-vue-3@3.20.1", "", { "peerDependencies": { "@tiptap/extension-drag-handle": "^3.20.1", "@tiptap/pm": "^3.20.1", "@tiptap/vue-3": "^3.20.1", "vue": "^3.0.0" } }, "sha512-FJonOxcj/I7uBpJBSqfEfU+Fqem5aanEj+EsqG5ZQnxhp7cxbUYZkGH0tBBR7jeIIkt2Jk+1LoCAlYzCWbDLcQ=="],
"@tiptap/extension-drag-handle-vue-3": ["@tiptap/extension-drag-handle-vue-3@3.22.0", "", { "peerDependencies": { "@tiptap/extension-drag-handle": "^3.22.0", "@tiptap/pm": "^3.22.0", "@tiptap/vue-3": "^3.22.0", "vue": "^3.0.0" } }, "sha512-QuA3Fxe/jxJAW1LzUazN5FEA0i8UyUQCRQ46IzpA878RI2yzeaOfxTiY26s0oA7uUaoAyPg/pLgVjIdnc1epfA=="],
"@tiptap/extension-dropcursor": ["@tiptap/extension-dropcursor@3.20.1", "", { "peerDependencies": { "@tiptap/extensions": "^3.20.1" } }, "sha512-K18L9FX4znn+ViPSIbTLOGcIaXMx/gLNwAPE8wPLwswbHhQqdiY1zzdBw6drgOc1Hicvebo2dIoUlSXOZsOEcw=="],
"@tiptap/extension-dropcursor": ["@tiptap/extension-dropcursor@3.22.0", "", { "peerDependencies": { "@tiptap/extensions": "^3.22.0" } }, "sha512-yI0aMD4szbNdy/dlglPbZ9Ddc2UucRatJSifmtenCLg7YWyIIYton0T6Uym+FXAEUZ6KsaoNqEKiUbK5cRzZMQ=="],
"@tiptap/extension-floating-menu": ["@tiptap/extension-floating-menu@3.20.1", "", { "peerDependencies": { "@floating-ui/dom": "^1.0.0", "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-BeDC6nfOesIMn5pFuUnkEjOxGv80sOJ8uk1mdt9/3Fkvra8cB9NIYYCVtd6PU8oQFmJ8vFqPrRkUWrG5tbqnOg=="],
"@tiptap/extension-floating-menu": ["@tiptap/extension-floating-menu@3.22.0", "", { "peerDependencies": { "@floating-ui/dom": "^1.0.0", "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-6Gg3I6n+YaCJyvpcKheWiOtU9Oy0M3lbwUGdLK7jTxgAG2YOJxEcx2CzDv3PtNcoyAVUVk9Eio21awVMOECLAQ=="],
"@tiptap/extension-gapcursor": ["@tiptap/extension-gapcursor@3.20.1", "", { "peerDependencies": { "@tiptap/extensions": "^3.20.1" } }, "sha512-kZOtttV6Ai8VUAgEng3h4WKFbtdSNJ6ps7r0cRPY+FctWhVmgNb/JJwwyC+vSilR7nRENAhrA/Cv/RxVlvLw+g=="],
"@tiptap/extension-gapcursor": ["@tiptap/extension-gapcursor@3.22.0", "", { "peerDependencies": { "@tiptap/extensions": "^3.22.0" } }, "sha512-VsnaTU88PlA/eG9DtUvuB90z5gVZIaH6T/JVTxGasxR4CFsv0L4Zq5awwr0+SsYH9dKepRMgbanVU03c6k1SuA=="],
"@tiptap/extension-hard-break": ["@tiptap/extension-hard-break@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-9sKpmg/IIdlLXimYWUZ3PplIRcehv4Oc7V1miTqlnAthMzjMqigDkjjgte4JZV67RdnDJTQkRw8TklCAU28Emg=="],
"@tiptap/extension-hard-break": ["@tiptap/extension-hard-break@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-F51pt3fgjbtWrY0Uud+5HoJW4f7w/aBZvmoCk19nrEY955vvuQQ2PD/DZtecl4A8fF50PpRjgilrYnnh99l0ew=="],
"@tiptap/extension-heading": ["@tiptap/extension-heading@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-unudyfQP6FxnyWinxvPqe/51DG91J6AaJm666RnAubgYMCgym+33kBftx4j4A6qf+ddWYbD00thMNKOnVLjAEQ=="],
"@tiptap/extension-heading": ["@tiptap/extension-heading@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-SnOUBXzh9Dft7HY0rqaSL/kZKg4W9wlHfpnFPW8aIuewXvFDLKa6PisqxPpHsXSbG21kfs5E0MLdwdXtNP89XA=="],
"@tiptap/extension-horizontal-rule": ["@tiptap/extension-horizontal-rule@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-rjFKFXNntdl0jay8oIGFvvykHlpyQTLmrH3Ag2fj3i8yh6MVvqhtaDomYQbw5sxECd5hBkL+T4n2d2DRuVw/QQ=="],
"@tiptap/extension-horizontal-rule": ["@tiptap/extension-horizontal-rule@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-9v08PcmJOumVmgGgcuFPZpAk+tf+m7+vaCNsNyf8Ce1i0m3GPSle1ZmxzjDU2FlpaCFrcgoUKlEjKYaFYFCJIg=="],
"@tiptap/extension-image": ["@tiptap/extension-image@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-/GPFSLNdYSZQ0E6VBXSAk0UFtDdn98HT1Aa2tO+STELqc5jAdFB42dfFnTC6KQzTvcUOUYkE2S1Q22YC5H2XNQ=="],
"@tiptap/extension-image": ["@tiptap/extension-image@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-b3n86lWF3thywUrWmZv27EzTGhCBTjifXY/NzPfri3D22cKkxardrJi2WZIc0J65je91oTzqY7SkdQnyIrZksw=="],
"@tiptap/extension-italic": ["@tiptap/extension-italic@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-ZYRX13Kt8tR8JOzSXirH3pRpi8x30o7LHxZY58uXBdUvr3tFzOkh03qbN523+diidSVeHP/aMd/+IrplHRkQug=="],
"@tiptap/extension-italic": ["@tiptap/extension-italic@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-+qq9QZF44O1MRqk6w1AMDZ8oDBs5AtdDdNEcdXpzVU54cJAtWyEPEfXtD0B68hOUp/RdZjMdL27fp+4Id7C1YA=="],
"@tiptap/extension-link": ["@tiptap/extension-link@3.20.1", "", { "dependencies": { "linkifyjs": "^4.3.2" }, "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-oYTTIgsQMqpkSnJAuAc+UtIKMuI4lv9e1y4LfI1iYm6NkEUHhONppU59smhxHLzb3Ww7YpDffbp5IgDTAiJztA=="],
"@tiptap/extension-link": ["@tiptap/extension-link@3.22.0", "", { "dependencies": { "linkifyjs": "^4.3.2" }, "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-tGMBUAmni532G6R5gnaRvTb6c7+ST1qCHBV0p5kGGzdHaQTDd1R7S8fnuA3M7+6Sruc82iIY+Ur+6Tusvo/vLA=="],
"@tiptap/extension-list": ["@tiptap/extension-list@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-euBRAn0mkV7R2VEE+AuOt3R0j9RHEMFXamPFmtvTo8IInxDClusrm6mJoDjS8gCGAXsQCRiAe1SCQBPgGbOOwg=="],
"@tiptap/extension-list": ["@tiptap/extension-list@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-NfSCAgX44NVLib6aN4HmsP1wi6fFfK3dt6TBb9EgcR82nzq6n7dq7VEBw9V1aKqeXQEtNpqMnQFd0SDayweyfQ=="],
"@tiptap/extension-list-item": ["@tiptap/extension-list-item@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.1" } }, "sha512-tzgnyTW82lYJkUnadYbatwkI9dLz/OWRSWuFpQPRje/ItmFMWuQ9c9NDD8qLbXPdEYnvrgSAA+ipCD/1G0qA0Q=="],
"@tiptap/extension-list-item": ["@tiptap/extension-list-item@3.22.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.22.0" } }, "sha512-9cFvFLEtf0bnOc/LaGeX2D+c9wOxeqhzgabUl2Ztz8Xzoby4JtamXnrIpb7DG7hZMf3luJMF8bz0HSvAnNiISQ=="],
"@tiptap/extension-list-keymap": ["@tiptap/extension-list-keymap@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.1" } }, "sha512-Dr0xsQKx0XPOgDg7xqoWwfv7FFwZ3WeF3eOjqh3rDXlNHMj1v+UW5cj1HLphrsAZHTrVTn2C+VWPJkMZrSbpvQ=="],
"@tiptap/extension-list-keymap": ["@tiptap/extension-list-keymap@3.22.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.22.0" } }, "sha512-uCtr5/g+Cwkmsb/VLctgo4VjKm0jv52moAmDyr/TLRjW94gnSLhwXFKzyd7BNIXBQHDyS44UEIJFD3ul4dUKdw=="],
"@tiptap/extension-mention": ["@tiptap/extension-mention@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1", "@tiptap/suggestion": "^3.20.1" } }, "sha512-KOGokj7oH1QpcM8P02V+o6wHsVE0g7XEtdIy2vtq2vlFE3npNNNFkMa8F8VWX6qyC+VeVrNU6SIzS5MFY2TORA=="],
"@tiptap/extension-mention": ["@tiptap/extension-mention@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0", "@tiptap/suggestion": "^3.22.0" } }, "sha512-Ndjn8YTcZMyyEV5cm+3TupRsQ4b8+4gRrZXfsqbEbXN/IGXgl+ObBx+bxBU+aAe2ZRgqEeuVIBIVWBzYaxLxrg=="],
"@tiptap/extension-node-range": ["@tiptap/extension-node-range@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-+W/mQJxlkXMcwldWUqwdoR0eniJ1S9cVJoAy2Lkis0NhILZDWVNGKl9J4WFoCOXn8Myr17IllIxRYvAXJJ4FHQ=="],
"@tiptap/extension-node-range": ["@tiptap/extension-node-range@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-tize9T79ABbOmkw3+7k8cFjSU/JMpzv1JyvFXuGD7lmiHSrFH9Ll8uOGJC7qhCGJWMsjVvrKmBHSOGbzfJI5hQ=="],
"@tiptap/extension-ordered-list": ["@tiptap/extension-ordered-list@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.1" } }, "sha512-Y+3Ad7OwAdagqdYwCnbqf7/to5ypD4NnUNHA0TXRCs7cAHRA8AdgPoIcGFpaaSpV86oosNU3yfeJouYeroffog=="],
"@tiptap/extension-ordered-list": ["@tiptap/extension-ordered-list@3.22.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.22.0" } }, "sha512-B5JSJ2Xe2KPIYYG7jpZHVeAku/VJB+CCgPYl+qIHjZ4JGTnW23qkIA+6dWk6WljGmhQL1qusxZZn4UAnZtBLeQ=="],
"@tiptap/extension-paragraph": ["@tiptap/extension-paragraph@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-QFrAtXNyv7JSnomMQc1nx5AnG9mMznfbYJAbdOQYVdbLtAzTfiTuNPNbQrufy5ZGtGaHxDCoaygu2QEfzaKG+Q=="],
"@tiptap/extension-paragraph": ["@tiptap/extension-paragraph@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-fwkPvbGI3xvzWrTJVGZVocgA99Pgqd5kW7iv7MEWlI9uOUa6Ifu31/seHV7j+QDW3y3mADcx+zyhxcMVELtLjA=="],
"@tiptap/extension-placeholder": ["@tiptap/extension-placeholder@3.20.1", "", { "peerDependencies": { "@tiptap/extensions": "^3.20.1" } }, "sha512-k+jfbCugYGuIFBdojukgEopGazIMOgHrw46FnyN2X/6ICOIjQP2rh2ObslrsUOsJYoEevxCsNF9hZl1HvWX66g=="],
"@tiptap/extension-placeholder": ["@tiptap/extension-placeholder@3.22.0", "", { "peerDependencies": { "@tiptap/extensions": "^3.22.0" } }, "sha512-1GCc87DIPG3jgLH1Xg3ZW11LEzEWnpinLBIZ8RQqrEH0UwtRUW3QsbvwnKKgbbAEtA91GAdnc1eUQ0dpn+tSeQ=="],
"@tiptap/extension-strike": ["@tiptap/extension-strike@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-EYgyma10lpsY+rwbVQL9u+gA7hBlKLSMFH7Zgd37FSxukOjr+HE8iKPQQ+SwbGejyDsPlLT8Z5Jnuxo5Ng90Pg=="],
"@tiptap/extension-strike": ["@tiptap/extension-strike@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-gCgFr1sIcqrJeV5Gdrh8KVZHA+0B1FpFBuOi6FzMyVfBB2sBBqKnjoInYTkPXXdP49Qu8L8hi4luFQtoj4zGzA=="],
"@tiptap/extension-text": ["@tiptap/extension-text@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-7PlIbYW8UenV6NPOXHmv8IcmPGlGx6HFq66RmkJAOJRPXPkTLAiX0N8rQtzUJ6jDEHqoJpaHFEHJw0xzW1yF+A=="],
"@tiptap/extension-text": ["@tiptap/extension-text@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-FQ3lBRswZbSEbtxOnDF4T7pdsZRmKh/8q+M29zXaDHGfBc6nuGNPlNKSIy0Iryjhf/YmMVaWDpHvzk56KD7QtA=="],
"@tiptap/extension-underline": ["@tiptap/extension-underline@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1" } }, "sha512-fmHvDKzwCgnZUwRreq8tYkb1YyEwgzZ6QQkAQ0CsCRtvRMqzerr3Duz0Als4i8voZTuGDEL3VR6nAJbLAb/wPg=="],
"@tiptap/extension-underline": ["@tiptap/extension-underline@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0" } }, "sha512-AxQOnXQwYmZNjagkEoCZZqbpJbLVmBcu1ivJ9dE0SAQsr1wRUp7mAg+g1SqhbMAvrXvv7yhhNevSdQKmXsnFyA=="],
"@tiptap/extensions": ["@tiptap/extensions@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-JRc/v+OBH0qLTdvQ7HvHWTxGJH73QOf1MC0R8NhOX2QnAbg2mPFv1h+FjGa2gfLGuCXBdWQomjekWkUKbC4e5A=="],
"@tiptap/extensions": ["@tiptap/extensions@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-En8p1FiFBT3V9CduErCyLPFxDRsYLISb2cCtLKTeYVeCRn2vQZK4B8WuOgHI4IBipz3I3XidmDhra4yt8mmi/w=="],
"@tiptap/markdown": ["@tiptap/markdown@3.20.1", "", { "dependencies": { "marked": "^17.0.1" }, "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-dNrtP7kmabDomgjv9G/6+JSFL6WraPaFbmKh1eHSYKdDGvIwBfJnVPTV2VS3bP1OuYJEDJN/2ydtiCHyOTrQsQ=="],
"@tiptap/markdown": ["@tiptap/markdown@3.22.0", "", { "dependencies": { "marked": "^17.0.1" }, "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-lvYqID2ui4+HEgh/zULQJoKfb7ILe6ahB9IeaJ5R48mrVyeudciqoJV6VmNOaucm/UpKExlDC3I+QlA9sLpYPw=="],
"@tiptap/pm": ["@tiptap/pm@3.20.1", "", { "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", "prosemirror-commands": "^1.6.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", "prosemirror-history": "^1.4.1", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", "prosemirror-markdown": "^1.13.1", "prosemirror-menu": "^1.2.4", "prosemirror-model": "^1.24.1", "prosemirror-schema-basic": "^1.2.3", "prosemirror-schema-list": "^1.5.0", "prosemirror-state": "^1.4.3", "prosemirror-tables": "^1.6.4", "prosemirror-trailing-node": "^3.0.0", "prosemirror-transform": "^1.10.2", "prosemirror-view": "^1.38.1" } }, "sha512-6kCiGLvpES4AxcEuOhb7HR7/xIeJWMjZlb6J7e8zpiIh5BoQc7NoRdctsnmFEjZvC19bIasccshHQ7H2zchWqw=="],
"@tiptap/pm": ["@tiptap/pm@3.22.0", "", { "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", "prosemirror-commands": "^1.6.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", "prosemirror-history": "^1.4.1", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", "prosemirror-markdown": "^1.13.1", "prosemirror-menu": "^1.2.4", "prosemirror-model": "^1.24.1", "prosemirror-schema-basic": "^1.2.3", "prosemirror-schema-list": "^1.5.0", "prosemirror-state": "^1.4.3", "prosemirror-tables": "^1.6.4", "prosemirror-trailing-node": "^3.0.0", "prosemirror-transform": "^1.10.2", "prosemirror-view": "^1.38.1" } }, "sha512-O9kpzNnFX5837kFevwAM8yr7ImLHu8noIwIpoci0AwfJjiBMzfZBejhbzxnKEfTpFWnkvZ8rWohlb6CQdJ6Crg=="],
"@tiptap/starter-kit": ["@tiptap/starter-kit@3.20.1", "", { "dependencies": { "@tiptap/core": "^3.20.1", "@tiptap/extension-blockquote": "^3.20.1", "@tiptap/extension-bold": "^3.20.1", "@tiptap/extension-bullet-list": "^3.20.1", "@tiptap/extension-code": "^3.20.1", "@tiptap/extension-code-block": "^3.20.1", "@tiptap/extension-document": "^3.20.1", "@tiptap/extension-dropcursor": "^3.20.1", "@tiptap/extension-gapcursor": "^3.20.1", "@tiptap/extension-hard-break": "^3.20.1", "@tiptap/extension-heading": "^3.20.1", "@tiptap/extension-horizontal-rule": "^3.20.1", "@tiptap/extension-italic": "^3.20.1", "@tiptap/extension-link": "^3.20.1", "@tiptap/extension-list": "^3.20.1", "@tiptap/extension-list-item": "^3.20.1", "@tiptap/extension-list-keymap": "^3.20.1", "@tiptap/extension-ordered-list": "^3.20.1", "@tiptap/extension-paragraph": "^3.20.1", "@tiptap/extension-strike": "^3.20.1", "@tiptap/extension-text": "^3.20.1", "@tiptap/extension-underline": "^3.20.1", "@tiptap/extensions": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-opqWxL/4OTEiqmVC0wsU4o3JhAf6LycJ2G/gRIZVAIFLljI9uHfpPMTFGxZ5w9IVVJaP5PJysfwW/635kKqkrw=="],
"@tiptap/starter-kit": ["@tiptap/starter-kit@3.22.0", "", { "dependencies": { "@tiptap/core": "^3.22.0", "@tiptap/extension-blockquote": "^3.22.0", "@tiptap/extension-bold": "^3.22.0", "@tiptap/extension-bullet-list": "^3.22.0", "@tiptap/extension-code": "^3.22.0", "@tiptap/extension-code-block": "^3.22.0", "@tiptap/extension-document": "^3.22.0", "@tiptap/extension-dropcursor": "^3.22.0", "@tiptap/extension-gapcursor": "^3.22.0", "@tiptap/extension-hard-break": "^3.22.0", "@tiptap/extension-heading": "^3.22.0", "@tiptap/extension-horizontal-rule": "^3.22.0", "@tiptap/extension-italic": "^3.22.0", "@tiptap/extension-link": "^3.22.0", "@tiptap/extension-list": "^3.22.0", "@tiptap/extension-list-item": "^3.22.0", "@tiptap/extension-list-keymap": "^3.22.0", "@tiptap/extension-ordered-list": "^3.22.0", "@tiptap/extension-paragraph": "^3.22.0", "@tiptap/extension-strike": "^3.22.0", "@tiptap/extension-text": "^3.22.0", "@tiptap/extension-underline": "^3.22.0", "@tiptap/extensions": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-3V0RysviBKbsvzHuupM30ftb/WLogSgINtIbmGQHZK4Ta1YzwzW63nAWPGKOoFw8r1HRFFO6LjtqrT6iJsPnzQ=="],
"@tiptap/suggestion": ["@tiptap/suggestion@3.20.1", "", { "peerDependencies": { "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1" } }, "sha512-ng7olbzgZhWvPJVJygNQK5153CjquR2eJXpkLq7bRjHlahvt4TH4tGFYvGdYZcXuzbe2g9RoqT7NaPGL9CUq9w=="],
"@tiptap/suggestion": ["@tiptap/suggestion@3.22.0", "", { "peerDependencies": { "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0" } }, "sha512-qdZ4v7sXkM4p2+M7OWCGVoNmHmiaHhiGQN3lUzaNG7mG1gZ2SDirSaeOfL8lHxpnPlGzmE4tUe5eCWMpNKHypA=="],
"@tiptap/vue-3": ["@tiptap/vue-3@3.20.1", "", { "optionalDependencies": { "@tiptap/extension-bubble-menu": "^3.20.1", "@tiptap/extension-floating-menu": "^3.20.1" }, "peerDependencies": { "@floating-ui/dom": "^1.0.0", "@tiptap/core": "^3.20.1", "@tiptap/pm": "^3.20.1", "vue": "^3.0.0" } }, "sha512-06IsNzIkAC0HPHNSdXf4AgtExnr02BHBLXmUiNrjjhgHdxXDKIB0Yq3hEWEfbWNPr3lr7jK6EaFu2IKFMhoUtQ=="],
"@tiptap/vue-3": ["@tiptap/vue-3@3.22.0", "", { "optionalDependencies": { "@tiptap/extension-bubble-menu": "^3.22.0", "@tiptap/extension-floating-menu": "^3.22.0" }, "peerDependencies": { "@floating-ui/dom": "^1.0.0", "@tiptap/core": "^3.22.0", "@tiptap/pm": "^3.22.0", "vue": "^3.0.0" } }, "sha512-CVThMRtCAYmz+N5RtnxRAjfPZwavdqi0RqjznF3M0Tc5UVrwfJG5YYtE7uzySmzuxW7VrkjTUC+Zx9YM2hQEXQ=="],
"@tiptap/y-tiptap": ["@tiptap/y-tiptap@3.0.2", "", { "dependencies": { "lib0": "^0.2.100" }, "peerDependencies": { "prosemirror-model": "^1.7.1", "prosemirror-state": "^1.2.3", "prosemirror-view": "^1.9.10", "y-protocols": "^1.0.1", "yjs": "^13.5.38" } }, "sha512-flMn/YW6zTbc6cvDaUPh/NfLRTXDIqgpBUkYzM74KA1snqQwhOMjnRcnpu4hDFrTnPO6QGzr99vRyXEA7M44WA=="],
@@ -474,29 +474,29 @@
"@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.57.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/type-utils": "8.57.0", "@typescript-eslint/utils": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.57.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.58.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/type-utils": "8.58.0", "@typescript-eslint/utils": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.58.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.57.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.58.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.0", "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.58.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.58.0", "@typescript-eslint/types": "^8.58.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0" } }, "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0" } }, "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.58.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0", "@typescript-eslint/utils": "8.58.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.58.0", "", {}, "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.0", "@typescript-eslint/tsconfig-utils": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.58.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.58.0", "@typescript-eslint/tsconfig-utils": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.58.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ=="],
"@unhead/vue": ["@unhead/vue@2.1.12", "", { "dependencies": { "hookable": "^6.0.1", "unhead": "2.1.12" }, "peerDependencies": { "vue": ">=3.5.18" } }, "sha512-zEWqg0nZM8acpuTZE40wkeUl8AhIe0tU0OkilVi1D4fmVjACrwoh5HP6aNqJ8kUnKsoy6D+R3Vi/O+fmdNGO7g=="],
"@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.4", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.2" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "vue": "^3.2.25" } }, "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ=="],
"@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.5", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.2" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg=="],
"@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="],
@@ -512,39 +512,39 @@
"@vue/babel-plugin-resolve-type": ["@vue/babel-plugin-resolve-type@1.5.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/parser": "^7.28.0", "@vue/compiler-sfc": "^3.5.18" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w=="],
"@vue/compiler-core": ["@vue/compiler-core@3.6.0-beta.7", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.6.0-beta.7", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-fYOlA9PCFuf5l8AtKJSxAM+K+MLoM8dyN9Xsa/GDE0Uf6wxFe33AEU6xyVqYMPy6uxp4RtgE4KuQ7JdYvE0Jnw=="],
"@vue/compiler-core": ["@vue/compiler-core@3.6.0-beta.9", "", { "dependencies": { "@babel/parser": "^7.29.2", "@vue/shared": "3.6.0-beta.9", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-/qlfk4cbU//tgdwWeAbl4kBvH5ZocjJ6CMGigzRKk1So/0jl6kRpFxVbc6oNsYYH6Xj28ByA+msAes1FjExejg=="],
"@vue/compiler-dom": ["@vue/compiler-dom@3.6.0-beta.7", "", { "dependencies": { "@vue/compiler-core": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7" } }, "sha512-4myAKKPogd6MAA/oKKn1+uDOPGJ6gB+pivaUxaBqfvXJch1QHSpcUgdHCJqDb9O/99EjcwppkTLGe7cRWMSqHQ=="],
"@vue/compiler-dom": ["@vue/compiler-dom@3.6.0-beta.9", "", { "dependencies": { "@vue/compiler-core": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9" } }, "sha512-Bh2h+Co2Vl85jhNjR+yBU1oIujqQ3XIhF7FzODBStvp8yn2WvsXmm5QlvnE7q+smJkfglTbfFcaou8fjR0Y4ag=="],
"@vue/compiler-sfc": ["@vue/compiler-sfc@3.6.0-beta.7", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-core": "3.6.0-beta.7", "@vue/compiler-dom": "3.6.0-beta.7", "@vue/compiler-ssr": "3.6.0-beta.7", "@vue/compiler-vapor": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-bf0NkJb0Hxoj1K8cZKYgduEY0FPP28WnoUGqHvYA/a1cjJfrhaypbiS5u6pEFVXug/JZJF9sI+c4JTHkgqRKDw=="],
"@vue/compiler-sfc": ["@vue/compiler-sfc@3.6.0-beta.9", "", { "dependencies": { "@babel/parser": "^7.29.2", "@vue/compiler-core": "3.6.0-beta.9", "@vue/compiler-dom": "3.6.0-beta.9", "@vue/compiler-ssr": "3.6.0-beta.9", "@vue/compiler-vapor": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.8", "source-map-js": "^1.2.1" } }, "sha512-13MwFqrIN+AFxR5uT88WYaMTxXycpNNI75sIllz5blXbFaBsDfiegQZj10Pj5G3cgH7WFy2Trs1rTlXrmSgG/w=="],
"@vue/compiler-ssr": ["@vue/compiler-ssr@3.6.0-beta.7", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7" } }, "sha512-fwO4qe6iXZ+SZedurh/vLwjBgjAX/wL5aI/eIECv0C79AgTAlJNjD6dwMafukhnZamQgNKYBxXUOkGl8sqn1PA=="],
"@vue/compiler-ssr": ["@vue/compiler-ssr@3.6.0-beta.9", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9" } }, "sha512-ufzHVMJoMz7QzMFop03a8KpWAWUh4hiof/tJXvxiDClIFUY7P5OrKk644fV9qlWgTP7V+eQvA7kVSEVRUgYjvA=="],
"@vue/compiler-vapor": ["@vue/compiler-vapor@3.6.0-beta.7", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-dom": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-fc6ZAFv9yRSoQQVsgN5gGDaUWdTPctDb6lVUtUGgnrCB7n+hQIBwuId7HIeic3PK6HPVZMoEbluNU/ge3DIveA=="],
"@vue/compiler-vapor": ["@vue/compiler-vapor@3.6.0-beta.9", "", { "dependencies": { "@babel/parser": "^7.29.2", "@vue/compiler-dom": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-1WWCcRjkH/scYJ8dsjNp8+NDf4f9SwQgOcd4Hbl5p0srNPflqrQYvAaJh4N2Szxj5FdkXw2t5uiK35TpFM5uKA=="],
"@vue/devtools-api": ["@vue/devtools-api@7.7.9", "", { "dependencies": { "@vue/devtools-kit": "^7.7.9" } }, "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g=="],
"@vue/devtools-core": ["@vue/devtools-core@8.0.7", "", { "dependencies": { "@vue/devtools-kit": "^8.0.7", "@vue/devtools-shared": "^8.0.7" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-PmpiPxvg3Of80ODHVvyckxwEW1Z02VIAvARIZS1xegINn3VuNQLm9iHUmKD+o6cLkMNWV8OG8x7zo0kgydZgdg=="],
"@vue/devtools-core": ["@vue/devtools-core@8.1.1", "", { "dependencies": { "@vue/devtools-kit": "^8.1.1", "@vue/devtools-shared": "^8.1.1" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-bCCsSABp1/ot4j8xJEycM6Mtt2wbuucfByr6hMgjbYhrtlscOJypZKvy8f1FyWLYrLTchB5Qz216Lm92wfbq0A=="],
"@vue/devtools-kit": ["@vue/devtools-kit@8.0.7", "", { "dependencies": { "@vue/devtools-shared": "^8.0.7", "birpc": "^2.6.1", "hookable": "^5.5.3", "perfect-debounce": "^2.0.0" } }, "sha512-H6esJGHGl5q0E9iV3m2EoBQHJ+V83WMW83A0/+Fn95eZ2iIvdsq4+UCS6yT/Fdd4cGZSchx/MdWDreM3WqMsDw=="],
"@vue/devtools-kit": ["@vue/devtools-kit@8.1.1", "", { "dependencies": { "@vue/devtools-shared": "^8.1.1", "birpc": "^2.6.1", "hookable": "^5.5.3", "perfect-debounce": "^2.0.0" } }, "sha512-gVBaBv++i+adg4JpH71k9ppl4soyR7Y2McEqO5YNgv0BI1kMZ7BDX5gnwkZ5COYgiCyhejZG+yGNrBAjj6Coqg=="],
"@vue/devtools-shared": ["@vue/devtools-shared@8.0.7", "", {}, "sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA=="],
"@vue/devtools-shared": ["@vue/devtools-shared@8.1.1", "", {}, "sha512-+h4ttmJYl/txpxHKaoZcaKpC+pvckgLzIDiSQlaQ7kKthKh8KuwoLW2D8hPJEnqKzXOvu15UHEoGyngAXCz0EQ=="],
"@vue/eslint-config-typescript": ["@vue/eslint-config-typescript@14.7.0", "", { "dependencies": { "@typescript-eslint/utils": "^8.56.0", "fast-glob": "^3.3.3", "typescript-eslint": "^8.56.0", "vue-eslint-parser": "^10.4.0" }, "peerDependencies": { "eslint": "^9.10.0 || ^10.0.0", "eslint-plugin-vue": "^9.28.0 || ^10.0.0", "typescript": ">=4.8.4" }, "optionalPeers": ["typescript"] }, "sha512-iegbMINVc+seZ/QxtzWiOBozctrHiF2WvGedruu2EbLujg9VuU0FQiNcN2z1ycuaoKKpF4m2qzB5HDEMKbxtIg=="],
"@vue/language-core": ["@vue/language-core@3.2.5", "", { "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" } }, "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g=="],
"@vue/language-core": ["@vue/language-core@3.2.6", "", { "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" } }, "sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg=="],
"@vue/reactivity": ["@vue/reactivity@3.6.0-beta.7", "", { "dependencies": { "@vue/shared": "3.6.0-beta.7" } }, "sha512-d1Z7U3QqfrpnT1/m8glRDBGlzQVj4J3u7LvCxieyxvrH03ZcR9qZ8hMw9x/Q3K/VcT2BSHp8A8662cqigCiCEA=="],
"@vue/reactivity": ["@vue/reactivity@3.6.0-beta.9", "", { "dependencies": { "@vue/shared": "3.6.0-beta.9" } }, "sha512-Mo0GjZB/q7LUJplPjBdKqAAk4mawkzvnk2nNf9CEetp4RQJP5/e/DdmgjYBsr/+UVX5ShasCalwdyknuuIepdw=="],
"@vue/runtime-core": ["@vue/runtime-core@3.6.0-beta.7", "", { "dependencies": { "@vue/reactivity": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7" } }, "sha512-z6wXT1w0lFYS2uHAYuNZRutxNmg5i4S6yKYVf58/DVu+j/L1eq2ntPNVpPJpof71izXbv14ImvvPUCTTqHwAUA=="],
"@vue/runtime-core": ["@vue/runtime-core@3.6.0-beta.9", "", { "dependencies": { "@vue/reactivity": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9" } }, "sha512-IPbO/cmw0BSHec17fSE8Mbtv0UFBiiiGhvlUGiJWTa/eOlbiO+mZ9/PRRUQ+v/tkKuwFSzKye7KOKj5aFO1dgQ=="],
"@vue/runtime-dom": ["@vue/runtime-dom@3.6.0-beta.7", "", { "dependencies": { "@vue/reactivity": "3.6.0-beta.7", "@vue/runtime-core": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7", "csstype": "^3.2.3" } }, "sha512-purk/iT3R5y2CizeV+YdxHhqPE1yAk3MSptggsCdO0zkShl2NA1/xec1WgVg1OL6IV0xNrknsMxl9Fit4g44hA=="],
"@vue/runtime-dom": ["@vue/runtime-dom@3.6.0-beta.9", "", { "dependencies": { "@vue/reactivity": "3.6.0-beta.9", "@vue/runtime-core": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9", "csstype": "^3.2.3" } }, "sha512-+WV0V1s/uf9iFwZt41lOtJHbIqKyYdEO+nmW0UOnQLjG9ELz6rKuZ92fEim6NPcKCsucv2BoB1mK9T82khYqgg=="],
"@vue/runtime-vapor": ["@vue/runtime-vapor@3.6.0-beta.7", "", { "dependencies": { "@vue/reactivity": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7" }, "peerDependencies": { "@vue/runtime-dom": "3.6.0-beta.7" } }, "sha512-H+XdbkqtBI+9gsS957Om94qpTx+keklzvO6rllls4TcKlRo/xcXsDnMhWjghX0Irg6iM/MgBBK8bQkfUkF+xSg=="],
"@vue/runtime-vapor": ["@vue/runtime-vapor@3.6.0-beta.9", "", { "dependencies": { "@vue/reactivity": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9" }, "peerDependencies": { "@vue/runtime-dom": "3.6.0-beta.9" } }, "sha512-UlAziGF77byUa84RgkIdCT4bleZbB4UvQvmxdGHFfscGylSABBZHAMR8WJIwBsy1MsZnlpRSSeDAYB20RicrhQ=="],
"@vue/server-renderer": ["@vue/server-renderer@3.6.0-beta.7", "", { "dependencies": { "@vue/compiler-ssr": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7" }, "peerDependencies": { "vue": "3.6.0-beta.7" } }, "sha512-VqX6+8+NyCC/nqkOvj/vKHeMtBr3Mxo7rccDLNyuSb6o5Mp+itlxdpaD0LD28SqHEaDjqfIUBTnFsfDJLN/cww=="],
"@vue/server-renderer": ["@vue/server-renderer@3.6.0-beta.9", "", { "dependencies": { "@vue/compiler-ssr": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9" }, "peerDependencies": { "vue": "3.6.0-beta.9" } }, "sha512-qyz37g6pmwHvtXbe7CWKm5+VTmCs4mHrC1uDw4OVZlvwDDZb9pWMzW0kOrzhj1iI6sZ4D9k5fYQIdzBqB7aOqw=="],
"@vue/shared": ["@vue/shared@3.6.0-beta.7", "", {}, "sha512-BNC0ohwv5hYybiUvZ/7gBjSzWFRxpZ2MzRQ/lH2zYZds085ylmAqMGEwbGlWFD+/WPRBsXQd7+e1hNGFksNuCg=="],
"@vue/shared": ["@vue/shared@3.6.0-beta.9", "", {}, "sha512-nY6DXeelJsmveeNk5YZYGd8q0ulWXACL8Qs/qvkPC4HQkyhPgf+Ja00AkG2hYsEI8Uixia2UpQl4CbObzw0hag=="],
"@vue/tsconfig": ["@vue/tsconfig@0.8.1", "", { "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" }, "optionalPeers": ["typescript", "vue"] }, "sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g=="],
@@ -580,23 +580,23 @@
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="],
"birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="],
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
"brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="],
"brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
"browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="],
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
"c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="],
"caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001784", "", {}, "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw=="],
"chart.js": ["chart.js@4.5.1", "", { "dependencies": { "@kurkle/color": "^0.3.0" } }, "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw=="],
@@ -646,7 +646,7 @@
"dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
"electron-to-chromium": ["electron-to-chromium@1.5.307", "", {}, "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg=="],
"electron-to-chromium": ["electron-to-chromium@1.5.330", "", {}, "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA=="],
"embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="],
@@ -666,7 +666,7 @@
"embla-carousel-wheel-gestures": ["embla-carousel-wheel-gestures@8.1.0", "", { "dependencies": { "wheel-gestures": "^2.2.5" }, "peerDependencies": { "embla-carousel": "^8.0.0 || ~8.0.0-rc03" } }, "sha512-J68jkYrxbWDmXOm2n2YHl+uMEXzkGSKjWmjaEgL9xVvPb3HqVmg6rJSKfI3sqIDVvm7mkeTy87wtG/5263XqHQ=="],
"enhanced-resolve": ["enhanced-resolve@5.20.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ=="],
"enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="],
"entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
@@ -674,13 +674,13 @@
"errx": ["errx@0.1.0", "", {}, "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q=="],
"esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
"esbuild": ["esbuild@0.27.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.4", "@esbuild/android-arm": "0.27.4", "@esbuild/android-arm64": "0.27.4", "@esbuild/android-x64": "0.27.4", "@esbuild/darwin-arm64": "0.27.4", "@esbuild/darwin-x64": "0.27.4", "@esbuild/freebsd-arm64": "0.27.4", "@esbuild/freebsd-x64": "0.27.4", "@esbuild/linux-arm": "0.27.4", "@esbuild/linux-arm64": "0.27.4", "@esbuild/linux-ia32": "0.27.4", "@esbuild/linux-loong64": "0.27.4", "@esbuild/linux-mips64el": "0.27.4", "@esbuild/linux-ppc64": "0.27.4", "@esbuild/linux-riscv64": "0.27.4", "@esbuild/linux-s390x": "0.27.4", "@esbuild/linux-x64": "0.27.4", "@esbuild/netbsd-arm64": "0.27.4", "@esbuild/netbsd-x64": "0.27.4", "@esbuild/openbsd-arm64": "0.27.4", "@esbuild/openbsd-x64": "0.27.4", "@esbuild/openharmony-arm64": "0.27.4", "@esbuild/sunos-x64": "0.27.4", "@esbuild/win32-arm64": "0.27.4", "@esbuild/win32-ia32": "0.27.4", "@esbuild/win32-x64": "0.27.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@10.0.3", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.3", "@eslint/config-helpers": "^0.5.2", "@eslint/core": "^1.1.1", "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.1.1", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ=="],
"eslint": ["eslint@10.1.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.3", "@eslint/config-helpers": "^0.5.3", "@eslint/core": "^1.1.1", "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA=="],
"eslint-plugin-vue": ["eslint-plugin-vue@10.8.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", "postcss-selector-parser": "^7.1.0", "semver": "^7.6.3", "xml-name-validator": "^4.0.0" }, "peerDependencies": { "@stylistic/eslint-plugin": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "vue-eslint-parser": "^10.0.0" }, "optionalPeers": ["@stylistic/eslint-plugin", "@typescript-eslint/parser"] }, "sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA=="],
@@ -724,7 +724,7 @@
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.4.1", "", {}, "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ=="],
"flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="],
"fontaine": ["fontaine@0.8.0", "", { "dependencies": { "@capsizecss/unpack": "^4.0.0", "css-tree": "^3.1.0", "magic-regexp": "^0.10.0", "magic-string": "^0.30.21", "pathe": "^2.0.3", "ufo": "^1.6.1", "unplugin": "^2.3.10" } }, "sha512-eek1GbzOdWIj9FyQH/emqW1aEdfC3lYRCHepzwlFCm5T77fBSRSyNRKE6/antF1/B1M+SfJXVRQTY9GAr7lnDg=="],
@@ -732,7 +732,7 @@
"fontless": ["fontless@0.2.1", "", { "dependencies": { "consola": "^3.4.2", "css-tree": "^3.1.0", "defu": "^6.1.4", "esbuild": "^0.27.0", "fontaine": "0.8.0", "jiti": "^2.6.1", "lightningcss": "^1.30.2", "magic-string": "^0.30.21", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1", "unifont": "^0.7.4", "unstorage": "^1.17.1" }, "peerDependencies": { "vite": "*" }, "optionalPeers": ["vite"] }, "sha512-mUWZ8w91/mw2KEcZ6gHNoNNmsAq9Wiw2IypIux5lM03nhXm+WSloXGUNuRETNTLqZexMgpt7Aj/v63qqrsWraQ=="],
"framer-motion": ["framer-motion@12.35.2", "", { "dependencies": { "motion-dom": "^12.35.2", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-dhfuEMaNo0hc+AEqyHiIfiJRNb9U9UQutE9FoKm5pjf7CMitp9xPEF1iWZihR1q86LBmo6EJ7S8cN8QXEy49AA=="],
"framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
@@ -748,11 +748,11 @@
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"h3": ["h3@1.15.6", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-oi15ESLW5LRthZ+qPCi5GNasY/gvynSKUQxgiovrY63bPAtG59wtM+LSrlcwvOHAXzGrXVLnI97brbkdPF9WoQ=="],
"h3": ["h3@1.15.10", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-YzJeWSkDZxAhvmp8dexjRK5hxziRO7I9m0N53WhvYL5NiWfkUkzssVzY9jvGu0HBoLFW6+duYmNSn6MaZBCCtg=="],
"hey-listen": ["hey-listen@1.0.8", "", {}, "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="],
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"hookable": ["hookable@6.1.0", "", {}, "sha512-ZoKZSJgu8voGK2geJS+6YtYjvIzu9AOM/KZXsBxr83uhLL++e9pEv/dlgwgy3dvHg06kTz6JOh1hk3C8Ceiymw=="],
"human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
@@ -842,7 +842,7 @@
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="],
"lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="],
"magic-regexp": ["magic-regexp@0.10.0", "", { "dependencies": { "estree-walker": "^3.0.3", "magic-string": "^0.30.12", "mlly": "^1.7.2", "regexp-tree": "^0.1.27", "type-level-regexp": "~0.1.17", "ufo": "^1.5.4", "unplugin": "^2.0.0" } }, "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg=="],
@@ -852,7 +852,7 @@
"markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="],
"marked": ["marked@17.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ=="],
"marked": ["marked@17.0.5", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-6hLvc0/JEbRjRgzI6wnT2P1XuM1/RrrDEX0kPt0N7jGm1133g6X7DlxFasUIx+72aKAr904GTxhSLDrd5DIlZg=="],
"mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="],
@@ -868,17 +868,17 @@
"mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
"minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
"minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
"mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
"mlly": ["mlly@1.8.1", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ=="],
"mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="],
"motion-dom": ["motion-dom@12.35.2", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-pWXFMTwvGDbx1Fe9YL5HZebv2NhvGBzRtiNUv58aoK7+XrsuaydQ0JGRKK2r+bTKlwgSWwWxHbP5249Qr/BNpg=="],
"motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="],
"motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="],
"motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="],
"motion-v": ["motion-v@1.10.3", "", { "dependencies": { "framer-motion": "^12.25.0", "hey-listen": "^1.0.8", "motion-dom": "^12.23.23" }, "peerDependencies": { "@vueuse/core": ">=10.0.0", "vue": ">=3.0.0" } }, "sha512-9Ewo/wwGv7FO3PqYJpllBF/Efc7tbeM1iinVrM73s0RUQrnXHwMZCaRX98u4lu0PQCrZghPPfCsQ14pWKIEbnQ=="],
"motion-v": ["motion-v@2.2.0", "", { "dependencies": { "framer-motion": "^12.38.0", "hey-listen": "^1.0.8", "motion-dom": "^12.38.0", "motion-utils": "^12.36.0" }, "peerDependencies": { "@vueuse/core": ">=10.0.0", "vue": ">=3.0.0" } }, "sha512-8rrUBt9UMwy45MfLMwHer9J7xBY/rL31S+0U3ZUAouqjH3AOVHvS0NGuXwF4mfWfvb22rfZEv59ZsBc2f1epxQ=="],
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
@@ -942,7 +942,7 @@
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
"pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="],
@@ -990,9 +990,9 @@
"prosemirror-trailing-node": ["prosemirror-trailing-node@3.0.0", "", { "dependencies": { "@remirror/core-constants": "3.0.0", "escape-string-regexp": "^4.0.0" }, "peerDependencies": { "prosemirror-model": "^1.22.1", "prosemirror-state": "^1.4.2", "prosemirror-view": "^1.33.8" } }, "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ=="],
"prosemirror-transform": ["prosemirror-transform@1.11.0", "", { "dependencies": { "prosemirror-model": "^1.21.0" } }, "sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw=="],
"prosemirror-transform": ["prosemirror-transform@1.12.0", "", { "dependencies": { "prosemirror-model": "^1.21.0" } }, "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w=="],
"prosemirror-view": ["prosemirror-view@1.41.6", "", { "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0" } }, "sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg=="],
"prosemirror-view": ["prosemirror-view@1.41.7", "", { "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0" } }, "sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
@@ -1012,7 +1012,7 @@
"regexp-tree": ["regexp-tree@0.1.27", "", { "bin": { "regexp-tree": "bin/regexp-tree" } }, "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA=="],
"reka-ui": ["reka-ui@2.8.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^14.1.0", "@vueuse/shared": "^14.1.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.2.0" } }, "sha512-8lTKcJhmG+D3UyJxhBnNnW/720sLzm0pbA9AC1MWazmJ5YchJAyTSl+O00xP/kxBmEN0fw5JqWVHguiFmsGjzA=="],
"reka-ui": ["reka-ui@2.9.3", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^14.1.0", "@vueuse/shared": "^14.1.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.4.0" } }, "sha512-C9lCVxsSC7uYD0Nbgik1+14FNndHNprZmf0zGQt0ZDYIt5KxXV3zD0hEqNcfRUsEEJvVmoRsUkJnASBVBeaaUw=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
@@ -1056,13 +1056,13 @@
"tailwind-variants": ["tailwind-variants@3.2.2", "", { "peerDependencies": { "tailwind-merge": ">=3.0.0", "tailwindcss": "*" }, "optionalPeers": ["tailwind-merge"] }, "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg=="],
"tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="],
"tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="],
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
"tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="],
"tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
"tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
"tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
@@ -1070,7 +1070,7 @@
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
"ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
"ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
@@ -1080,7 +1080,7 @@
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-eslint": ["typescript-eslint@8.57.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.57.0", "@typescript-eslint/parser": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA=="],
"typescript-eslint": ["typescript-eslint@8.58.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.58.0", "@typescript-eslint/parser": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0", "@typescript-eslint/utils": "8.58.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA=="],
"uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="],
@@ -1104,9 +1104,9 @@
"unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
"unplugin-vue-components": ["unplugin-vue-components@31.0.0", "", { "dependencies": { "chokidar": "^5.0.0", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "obug": "^2.1.1", "picomatch": "^4.0.3", "tinyglobby": "^0.2.15", "unplugin": "^2.3.11", "unplugin-utils": "^0.3.1" }, "peerDependencies": { "@nuxt/kit": "^3.2.2 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@nuxt/kit"] }, "sha512-4ULwfTZTLuWJ7+S9P7TrcStYLsSRkk6vy2jt/WTfgUEUb0nW9//xxmrfhyHUEVpZ2UKRRwfRb8Yy15PDbVZf+Q=="],
"unplugin-vue-components": ["unplugin-vue-components@31.1.0", "", { "dependencies": { "chokidar": "^5.0.0", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.2", "obug": "^2.1.1", "picomatch": "^4.0.3", "tinyglobby": "^0.2.15", "unplugin": "^2.3.11", "unplugin-utils": "^0.3.1" }, "peerDependencies": { "@nuxt/kit": "^3.2.2 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@nuxt/kit"] }, "sha512-9EbV5ark21A4BOBt6RJGJXCVD2I1eoxTZL1TAvNgYTokcrFIiuxpufb8owyWn7n+z2x8daz/ltZq6IRRKL3ydQ=="],
"unstorage": ["unstorage@1.17.4", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.5", "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw=="],
"unstorage": ["unstorage@1.17.5", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.10", "lru-cache": "^11.2.7", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg=="],
"untyped": ["untyped@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "defu": "^6.1.4", "jiti": "^2.4.2", "knitwork": "^1.2.0", "scule": "^1.3.0" }, "bin": { "untyped": "dist/cli.mjs" } }, "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g=="],
@@ -1126,17 +1126,17 @@
"vite-plugin-inspect": ["vite-plugin-inspect@11.3.3", "", { "dependencies": { "ansis": "^4.1.0", "debug": "^4.4.1", "error-stack-parser-es": "^1.0.5", "ohash": "^2.0.11", "open": "^10.2.0", "perfect-debounce": "^2.0.0", "sirv": "^3.0.1", "unplugin-utils": "^0.3.0", "vite-dev-rpc": "^1.1.0" }, "peerDependencies": { "vite": "^6.0.0 || ^7.0.0-0" } }, "sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA=="],
"vite-plugin-vue-devtools": ["vite-plugin-vue-devtools@8.0.7", "", { "dependencies": { "@vue/devtools-core": "^8.0.7", "@vue/devtools-kit": "^8.0.7", "@vue/devtools-shared": "^8.0.7", "sirv": "^3.0.2", "vite-plugin-inspect": "^11.3.3", "vite-plugin-vue-inspector": "^5.3.2" }, "peerDependencies": { "vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0" } }, "sha512-BWj/ykGpqVAJVdPyHmSTUm44buz3jPv+6jnvuFdQSRH0kAgP1cEIE4doHiFyqHXOmuB5EQVR/nh2g9YRiRNs9g=="],
"vite-plugin-vue-devtools": ["vite-plugin-vue-devtools@8.1.1", "", { "dependencies": { "@vue/devtools-core": "^8.1.1", "@vue/devtools-kit": "^8.1.1", "@vue/devtools-shared": "^8.1.1", "sirv": "^3.0.2", "vite-plugin-inspect": "^11.3.3", "vite-plugin-vue-inspector": "^5.3.2" }, "peerDependencies": { "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-9qTpOmZ2vHpvlI9hdVXAQ1Ry4I8GcBArU7aPi0qfIaV7fQIXy0L1nb6X4mFY2Gw0dYshHuLbIl0Ulb572SCjsQ=="],
"vite-plugin-vue-inspector": ["vite-plugin-vue-inspector@5.3.2", "", { "dependencies": { "@babel/core": "^7.23.0", "@babel/plugin-proposal-decorators": "^7.23.0", "@babel/plugin-syntax-import-attributes": "^7.22.5", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-transform-typescript": "^7.22.15", "@vue/babel-plugin-jsx": "^1.1.5", "@vue/compiler-dom": "^3.3.4", "kolorist": "^1.8.0", "magic-string": "^0.30.4" }, "peerDependencies": { "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0" } }, "sha512-YvEKooQcSiBTAs0DoYLfefNja9bLgkFM7NI2b07bE2SruuvX0MEa9cMaxjKVMkeCp5Nz9FRIdcN1rOdFVBeL6Q=="],
"vite-plugin-vue-inspector": ["vite-plugin-vue-inspector@5.4.0", "", { "dependencies": { "@babel/core": "^7.23.0", "@babel/plugin-proposal-decorators": "^7.23.0", "@babel/plugin-syntax-import-attributes": "^7.22.5", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-transform-typescript": "^7.22.15", "@vue/babel-plugin-jsx": "^1.1.5", "@vue/compiler-dom": "^3.3.4", "kolorist": "^1.8.0", "magic-string": "^0.30.4" }, "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-Iq/024CydcE46FZqWPU4t4lw4uYOdLnFSO1RNxJVt2qY9zxIjmnkBqhHnYaReWM82kmNnaXs7OkfgRrV2GEjyw=="],
"vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
"vue": ["vue@3.6.0-beta.7", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-beta.7", "@vue/compiler-sfc": "3.6.0-beta.7", "@vue/runtime-dom": "3.6.0-beta.7", "@vue/runtime-vapor": "3.6.0-beta.7", "@vue/server-renderer": "3.6.0-beta.7", "@vue/shared": "3.6.0-beta.7" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-SlNdNG+c37xycRFIJ/KB9CmpZmWwKovbDTNl00ck0+ZSNZSgb+n6DKLuXtVvGZImNPu6jj+zzaM1gqNB5NeC6Q=="],
"vue": ["vue@3.6.0-beta.9", "", { "dependencies": { "@vue/compiler-dom": "3.6.0-beta.9", "@vue/compiler-sfc": "3.6.0-beta.9", "@vue/runtime-dom": "3.6.0-beta.9", "@vue/runtime-vapor": "3.6.0-beta.9", "@vue/server-renderer": "3.6.0-beta.9", "@vue/shared": "3.6.0-beta.9" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-K/+HT52OAZvaNDDMvT+Lfk36e/97PsyJyDWXM0FDfLQKGbEDXsd4pSQz+BJViGssLcltQLSTlSqQlZ6fkGo5CA=="],
"vue-chartjs": ["vue-chartjs@5.3.3", "", { "peerDependencies": { "chart.js": "^4.1.1", "vue": "^3.0.0-0 || ^2.7.0" } }, "sha512-jqxtL8KZ6YJ5NTv6XzrzLS7osyegOi28UGNZW0h9OkDL7Sh1396ht4Dorh04aKrl2LiSalQ84WtqiG0RIJb0tA=="],
"vue-component-type-helpers": ["vue-component-type-helpers@3.2.5", "", {}, "sha512-tkvNr+bU8+xD/onAThIe7CHFvOJ/BO6XCOrxMzeytJq40nTfpGDJuVjyCM8ccGZKfAbGk2YfuZyDMXM56qheZQ=="],
"vue-component-type-helpers": ["vue-component-type-helpers@3.2.6", "", {}, "sha512-O02tnvIfOQVmnvoWwuSydwRoHjZVt8UEBR+2p4rT35p8GAy5VTlWP8o5qXfJR/GWCN0nVZoYWsVUvx2jwgdBmQ=="],
"vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
@@ -1144,9 +1144,9 @@
"vue-i18n": ["vue-i18n@11.3.0", "", { "dependencies": { "@intlify/core-base": "11.3.0", "@intlify/devtools-types": "11.3.0", "@intlify/shared": "11.3.0", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-1J+xDfDJTLhDxElkd3+XUhT7FYSZd2b8pa7IRKGxhWH/8yt6PTvi3xmWhGwhYT5EaXdatui11pF2R6tL73/zPA=="],
"vue-router": ["vue-router@5.0.3", "", { "dependencies": { "@babel/generator": "^7.28.6", "@vue-macros/common": "^3.1.1", "@vue/devtools-api": "^8.0.6", "ast-walker-scope": "^0.8.3", "chokidar": "^5.0.0", "json5": "^2.2.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "muggle-string": "^0.4.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "scule": "^1.3.0", "tinyglobby": "^0.2.15", "unplugin": "^3.0.0", "unplugin-utils": "^0.3.1", "yaml": "^2.8.2" }, "peerDependencies": { "@pinia/colada": ">=0.21.2", "@vue/compiler-sfc": "^3.5.17", "pinia": "^3.0.4", "vue": "^3.5.0" }, "optionalPeers": ["@pinia/colada", "@vue/compiler-sfc", "pinia"] }, "sha512-nG1c7aAFac7NYj8Hluo68WyWfc41xkEjaR0ViLHCa3oDvTQ/nIuLJlXJX1NUPw/DXzx/8+OKMng045HHQKQKWw=="],
"vue-router": ["vue-router@5.0.4", "", { "dependencies": { "@babel/generator": "^7.28.6", "@vue-macros/common": "^3.1.1", "@vue/devtools-api": "^8.0.6", "ast-walker-scope": "^0.8.3", "chokidar": "^5.0.0", "json5": "^2.2.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "muggle-string": "^0.4.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "scule": "^1.3.0", "tinyglobby": "^0.2.15", "unplugin": "^3.0.0", "unplugin-utils": "^0.3.1", "yaml": "^2.8.2" }, "peerDependencies": { "@pinia/colada": ">=0.21.2", "@vue/compiler-sfc": "^3.5.17", "pinia": "^3.0.4", "vue": "^3.5.0" }, "optionalPeers": ["@pinia/colada", "@vue/compiler-sfc", "pinia"] }, "sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg=="],
"vue-tsc": ["vue-tsc@3.2.5", "", { "dependencies": { "@volar/typescript": "2.4.28", "@vue/language-core": "3.2.5" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "bin/vue-tsc.js" } }, "sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA=="],
"vue-tsc": ["vue-tsc@3.2.6", "", { "dependencies": { "@volar/typescript": "2.4.28", "@vue/language-core": "3.2.6" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "bin/vue-tsc.js" } }, "sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q=="],
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
@@ -1166,9 +1166,9 @@
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
"yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="],
"yjs": ["yjs@13.6.29", "", { "dependencies": { "lib0": "^0.2.99" } }, "sha512-kHqDPdltoXH+X4w1lVmMtddE3Oeqq48nM40FD5ojTd8xYhQpzIDcfE2keMSU5bAgRPJBe225WTUdyUgj1DtbiQ=="],
"yjs": ["yjs@13.6.30", "", { "dependencies": { "lib0": "^0.2.99" } }, "sha512-vv/9h42eCMC81ZHDFswuu/MKzkl/vyq1BhaNGfHyOonwlG4CJbQF4oiBBJPvfdeCt/PlVDWh7Nov9D34YY09uQ=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
@@ -1184,21 +1184,23 @@
"@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@nuxtjs/color-mode/@nuxt/kit": ["@nuxt/kit@3.21.1", "", { "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.8", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.3.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^3.0.0", "scule": "^1.3.0", "semver": "^7.7.4", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unctx": "^2.5.0", "untyped": "^2.0.0" } }, "sha512-QORZRjcuTKgo++XP1Pc2c2gqwRydkaExrIRfRI9vFsPA3AzuHVn5Gfmbv1ic8y34e78mr5DMBvJlelUaeOuajg=="],
"@nuxt/schema/std-env": ["std-env@4.0.0", "", {}, "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ=="],
"@nuxt/ui/reka-ui": ["reka-ui@2.9.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^14.1.0", "@vueuse/shared": "^14.1.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.4.0" } }, "sha512-/t4e6y1hcG+uDuRfpg6tbMz3uUEvRzNco6NeYTufoJeUghy5Iosxos5YL/p+ieAsid84sdMX9OrgDqpEuCJhBw=="],
"@nuxtjs/color-mode/@nuxt/kit": ["@nuxt/kit@3.21.2", "", { "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.8", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.3.0", "mlly": "^1.8.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^3.0.0", "scule": "^1.3.0", "semver": "^7.7.4", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unctx": "^2.5.0", "untyped": "^2.0.0" } }, "sha512-Bd6m6mrDrqpBEbX+g0rc66/ALd1sxlgdx5nfK9MAYO0yKLTOSK7McSYz1KcOYn3LQFCXOWfvXwaqih/b+REI1g=="],
"@nuxtjs/color-mode/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"@nuxtjs/color-mode/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
"@tailwindcss/node/lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="],
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
@@ -1206,11 +1208,11 @@
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@unhead/vue/hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="],
"@vue/devtools-api/@vue/devtools-kit": ["@vue/devtools-kit@7.7.9", "", { "dependencies": { "@vue/devtools-shared": "^7.7.9", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA=="],
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"@vue/devtools-kit/hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
"c12/rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
@@ -1226,7 +1228,7 @@
"markdown-it/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
@@ -1242,8 +1244,6 @@
"unctx/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unhead/hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="],
"unimport/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"unimport/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
@@ -1256,9 +1256,11 @@
"vaul-vue/@vueuse/core": ["@vueuse/core@10.11.1", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "10.11.1", "@vueuse/shared": "10.11.1", "vue-demi": ">=0.14.8" } }, "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww=="],
"vaul-vue/reka-ui": ["reka-ui@2.9.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^14.1.0", "@vueuse/shared": "^14.1.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.4.0" } }, "sha512-/t4e6y1hcG+uDuRfpg6tbMz3uUEvRzNco6NeYTufoJeUghy5Iosxos5YL/p+ieAsid84sdMX9OrgDqpEuCJhBw=="],
"vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
"vue-router/@vue/devtools-api": ["@vue/devtools-api@8.0.7", "", { "dependencies": { "@vue/devtools-kit": "^8.0.7" } }, "sha512-tc1TXAxclsn55JblLkFVcIRG7MeSJC4fWsPjfM7qu/IcmPUYnQ5Q8vzWwBpyDY24ZjmZTUCCwjRSNbx58IhlAA=="],
"vue-router/@vue/devtools-api": ["@vue/devtools-api@8.1.1", "", { "dependencies": { "@vue/devtools-kit": "^8.1.1" } }, "sha512-bsDMJ07b3GN1puVwJb/fyFnj/U2imyswK5UQVLZwVl7O05jDrt6BHxeG5XffmOOdasOj/bOmIjxJvGPxU7pcqw=="],
"@nuxtjs/color-mode/@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
@@ -1270,30 +1272,10 @@
"@nuxtjs/color-mode/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"@tailwindcss/node/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
"@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
"@tailwindcss/node/lightningcss/lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
"@tailwindcss/node/lightningcss/lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
"@tailwindcss/node/lightningcss/lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
"@tailwindcss/node/lightningcss/lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
"@tailwindcss/node/lightningcss/lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
"@tailwindcss/node/lightningcss/lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
"@tailwindcss/node/lightningcss/lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
"@tailwindcss/node/lightningcss/lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
"@tailwindcss/node/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
"@vue/devtools-api/@vue/devtools-kit/@vue/devtools-shared": ["@vue/devtools-shared@7.7.9", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA=="],
"@vue/devtools-api/@vue/devtools-kit/hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"@vue/devtools-api/@vue/devtools-kit/perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
@@ -1305,5 +1287,7 @@
"vaul-vue/@vueuse/core/@vueuse/metadata": ["@vueuse/metadata@10.11.1", "", {}, "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw=="],
"vaul-vue/@vueuse/core/@vueuse/shared": ["@vueuse/shared@10.11.1", "", { "dependencies": { "vue-demi": ">=0.14.8" } }, "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA=="],
"vaul-vue/reka-ui/@vueuse/core": ["@vueuse/core@14.2.1", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.2.1", "@vueuse/shared": "14.2.1" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ=="],
}
}

23
bo/components.d.ts vendored
View File

@@ -12,12 +12,15 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
CartDetails: typeof import('./src/components/customer/CartDetails.vue')['default']
CategoryMenu: typeof import('./src/components/inner/categoryMenu.vue')['default']
CategoryMenu: typeof import('./src/components/inner/CategoryMenu.vue')['default']
copy: typeof import('./src/components/admin/ProductDetailView copy.vue')['default']
CountryCurrencySwitch: typeof import('./src/components/inner/CountryCurrencySwitch.vue')['default']
Cs_PrivacyPolicyView: typeof import('./src/components/terms/cs_PrivacyPolicyView.vue')['default']
Cs_TermsAndConditionsView: typeof import('./src/components/terms/cs_TermsAndConditionsView.vue')['default']
En_PrivacyPolicyView: typeof import('./src/components/terms/en_PrivacyPolicyView.vue')['default']
En_TermsAndConditionsView: typeof import('./src/components/terms/en_TermsAndConditionsView.vue')['default']
LangSwitch: typeof import('./src/components/inner/langSwitch.vue')['default']
FavoriteProducts: typeof import('./src/components/admin/FavoriteProducts.vue')['default']
LangSwitch: typeof import('./src/components/inner/LangSwitch.vue')['default']
PageAddresses: typeof import('./src/components/customer/PageAddresses.vue')['default']
PageCarts: typeof import('./src/components/customer/PageCarts.vue')['default']
PageOrders: typeof import('./src/components/customer/PageOrders.vue')['default']
@@ -30,17 +33,25 @@ declare module 'vue' {
Pl_TermsAndConditionsView: typeof import('./src/components/terms/pl_TermsAndConditionsView.vue')['default']
ProductCustomization: typeof import('./src/components/customer/components/ProductCustomization.vue')['default']
ProductDetailView: typeof import('./src/components/admin/ProductDetailView.vue')['default']
'ProductDetailView copy': typeof import('./src/components/admin/ProductDetailView copy.vue')['default']
ProductEditor: typeof import('./src/components/inner/ProductEditor.vue')['default']
ProductVariants: typeof import('./src/components/customer/components/ProductVariants.vue')['default']
Profile: typeof import('./src/components/customer-management/Profile.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ThemeSwitch: typeof import('./src/components/inner/themeSwitch.vue')['default']
StorageFileBrowser: typeof import('./src/components/customer/StorageFileBrowser.vue')['default']
ThemeSwitch: typeof import('./src/components/inner/ThemeSwitch.vue')['default']
TopBar: typeof import('./src/components/TopBar.vue')['default']
TopBarLogin: typeof import('./src/components/TopBarLogin.vue')['default']
UAlert: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Alert.vue')['default']
UApp: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/App.vue')['default']
UButton: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Button.vue')['default']
UCard: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Card.vue')['default']
UCheckbox: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Checkbox.vue')['default']
UDrawer: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Drawer.vue')['default']
UDropdownMenu: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/DropdownMenu.vue')['default']
UEditor: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Editor.vue')['default']
UEditorToolbar: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/EditorToolbar.vue')['default']
UForm: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Form.vue')['default']
UFormField: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/FormField.vue')['default']
UIcon: typeof import('./node_modules/@nuxt/ui/dist/runtime/vue/components/Icon.vue')['default']
@@ -51,6 +62,12 @@ declare module 'vue' {
UPagination: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Pagination.vue')['default']
USelect: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Select.vue')['default']
USelectMenu: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/SelectMenu.vue')['default']
UsersList: typeof import('./src/components/admin/UsersList.vue')['default']
UsersSearch: typeof import('./src/components/admin/UsersSearch.vue')['default']
USidebar: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Sidebar.vue')['default']
UTable: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Table.vue')['default']
UTabs: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Tabs.vue')['default']
UTextarea: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Textarea.vue')['default']
UTree: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Tree.vue')['default']
}
}

View File

@@ -13,21 +13,22 @@
"format": "prettier --write --experimental-cli src/"
},
"dependencies": {
"@nuxt/ui": "^4.5.0",
"@tailwindcss/vite": "^4.2.0",
"@nuxt/ui": "^4.6.0",
"@tailwindcss/vite": "^4.2.2",
"chart.js": "^4.5.1",
"pinia": "^3.0.4",
"tailwindcss": "^4.2.0",
"reka-ui": "^2.9.3",
"tailwindcss": "^4.2.2",
"vue": "beta",
"vue-chartjs": "^5.3.3",
"vue-i18n": "11",
"vue-router": "^5.0.2"
"vue-i18n": "^11.3.0",
"vue-router": "^5.0.4"
},
"devDependencies": {
"@tsconfig/node24": "^24.0.4",
"@types/node": "^24.10.13",
"@vitejs/plugin-vue": "^6.0.4",
"@vue/eslint-config-typescript": "^14.6.0",
"@types/node": "^24.12.0",
"@vitejs/plugin-vue": "^6.0.5",
"@vue/eslint-config-typescript": "^14.7.0",
"@vue/tsconfig": "^0.8.1",
"jiti": "^2.6.1",
"npm-run-all2": "^8.0.4",
@@ -35,8 +36,8 @@
"prettier": "3.8.1",
"typescript": "~5.9.3",
"vite": "beta",
"vite-plugin-vue-devtools": "^8.0.6",
"vue-tsc": "^3.2.4"
"vite-plugin-vue-devtools": "^8.1.1",
"vue-tsc": "^3.2.6"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"

View File

@@ -1,9 +1,27 @@
<script setup lang="ts">
import { RouterView } from 'vue-router'
import { computed } from 'vue'
import { TooltipProvider } from 'reka-ui'
import { RouterView, useRoute } from 'vue-router'
import DefaultLayout from '@/layouts/default.vue'
import EmptyLayout from '@/layouts/empty.vue'
import ManagementLayout from '@/layouts/management.vue'
import { useAuthStore } from './stores/customer/auth'
const authStore = useAuthStore()
const route = useRoute()
const layout = computed(() => (route.meta.layout as string) || 'default')
</script>
<template>
<Suspense>
<RouterView />
<TooltipProvider>
<component :is="layout === 'empty' ? EmptyLayout : layout === 'management' ? ManagementLayout : DefaultLayout">
<RouterView v-slot="{ Component }">
<component :is="Component" />
</RouterView>
</component>
</TooltipProvider>
</Suspense>
</template>

View File

@@ -8,9 +8,6 @@ export const uiOptions: NuxtUIOptions = {
}
},
button: {
slots: {
base: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0!',
},
},
input: {
slots: {
@@ -40,16 +37,17 @@ export const uiOptions: NuxtUIOptions = {
},
selectMenu: {
slots: {
base: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0!',
content: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! z-80 text-(--black)! dark:text-white!',
itemLeadingIcon: 'text-(--black)! dark:text-white!'
// base: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0!',
// content: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! z-80',
// content: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! z-80 text-(--black)! dark:text-white!',
// itemLeadingIcon: 'text-(--black)! dark:text-white!'
}
},
table: {
slots: {
base: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! bg-(--second-light) dark:bg-(--main-dark)',
tr: 'border-b! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! text-(--black)! dark:text-white!',
// tr: 'border-b! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! text-(--black)! dark:text-white!',
}
},
@@ -58,6 +56,11 @@ export const uiOptions: NuxtUIOptions = {
content: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! bg-(--second-light) dark:bg-(--main-dark)',
}
},
textarea: {
slots: {
base: 'ring-0! outline-0! rounded-md border border-(--border-light)! dark:border-(--border-dark)! text-base!'
}
}
}
}

1
bo/src/assets/error.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none"><path stroke="#5b5b5b" stroke-width="2" d="M3 11c0-3.771 0-5.657 1.172-6.828S7.229 3 11 3h2c3.771 0 5.657 0 6.828 1.172S21 7.229 21 11v2c0 3.771 0 5.657-1.172 6.828S16.771 21 13 21h-2c-3.771 0-5.657 0-6.828-1.172S3 16.771 3 13z"/><path fill="#5b5b5b" fill-rule="evenodd" d="m19 13.585l-.02-.02c-.39-.39-.726-.726-1.026-.979c-.317-.267-.662-.502-1.088-.63a3 3 0 0 0-1.732 0c-.426.129-.77.363-1.088.63c-.3.253-.636.59-1.025.98l-.029.028c-.307.306-.487.486-.628.601l-.02.017l-.012-.023c-.087-.16-.189-.393-.36-.792l-.053-.124l-.022-.052c-.356-.83-.655-1.528-.95-2.054c-.305-.541-.685-1.05-1.277-1.346a3 3 0 0 0-1.597-.307c-.66.055-1.201.386-1.685.775c-.406.327-.86.77-1.388 1.297V13q0 .774.003 1.411l1.114-1.114c.69-.69 1.15-1.147 1.525-1.45c.37-.298.53-.335.6-.34a1 1 0 0 1 .532.102c.061.031.196.124.43.54c.236.42.493 1.016.877 1.912l.053.124l.017.038c.149.348.287.67.425.924c.145.265.355.583.709.802a2 2 0 0 0 1.398.27c.41-.073.723-.29.956-.482c.222-.184.47-.432.738-.7l.03-.03c.425-.425.701-.7.928-.891c.218-.184.32-.228.376-.245a1 1 0 0 1 .578 0c.056.017.158.061.376.245c.227.191.503.466.929.892l1.35 1.35c.046-.718.054-1.61.056-2.773" clip-rule="evenodd"/><circle cx="16.5" cy="7.5" r="1.5" fill="#5b5b5b"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -5,19 +5,22 @@ body {
font-family: "Inter", sans-serif;
}
li {
margin-left: 20px
}
.inter {
font-family: "Inter", sans-serif;
}
.container{
.container {
max-width: 2100px;
}
@theme {
--main-light: #FFFEFB;
--second-light: #F5F6FA;
--main-dark: #212121;
--second-light: #F8FAFC;
--main-dark: #1A1A1A;
--black: #1A1A1A;
/* gray */
@@ -25,13 +28,15 @@ body {
--gray-dark: #6B7280;
/* borders */
--border-light: #E8E7E0;
--border-dark: #3F3E3D;
--border-light: #E2E8F0;
--border-dark: #334155;
/* text */
--accent-blue-dark: #3B82F6;
--accent-blue-light:#2563EB;
--accent-blue-dark: #0EA5E91A;
--accent-blue-light: #E0F2FE;
--text-dark: #FFFEFB;
--text-sky-light: #0284C7;
--text-sky-dark: #38BDF8;
/* placeholder */
--placeholder: #8C8C8A;
@@ -40,11 +45,11 @@ body {
--ui-border-accented: var(--border-light);
--ui-border: var(--border-light);
--ui-color-neutral-700: var(--black);
--ui-primary: var(--accent-blue-light)
}
.dark {
--ui-bg: var(--black);
--ui-primary: var(--color-gray-500);
--ui-secondary: var(--accent-green-dark);
--ui-border-accented: var(--border-dark);
--ui-text-dimmed: var(--gray-dark);
@@ -52,22 +57,27 @@ body {
--ui-bg-elevated: var(--color-gray-500);
--ui-error: var(--dark-red);
--border: var(--border-dark);
--tw-border-style: var(--border-dark);
--tw-border-style: var(--border-dark);
--ui-text-inverted: #fff;
--ui-primary: var(--accent-blue-dark)
}
.label-form {
@apply text-(--gray) dark:text-(--gray-dark) pl-0 md:pl-6 leading-none;
}
.label-form {
@apply text-(--gray) dark:text-(--gray-dark) pl-0 md:pl-6 leading-none;
}
.title {
@apply font-medium text-[19px] sm:text-xl md:text-[22px] leading-none text-(--black) dark:text-(--main-light);
}
.title {
@apply font-medium text-[19px] sm:text-xl md:text-[22px] leading-none text-(--black) dark:text-(--main-light);
}
.column-title {
@apply md:ml-[25px] mb-[25px] sm:mb-[30px];
}
.column-title {
@apply md:ml-[25px] mb-[25px] sm:mb-[30px];
}
.form-title {
@apply text-(--accent-green) dark:text-(--accent-green-dark) font-medium;
}
.form-title {
@apply text-(--accent-green) dark:text-(--accent-green-dark) font-medium;
}
.blue-button {
@apply bg-info! text-white!
}

View File

@@ -1,13 +1,51 @@
<template>
<header
class="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-(--black) backdrop-blur-md border-b border-(--border-light) dark:border-(--border-dark)">
<div class="px-4">
<div class="flex items-center justify-between h-16">
<RouterLink :to="{ name: 'home' }" class="flex items-center gap-2">
<div class="w-8 h-8 rounded-lg bg-primary text-white flex items-center justify-center">
<UIcon name="i-heroicons-clock" class="w-5 h-5" />
</div>
<span class="font-semibold text-gray-900 dark:text-white">{{ settings.app.name }}</span>
</RouterLink>
<UNavigationMenu :type="'trigger'" :ui="{
root: 'justify-center',
list: 'gap-4 text-(--black)',
linkLabel: 'text-(--black) text-sm!'
}" :items="menuItems" class="" />
<!-- orientation="vertical" -->
<div class="flex items-center gap-12">
<div class="flex items-center gap-2">
<CountryCurrencySwitch />
<LangSwitch />
</div>
<div class="flex items-center gap-2">
<ThemeSwitch />
<button v-if="authStore.isAuthenticated" @click="authStore.logout()"
class="px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark) whitespace-nowrap">
{{ $t('general.logout') }}
</button>
</div>
</div>
</div>
</div>
</header>
</template>
<script setup lang="ts">
import { useFetchJson } from '@/composable/useFetchJson'
import LangSwitch from './inner/langSwitch.vue'
import ThemeSwitch from './inner/themeSwitch.vue'
import { useAuthStore } from '@/stores/auth'
import { computed, onMounted, ref } from 'vue'
import LangSwitch from './inner/LangSwitch.vue'
import ThemeSwitch from './inner/ThemeSwitch.vue'
import { useAuthStore } from '@/stores/customer/auth'
import { computed, ref } from 'vue'
import { currentLang } from '@/router/langs'
import type { LabelTrans, TopMenuItem } from '@/types'
import type { NavigationMenuItem } from '@nuxt/ui'
import { useRoute, useRouter } from 'vue-router'
import CountryCurrencySwitch from './inner/CountryCurrencySwitch.vue'
import { settings } from '@/router/settings'
const authStore = useAuthStore()
let menu = ref()
@@ -51,37 +89,3 @@ function transformMenu(items: TopMenuItem[], locale: string | undefined): Naviga
}
await getTopMenu()
</script>
<template>
<header
class="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-(--black) backdrop-blur-md border-b border-(--border-light) dark:border-(--border-dark)">
<!-- px-4 sm:px-6 lg:px-8 -->
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-14">
<!-- Logo -->
<RouterLink :to="{ name: 'home' }" class="flex items-center gap-2">
<div class="w-8 h-8 rounded-lg bg-primary text-white flex items-center justify-center">
<UIcon name="i-heroicons-clock" class="w-5 h-5" />
</div>
<span class="font-semibold text-gray-900 dark:text-white">TimeTracker</span>
</RouterLink>
<UNavigationMenu :type="'trigger'" :ui="{
root: 'justify-center',
list: 'gap-4'
}" :items="menuItems" class="w-full"></UNavigationMenu>
<div class="flex items-center gap-2">
<!-- Language Switcher -->
<LangSwitch />
<!-- Theme Switcher -->
<ThemeSwitch />
<!-- Logout Button (only when authenticated) -->
<button v-if="authStore.isAuthenticated" @click="authStore.logout()"
class="px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark)">
{{ $t('general.logout') }}
</button>
</div>
</div>
</div>
</header>
</template>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import LangSwitch from './inner/langSwitch.vue'
import ThemeSwitch from './inner/themeSwitch.vue'
import { useAuthStore } from '@/stores/auth'
import LangSwitch from './inner/LangSwitch.vue'
import ThemeSwitch from './inner/ThemeSwitch.vue'
import { useAuthStore } from '@/stores/customer/auth'
const authStore = useAuthStore()
</script>

View File

@@ -0,0 +1,9 @@
<template>
<div>
</div>
</template>
<script setup lang="ts">
</script>

View File

@@ -1,24 +1,21 @@
<template>
<suspense>
<component :is="Default || 'div'">
<div class="flex gap-10">
<CategoryMenu />
<div class="w-full flex flex-col items-center gap-4">
<UTable :data="productsList" :columns="columns" class="flex-1 w-full" />
<UPagination v-model:page="page" :total="total" :items-per-page="perPage" />
</div>
<div class="flex flex-col md:flex-row gap-10">
<CategoryMenu />
<div class="w-full flex flex-col items-center gap-4">
<UTable :data="productsList" :columns="columns" class="flex-1 w-full" :ui="{
root: 'max-w-100wv overflow-auto!'
}" />
<UPagination v-model:page="page" :total="total" :items-per-page="perPage" />
</div>
</component>
</suspense>
</template>
</div>
</template>
<script setup lang="ts">
import { ref, watch, h, resolveComponent, computed } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
import Default from '@/layouts/default.vue'
import { useRoute, useRouter } from 'vue-router'
import type { TableColumn } from '@nuxt/ui'
import CategoryMenu from '../inner/categoryMenu.vue'
import CategoryMenu from '../inner/CategoryMenu.vue'
import type { Product } from '@/types/product'
const router = useRouter()
@@ -141,7 +138,7 @@ async function fetchProductList() {
if (route.params.category_id)
params.append('category_id', String(route.params.category_id))
const url = `/api/v1/restricted/list/list-products?elems=${perPage.value}&${params.toString()}`
const url = `/api/v1/restricted/product/list?elems=${perPage.value}&${params.toString()}`
try {
const response = await useFetchJson<ApiResponse>(url)
productsList.value = response.items || []
@@ -153,10 +150,16 @@ async function fetchProductList() {
}
}
function goToProduct(productId: number) {
function goToProduct(productId: number, linkRewrite: string) {
let path = {
name: route.name,
params: route.params,
query: route.query
}
localStorage.setItem('back_from_product', JSON.stringify(path))
router.push({
name: 'customer-product-details',
params: { product_id: productId }
name: 'admin-product-details',
params: { product_id: productId, link_rewrite: linkRewrite }
})
}
@@ -173,6 +176,7 @@ const UInput = resolveComponent('UInput')
const UButton = resolveComponent('UButton')
const UIcon = resolveComponent('UIcon')
import errorImg from '@/assets/error.svg'
const columns: TableColumn<Product>[] = [
{
accessorKey: 'product_id',
@@ -209,9 +213,13 @@ const columns: TableColumn<Product>[] = [
cell: ({ row }) => {
return h('img', {
src: row.getValue('image_link') as string,
style: 'width:40px;height:40px;object-fit:cover;'
style: 'width:40px;height:40px;object-fit:cover;',
onError: (e: Event) => {
const target = e.target as HTMLImageElement
target.src = errorImg
}
})
}
},
},
{
accessorKey: 'name',
@@ -270,10 +278,11 @@ const columns: TableColumn<Product>[] = [
cell: ({ row }) => {
return h(UButton, {
onClick: () => {
goToProduct(row.original.product_id)
goToProduct(row.original.product_id, row.original.link_rewrite)
},
color: 'primary',
variant: 'solid'
class: 'cursor-pointer',
color: 'info',
variant: 'soft'
}, () => 'Show product')
},
}

View File

@@ -0,0 +1,523 @@
<template>
<div class="flex items-center gap-2 mb-4">
<UIcon name="line-md:arrow-left" class="text-(--text-sky-light) dark:text-(--text-sky-dark)" />
<p class="cursor-pointer text-(--text-sky-light) dark:text-(--text-sky-dark)" @click="backFromProduct()">
Back to products</p>
</div>
<div class="container mx-auto ">
<div
class="gap-4 mb-6 bg-slate-50 dark:bg-(--main-dark) border border-(--border-light) dark:border-(--border-dark) p-4 rounded-md">
<div class="flex items-center justify-between">
<div class="flex flex-col items-center gap-3" v-if="!isTranslations">
<USelectMenu v-model="toLangId" :items="langs" value-key="id"
class="w-48 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm" :searchInput="false">
<template #default>
<div class="flex flex-col items-start leading-tight">
<span class="text-xs text-gray-400">
Selected language
</span>
<span class="font-medium dark:text-white text-black">
{{langs.find(l => l.id === toLangId)?.name || 'Select language'}}
</span>
</div>
</template>
<template #item-leading="{ item }">
<div class="flex items-center gap-2 cursor-pointer">
<span class="text-lg">{{ item.flag }}</span>
<span class="font-medium dark:text-white text-black">
{{ item.name }}
</span>
</div>
</template>
</USelectMenu>
</div>
<div v-if="toLangId !== settingStore.shopDefaultLanguage && !isTranslations" class="flex gap-7">
<UButton @click="translateToSelectedLanguage" color="info" :loading="translating">
Translate from Polish to {{langs.find(l => l.id === toLangId)?.name}}
</UButton>
</div>
<div v-if="isTranslations" class="flex gap-3 w-full justify-end">
<UButton @click="() => {
toLangId = settingStore.shopDefaultLanguage
isTranslations = false
}" color="info" variant="outline">
Cancel and back to Polish
</UButton>
<UButton color="info" @click="productStore.saveProductDescription(productID, toLangId)">
Save translations
</UButton>
</div>
<!-- <div class="flex gap-7">
<div v-if="isTranslations === false">
<UButton @click="() => {
fetchForLanguage(toLangId)
isShowProductView = true
}" class="text-(--accent-blue-light) dark:text-(--accent-blue-dark)"
color="neutral" variant="outline">
<p class="dark:text-white"> Show product</p>
</UButton>
<UButton @click="translateToSelectedLanguage" color="primary" :loading="translating"
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) flex items-center! justify-center! px-12">
Translate
</UButton>
</div>
<div v-else class="flex gap-3">
<UButton @click="() => {
toLangId = settingStore.shopDefaultLanguage
isTranslations = false
}" color="primary" class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark)">
Cancel
</UButton>
<UButton color="primary" @click="productStore.saveProductDescription(productID, toLangId)"
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark)">
Save
</UButton>
</div>
</div> -->
</div>
</div>
<!-- <div v-if="translating" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
<div class="flex flex-col items-center gap-4 p-8 bg-(--main-light) dark:bg-(--main-dark) rounded-lg shadow-xl">
<UIcon name="svg-spinners:ring-resize" class="text-4xl text-primary" />
<p class="text-lg font-medium dark:text-white text-black">Translating...</p>
</div>
</div> -->
<div v-if="productStore.loading" class="flex items-center justify-center py-20">
<UIcon name="svg-spinners:ring-resize" class="text-4xl text-primary" />
</div>
<div v-else-if="productStore.error" class="flex items-center justify-center py-20">
<p class="text-red-500">{{ productStore.error }}</p>
</div>
<div v-else-if="productStore.productDescription" class="">
<div class="flex items-start gap-30">
<div class="w-80 h-80 bg-(--second-light) dark:bg-gray-700 rounded-lg flex items-center justify-center">
<span class="text-gray-500 dark:text-gray-400">Product Image</span>
</div>
<div class="flex flex-col gap-2">
<p class="text-[25px] font-bold text-black dark:text-white">
{{ productStore.productDescription.name || 'Product Name' }}
</p>
<p v-html="productStore.productDescription.description_short" class="text-black dark:text-white"></p>
<div class="space-y-[10px]">
<div class="flex items-center gap-1">
<UIcon name="lets-icons:done-ring-round-fill"
class="text-[20px] light:text-(--accent-green-light) dark:text-(--accent-green-dark)" />
<p class="text-[16px] font-bold text-(--accent-blue-light) dark:text-(--accent-blue-dark)">
{{ productStore.productDescription.available_now }}
</p>
</div>
<div class="flex items-center gap-1">
<UIcon name="marketeq:car-shipping"
class="text-[25px] light:text-(--accent-green-light) dark:text-(--accent-green-dark)" />
<p class="text-[18px] font-bold text-black dark:text-white">
{{ productStore.productDescription.delivery_in_stock || 'Delivery information' }}
</p>
</div>
</div>
</div>
</div>
<UTabs :items="items" v-model="activeTab" color="info" :content="true" :ui="{
list : 'w-auto!'
}">
<template #description>
<div v-if="!isTranslations" class="flex justify-end items-center gap-3 mb-4">
<UButton v-if="!isEditing" @click="activeTab === 'usage' ? enableEdit() : enableDescriptionEdit()"
class="flex items-center gap-2 m-2 cursor-pointer bg-(--accent-blue-light)! dark:bg-(--accent-blue-dark)!">
<p class="text-white">Change Text</p>
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px] text-white!" />
</UButton>
<UButton v-if="isEditing" @click="activeTab === 'usage' ? saveText : saveDescription" color="neutral"
variant="outline" class="p-2.5 cursor-pointer">
<p class="dark:text-white text-black">Save the edited text</p>
</UButton>
<UButton v-if="isEditing" @click="activeTab === 'usage' ? cancelEdit : cancelDescriptionEdit"
color="neutral" variant="outline" class="p-2.5 cursor-pointer">
Cancel
</UButton>
</div>
<UEditor v-if="isTranslations" v-slot="{ editor }" v-model="productStore.productDescription.description"
content-type="html" :ui="{ base: 'p-8 sm:px-16' }" class="w-full min-h-74" placeholder="Write there ...">
<UEditorToolbar :editor="editor" :items="toolbarItems" class="sm:px-8">
<template #link>
<EditorLinkPopover :editor="editor" auto-open />
</template>
</UEditorToolbar>
</UEditor>
<p v-else v-html="productStore.productDescription.description" class="text-black dark:text-white"></p>
</template>
<template #usage>
<div class="px-7">
<div class="flex justify-end items-center gap-3 mb-4">
<UButton v-if="!isEditing" @click="enableEdit"
class="flex items-center gap-2 m-2 cursor-pointer bg-(--accent-blue-light)! dark:bg-(--accent-blue-dark)!">
<p class="text-white">Change Text</p>
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px] text-white!" />
</UButton>
<UButton v-if="isEditing" @click="saveText" color="neutral" variant="outline"
class="p-2.5 cursor-pointer">
<p class="dark:text-white text-black">Save the edited text</p>
</UButton>
<UButton v-if="isEditing" @click="cancelEdit" color="neutral" variant="outline"
class="p-2.5 cursor-pointer">
Cancel
</UButton>
</div>
<UEditor v-if="isTranslations" v-slot="{ editor }" v-model="productStore.productDescription.usage"
content-type="html" :ui="{ base: 'p-8 sm:px-16' }" class="w-full min-h-74" placeholder="Write there ...">
<UEditorToolbar :editor="editor" :items="toolbarItems" class="sm:px-8">
<template #link>
<EditorLinkPopover :editor="editor" auto-open />
</template>
</UEditorToolbar>
</UEditor>
<p v-else v-html="productStore.productDescription.usage" class="text-black dark:text-white"></p>
</div>
</template>
</UTabs>
</div>
</div>
</template>
<script setup lang="ts">
import { useEditable } from '@/composable/useConteditable';
import { langs } from '@/router/langs';
import { useProductStore } from '@/stores/product';
import { useSettingsStore } from '@/stores/admin/settings';
import type { EditorToolbarItem } from '@nuxt/ui';
import { onMounted, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
const toolbarItems: EditorToolbarItem[][] = [
// History controls
[{
kind: 'undo',
icon: 'i-lucide-undo',
tooltip: { text: 'Undo' }
}, {
kind: 'redo',
icon: 'i-lucide-redo',
tooltip: { text: 'Redo' }
}],
// Block types
[{
icon: 'i-lucide-heading',
tooltip: { text: 'Headings' },
content: {
align: 'start'
},
items: [{
kind: 'heading',
level: 1,
icon: 'i-lucide-heading-1',
label: 'Heading 1'
}, {
kind: 'heading',
level: 2,
icon: 'i-lucide-heading-2',
label: 'Heading 2'
}, {
kind: 'heading',
level: 3,
icon: 'i-lucide-heading-3',
label: 'Heading 3'
}, {
kind: 'heading',
level: 4,
icon: 'i-lucide-heading-4',
label: 'Heading 4'
}]
}, {
icon: 'i-lucide-list',
tooltip: { text: 'Lists' },
content: {
align: 'start'
},
items: [{
kind: 'bulletList',
icon: 'i-lucide-list',
label: 'Bullet List'
}, {
kind: 'orderedList',
icon: 'i-lucide-list-ordered',
label: 'Ordered List'
}]
}, {
kind: 'blockquote',
icon: 'i-lucide-text-quote',
tooltip: { text: 'Blockquote' }
}, {
kind: 'codeBlock',
icon: 'i-lucide-square-code',
tooltip: { text: 'Code Block' }
}, {
kind: 'horizontalRule',
icon: 'i-lucide-separator-horizontal',
tooltip: { text: 'Horizontal Rule' }
}],
// Text formatting
[{
kind: 'mark',
mark: 'bold',
icon: 'i-lucide-bold',
tooltip: { text: 'Bold' }
}, {
kind: 'mark',
mark: 'italic',
icon: 'i-lucide-italic',
tooltip: { text: 'Italic' }
}, {
kind: 'mark',
mark: 'underline',
icon: 'i-lucide-underline',
tooltip: { text: 'Underline' }
}, {
kind: 'mark',
mark: 'strike',
icon: 'i-lucide-strikethrough',
tooltip: { text: 'Strikethrough' }
}, {
kind: 'mark',
mark: 'code',
icon: 'i-lucide-code',
tooltip: { text: 'Code' }
}],
// Link
[{
kind: 'link',
icon: 'i-lucide-link',
tooltip: { text: 'Link' }
}],
// Text alignment
[{
icon: 'i-lucide-align-justify',
tooltip: { text: 'Text Align' },
content: {
align: 'end'
},
items: [{
kind: 'textAlign',
align: 'left',
icon: 'i-lucide-align-left',
label: 'Align Left'
}, {
kind: 'textAlign',
align: 'center',
icon: 'i-lucide-align-center',
label: 'Align Center'
}, {
kind: 'textAlign',
align: 'right',
icon: 'i-lucide-align-right',
label: 'Align Right'
}, {
kind: 'textAlign',
align: 'justify',
icon: 'i-lucide-align-justify',
label: 'Align Justify'
}]
}]
]
const router = useRouter()
function backFromProduct() {
let path = localStorage.getItem('back_from_product')
if (path) {
let res = JSON.parse(path)
router.push({
name: res.name,
params: res.params,
query: res.query
})
localStorage.removeItem('back_from_product')
} else {
router.push({
name: 'customer-products',
})
}
}
const route = useRoute()
const settingStore = useSettingsStore()
const productStore = useProductStore()
const isTranslations = ref(false)
const toLangId = ref<number>(settingStore.shopDefaultLanguage)
const productID = ref<number>(0)
const translating = ref(false)
const activeTab = ref('description')
const usageRef = ref<HTMLElement | null>(null)
const originalUsage = ref('')
const isEditing = ref(false)
const usageEdit = useEditable(usageRef)
const descriptionRef = ref<HTMLElement | null>(null)
const descriptionEdit = useEditable(descriptionRef)
const originalDescription = ref('')
const translateToSelectedLanguage = async () => {
if (toLangId.value && productID.value) {
translating.value = true
try {
await productStore.translateProductDescription(productID.value, toLangId.value)
} finally {
translating.value = false
enableEdit()
enableDescriptionEdit()
}
}
if (productStore.productDescription) {
isTranslations.value = true
}
}
const fetchForLanguage = async (langId: number | null) => {
if (productID.value) {
await productStore.getProductDescription(langId, productID.value)
removeInlineStylesFromAll(productStore.productDescription)
}
}
watch(toLangId, () => {
fetchForLanguage(toLangId.value)
})
onMounted(async () => {
const id = route.params.product_id
if (id) {
productID.value = Number(id)
await fetchForLanguage(toLangId.value)
}
})
const items = ref([
{ label: 'Description', slot: 'description', name: 'description' },
{ label: 'Usage', slot: 'usage', name: 'usage' }
])
// text edit
const enableEdit = () => {
console.log(usageRef.value, 'usageRef');
if (usageRef.value) {
originalUsage.value = usageRef.value.innerHTML
}
isEditing.value = true
usageEdit.enableEdit()
}
const enableDescriptionEdit = () => {
console.log(usageRef.value, 'usageRef');
if (descriptionRef.value) {
originalDescription.value = descriptionRef.value.innerHTML
}
descriptionEdit.enableEdit()
}
const saveText = () => {
if (usageRef.value) {
productStore.productDescription.usage = usageRef.value.innerHTML
}
usageEdit.disableEdit()
isEditing.value = false
productStore.saveProductDescription(productID.value, toLangId.value)
}
const cancelEdit = () => {
if (usageRef.value) {
usageRef.value.innerHTML = originalUsage.value
}
usageEdit.disableEdit()
isEditing.value = false
}
const saveDescription = async () => {
if (descriptionRef.value) {
productStore.productDescription.description = descriptionRef.value.innerHTML
}
descriptionEdit.disableEdit()
await productStore.saveProductDescription(productID.value, toLangId.value)
toLangId.value = settingStore.shopDefaultLanguage
isTranslations.value = false
}
const cancelDescriptionEdit = () => {
if (descriptionRef.value) {
descriptionRef.value.innerHTML = originalDescription.value
}
descriptionEdit.disableEdit()
}
function removeInlineStylesFromAll(product) {
if (!product) return
const removeStyles = (html: string) => {
if (!html) return ''
const div = document.createElement('div')
div.innerHTML = html
div.querySelectorAll('*').forEach(el => {
const bg = el.style.background || el.style.backgroundColor
if (bg) {
el.style.background = ''
el.style.backgroundColor = ''
}
})
div.querySelectorAll('p').forEach(p => {
if (p.querySelector('img')) {
p.style.display = 'flex'
p.style.gap = '20px'
p.style.padding = '30px 0'
}
})
div.querySelectorAll('table').forEach(table => {
table.querySelectorAll('tbody').forEach(tbody => {
tbody.style.setProperty('background-color', '#F8FAFC', 'important')
tbody.querySelectorAll('tr').forEach(tr => {
tr.querySelectorAll('td').forEach(td => {
td.style.setProperty('padding', '10px', 'important')
td.style.setProperty('border-top', '1pt solid black', 'important')
td.style.setProperty('border-left', '1pt solid black', 'important')
td.style.setProperty('border-bottom', '1pt solid black', 'important')
td.style.setProperty('border-right', '1pt solid black', 'important')
td.querySelectorAll('p').forEach(p => {
p.style.setProperty('display', 'flex', 'important')
p.style.setProperty('padding', '0px', 'important')
p.style.setProperty('align-items', 'start', 'important')
p.style.setProperty('color', 'black', 'important')
p.style.setProperty('font-size', '14px', 'important')
p.querySelectorAll('span').forEach(span => {
span.style.setProperty('color', 'black', 'important')
span.style.setProperty('font-size', '14px', 'important')
})
})
})
})
})
})
return div.innerHTML
}
product.description = removeStyles(product.description)
product.description_short = removeStyles(product.description_short)
product.usage = removeStyles(product.usage)
}
</script>

View File

@@ -1,37 +1,61 @@
<template>
<component :is="Default || 'div'">
<div class="container my-10 mx-auto ">
<div class="flex items-center gap-2 mb-4">
<UIcon name="line-md:arrow-left" class="text-(--text-sky-light) dark:text-(--text-sky-dark)" />
<p class="cursor-pointer text-(--text-sky-light) dark:text-(--text-sky-dark)" @click="backFromProduct()">
Back to products</p>
</div>
<div>
<div class="gap-4 mb-6 border-b border-(--border-light) dark:border-(--border-dark) py-4">
<div class="flex flex-wrap gap-4 items-center justify-between">
<div class="flex flex-col items-center gap-3" v-if="!isTranslations">
<USelectMenu v-model="toLangId" :items="langs" value-key="id"
class="w-48 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm" :searchInput="false">
<template #default>
<div class="flex flex-col items-start leading-tight">
<span class="text-xs text-gray-400">
Selected language
</span>
<span class="font-medium dark:text-white text-black">
{{ selectedLangName }}
</span>
</div>
</template>
<div
class="flex items-end justify-between gap-4 mb-6 bg-(--second-light) dark:bg-(--main-dark) border border-(--border-light) dark:border-(--border-dark) p-4 rounded-md">
<div class="flex items-end gap-3">
<USelect v-model="selectedLanguage" :items="availableLangs" variant="outline" class="w-40!"
valueKey="iso_code">
<template #default="{ modelValue }">
<div class="flex items-center gap-2">
<span class="text-md">{{availableLangs.find(x => x.iso_code == modelValue)?.flag}}</span>
<span class="font-medium dark:text-white text-black">{{availableLangs.find(x => x.iso_code ==
modelValue)?.name}}</span>
</div>
</template>
<template #item-leading="{ item }">
<div class="flex items-center rounded-md cursor-pointer transition-colors">
<span class="text-md">{{ item.flag }}</span>
<span class="ml-2 dark:text-white text-black font-medium">{{ item.name }}</span>
</div>
</template>
</USelect>
</div>
<UButton @click="translateToSelectedLanguage" color="primary" :loading="translating"
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) px-12!">
Translate
</UButton>
</div>
<template #item-leading="{ item }">
<div class="flex items-center gap-2 cursor-pointer">
<span class="text-lg">{{ item.flag }}</span>
<span class="font-medium dark:text-white text-black">
{{ item.name }}
</span>
</div>
</template>
</USelectMenu>
</div>
<div v-if="translating" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
<div class="flex flex-col items-center gap-4 p-8 bg-(--main-light) dark:bg-(--main-dark) rounded-lg shadow-xl">
<UIcon name="svg-spinners:ring-resize" class="text-4xl text-primary" />
<p class="text-lg font-medium dark:text-white text-black">Translating...</p>
<div v-if="toLangId !== settingStore.shopDefaultLanguage && !isTranslations"
class="flex flex-wrap-reverse justify-between gap-2">
<UButton color="info" variant="outline" v-if="!isEditing" @click="isTranslations = true">
<p>Change Text</p>
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-7.5" />
</UButton>
<UButton @click="translateToSelectedLanguage" color="info" :loading="translating">
Translate from Polish to {{langs.find(l => l.id === toLangId)?.name}}
</UButton>
</div>
<div v-if="isTranslations" class="flex gap-3 w-full justify-end">
<UButton @click="() => {
handleCancel()
isTranslations = false
}" color="info" variant="outline">
Cancel
</UButton>
<UButton color="info" @click="async () => {
await productStore.saveProductDescription(productID, toLangId)
isTranslations = false
}">
Save
</UButton>
</div>
</div>
</div>
@@ -41,209 +65,179 @@
<div v-else-if="productStore.error" class="flex items-center justify-center py-20">
<p class="text-red-500">{{ productStore.error }}</p>
</div>
<div v-else-if="productStore.productDescription" class="flex items-start gap-30">
<div class="w-80 h-80 bg-(--second-light) dark:bg-gray-700 rounded-lg flex items-center justify-center">
<span class="text-gray-500 dark:text-gray-400">Product Image</span>
</div>
<div class="flex flex-col gap-2">
<p class="text-[25px] font-bold text-black dark:text-white">
{{ productStore.productDescription.name || 'Product Name' }}
</p>
<p v-html="productStore.productDescription.description_short" class="text-black dark:text-white"></p>
<div class="space-y-[10px]">
<div class="flex items-center gap-1">
<UIcon name="lets-icons:done-ring-round-fill" class="text-[20px] text-green-600" />
<p class="text-[16px] font-bold text-(--accent-blue-light) dark:text-(--accent-blue-dark)">
{{ productStore.productDescription.available_now }}
</p>
<div v-else-if="productStore.productDescription" class="space-y-7.5">
<div class="grid grid-cols-1 md:grid-cols-6 h-full w-full gap-6">
<img
class="md:col-span-2 rounded-md bg-white rounded-md border border-(--border-light) dark:border-(--border-dark)"
:src="productStore.productDescription.image_link" :alt="productStore.productDescription.name" @error="(e: Event) => {
const target = e.target as HTMLImageElement
target.src = errorImg
}">
<div class="md:col-span-4 flex flex-col justify-between min-h-full w-full space-y-7.5">
<div class="space-y-7.5">
<div>
<p v-if="!isTranslations" class="text-[25px] font-bold text-black dark:text-white">
{{ productStore.productDescription.name || 'Product name not provided' }}
</p>
<div class="" v-if="isTranslations">
<p>Title:</p>
<UTextarea :rows="1" v-model="productStore.productDescription.name" autoresize :ui="{
root: 'w-full bg-white!',
base: 'text-2xl!',
}" />
</div>
</div>
<div class="" v-if="isTranslations">
<p>Link rewrite:</p>
<UTextarea :rows="1" v-model="productStore.productDescription.link_rewrite" autoresize :ui="{
root: 'w-full',
base: 'bg-inherit!',
}" />
</div>
<div class="" v-if="isTranslations">
<p>Link rewrite:</p>
<UTextarea :rows="1" v-model="productStore.productDescription.link_rewrite" autoresize :ui="{
root: 'w-full bg-white!'
}" />
</div>
<div>
<p v-if="!isTranslations"
v-html="productStore.productDescription.description_short || 'No short description available'"
class="text-black dark:text-white" />
<div class="" v-if="isTranslations">
<p>Short description:</p>
<ProductEditor v-model="productStore.productDescription.description_short" />
</div>
</div>
</div>
<div class="flex items-center gap-1">
<UIcon name="marketeq:car-shipping" class="text-[25px] text-green-600" />
<p class="text-[18px] font-bold text-black dark:text-white">
{{ productStore.productDescription.delivery_in_stock || 'Delivery information' }}
</p>
<div class="space-y-2.5">
<div v-if="productStore.productDescription.available_now" class="flex items-center gap-1">
<UIcon name="lets-icons:done-ring-round-fill"
class="text-[20px] light:text-(--accent-green-light) dark:text-(--accent-green-dark)" />
<p>
{{ productStore.productDescription.available_now }}
</p>
</div>
<div v-if="productStore.productDescription.delivery_in_stock" class="flex items-center gap-1">
<UIcon name="marketeq:car-shipping"
class="text-[25px] light:text-(--accent-green-light) dark:text-(--accent-green-dark)" />
<p>
{{ productStore.productDescription.delivery_in_stock }}
</p>
</div>
</div>
</div>
</div>
<UTabs :items="items" color="info" default-value="0" :ui="{
list: 'w-auto!',
root: 'items-start!'
}">
<template #description>
<ProductEditor v-if="isTranslations" v-model="productStore.productDescription.description" />
<p v-else v-html="productStore.productDescription.description || 'No description available'"
class="text-black dark:text-white" />
</template>
<template #usage>
<ProductEditor v-if="isTranslations" v-model="productStore.productDescription.usage" />
<p v-else v-html="productStore.productDescription.usage || 'No usage information available'"
class="text-black dark:text-white" />
</template>
</UTabs>
</div>
<div v-if="productStore.productDescription" class="mt-16">
<div class="flex gap-4 my-6">
<UButton @click="activeTab = 'description'"
:class="['cursor-pointer', activeTab === 'description' ? 'bg-blue-500 text-white' : '']" color="neutral"
variant="outline">
<p class="dark:text-white">Description</p>
</UButton>
<UButton @click="activeTab = 'usage'"
:class="['cursor-pointer', activeTab === 'usage' ? 'bg-blue-500 text-white' : '']" color="neutral"
variant="outline">
<p class="dark:text-white">Usage</p>
</UButton>
</div>
<div v-if="activeTab === 'usage'"
class="px-8 py-4 border border-(--border-light) dark:border-(--border-dark) rounded-md bg-(--second-light) dark:bg-(--main-dark)">
<div class="flex justify-end items-center gap-3 mb-4">
<UButton v-if="!isEditing" @click="enableEdit"
class="flex items-center gap-2 m-2 cursor-pointer bg-(--accent-blue-light)! dark:bg-(--accent-blue-dark)!">
<p class="text-white">Change Text</p>
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px] text-white!" />
</UButton>
<UButton v-if="isEditing" @click="saveText" color="neutral" variant="outline" class="p-2.5 cursor-pointer">
<p class="dark:text-white text-black">Save the edited text</p>
</UButton>
<UButton v-if="isEditing" @click="cancelEdit" color="neutral" variant="outline"
class="p-2.5 cursor-pointer">
Cancel
</UButton>
</div>
<p ref="usageRef" v-html="productStore.productDescription.usage"
class="flex flex-col justify-center w-full text-start dark:text-white! text-black!"></p>
</div>
<div v-if="activeTab === 'description'"
class="px-8 py-4 border border-(--border-light) dark:border-(--border-dark) rounded-md bg-(--second-light) dark:bg-(--main-dark)">
<div class="flex items-center justify-end gap-3 mb-4">
<UButton v-if="!descriptionEdit.isEditing.value" @click="enableDescriptionEdit"
class="flex items-center gap-2 m-2 cursor-pointer bg-(--accent-blue-light)! dark:bg-(--accent-blue-dark)!">
<p class="text-white">Change Text</p>
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px] text-white!" />
</UButton>
<UButton v-if="descriptionEdit.isEditing.value" @click="saveDescription" color="neutral" variant="outline"
class="p-2.5 cursor-pointer">
<p class="dark:text-white text-black ">Save the edited text</p>
</UButton>
<UButton v-if="descriptionEdit.isEditing.value" @click="cancelDescriptionEdit" color="neutral"
variant="outline" class="p-2.5 cursor-pointer">Cancel</UButton>
</div>
<div ref="descriptionRef" v-html="productStore.productDescription.description"
class="flex flex-col justify-center dark:text-white text-black">
</div>
</div>
</div>
<div class=""></div>
</div>
</component>
</template>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useProductStore } from '@/stores/product'
import { useEditable } from '@/composable/useConteditable'
import { langs } from '@/router/langs'
import type { Language } from '@/types'
import Default from '@/layouts/default.vue'
import { langs } from '@/router/langs';
import { useProductStore } from '@/stores/admin/product';
import { useSettingsStore } from '@/stores/admin/settings';
import { computed, onMounted, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import ProductEditor from '../inner/ProductEditor.vue';
import errorImg from '@/assets/error.svg'
const router = useRouter()
const route = useRoute()
const activeTab = ref('description')
const settingStore = useSettingsStore()
const productStore = useProductStore()
const translating = ref(false)
const isEditing = ref(false)
const availableLangs = computed(() => langs)
const selectedLanguage = ref('en')
const currentLangId = ref(2)
const toLangId = ref<number>(settingStore.shopDefaultLanguage)
const productID = ref<number>(0)
const translating = ref(false)
const isEditing = ref(false)
const isTranslations = ref(false)
// Watch for language changes and refetch product description
watch(selectedLanguage, async (newLang: string) => {
if (productID.value) {
await fetchForLanguage(newLang)
}
const selectedLangName = computed(() => {
return langs.find(l => l.id === toLangId.value)?.name || 'Select language'
})
const fetchForLanguage = async (langCode: string) => {
const lang = langs.find((l: Language) => l.iso_code === langCode)
if (lang && productID.value) {
await productStore.getProductDescription(lang.id, productID.value)
currentLangId.value = lang.id
function backFromProduct() {
let path = localStorage.getItem('back_from_product')
if (path) {
let res = JSON.parse(path)
router.push({
name: res.name,
params: res.params,
query: res.query
})
localStorage.removeItem('back_from_product')
} else {
router.push({
name: 'admin-products',
})
}
}
const translateToSelectedLanguage = async () => {
const targetLang = langs.find((l: Language) => l.iso_code === selectedLanguage.value)
if (targetLang && currentLangId.value && productID.value) {
if (toLangId.value && productID.value) {
translating.value = true
try {
await productStore.translateProductDescription(productID.value, currentLangId.value, targetLang.id)
currentLangId.value = targetLang.id
await productStore.translateProductDescription(productID.value, toLangId.value)
} finally {
translating.value = false
}
}
if (productStore.productDescription) {
isTranslations.value = true
}
}
const fetchForLanguage = async (langId: number | null) => {
if (productID.value) {
await productStore.getProductDescription(langId, productID.value)
}
}
const handleCancel = async () => {
await productStore.getProductDescription(toLangId.value, productID.value)
isTranslations.value = false
}
watch(toLangId, (lang) => {
fetchForLanguage(lang)
})
onMounted(async () => {
const id = route.params.product_id
if (id) {
productID.value = Number(id)
await fetchForLanguage(selectedLanguage.value)
await fetchForLanguage(toLangId.value)
}
})
const descriptionRef = ref<HTMLElement | null>(null)
const usageRef = ref<HTMLElement | null>(null)
const descriptionEdit = useEditable(descriptionRef)
const usageEdit = useEditable(usageRef)
const originalDescription = ref('')
const originalUsage = ref('')
const saveDescription = async () => {
descriptionEdit.disableEdit()
await productStore.saveProductDescription(productID.value)
}
const cancelDescriptionEdit = () => {
if (descriptionRef.value) {
descriptionRef.value.innerHTML = originalDescription.value
}
descriptionEdit.disableEdit()
}
const enableDescriptionEdit = () => {
if (descriptionRef.value) {
originalDescription.value = descriptionRef.value.innerHTML
}
descriptionEdit.enableEdit()
}
const enableEdit = () => {
if (usageRef.value) {
originalUsage.value = usageRef.value.innerHTML
}
isEditing.value = true
usageEdit.enableEdit()
}
const saveText = () => {
usageEdit.disableEdit()
isEditing.value = false
productStore.saveProductDescription(productID.value)
}
const cancelEdit = () => {
if (usageRef.value) {
usageRef.value.innerHTML = originalUsage.value
}
usageEdit.disableEdit()
isEditing.value = false
}
const items = ref([
{ label: 'Description', slot: 'description', name: 'description' },
{ label: 'Usage', slot: 'usage', name: 'usage' }
])
</script>
<style>
.images {
display: flex;
align-items: center;
gap: 70px;
margin: 20px 0 20px 0;
}
</style>

View File

@@ -0,0 +1,208 @@
<template>
<div class="flex flex-col md:flex-row gap-10">
<div class="w-full flex flex-col items-center gap-4">
<UTable :data="usersList" :columns="columns" class="flex-1 w-full"
:ui="{ root: 'max-w-100wv overflow-auto!' }" />
<UPagination v-model:page="page" :total="total" :items-per-page="perPage" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, resolveComponent, h } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
import { useRoute, useRouter } from 'vue-router'
import CategoryMenu from '../inner/CategoryMenu.vue'
import type { TableColumn } from '@nuxt/ui'
import type { Customer } from '@/types/user'
const router = useRouter()
const route = useRoute()
const perPage = ref(15)
const page = computed({
get: () => Number(route.query.p) || 1,
set: (val: number) => {
router.push({ query: { ...route.query, p: val } })
}
})
const sortField = computed({
get: () => [
route.query.sort as string | undefined,
route.query.direction as 'asc' | 'desc' | undefined
],
set: ([sort]: [string, 'asc' | 'desc']) => {
const currentSort = route.query.sort as string | undefined
const currentDirection = route.query.direction as 'asc' | 'desc' | undefined
const query = { ...route.query }
if (currentSort === sort) {
if (currentDirection === 'asc') query.direction = 'desc'
else if (currentDirection === 'desc') {
delete query.sort
delete query.direction
} else {
query.direction = 'asc'
query.sort = sort
}
} else {
query.sort = sort
query.direction = 'asc'
}
router.push({ query })
}
})
const filters = computed<Record<string, string>>({
get: () => {
const q = { ...route.query }
delete q.page
delete q.sort
delete q.direction
return q as Record<string, string>
},
set: (val) => {
const baseQuery = { ...route.query }
Object.keys(baseQuery).forEach(k => {
if (!['page', 'sort', 'direction'].includes(k)) delete baseQuery[k]
})
router.push({ query: { ...baseQuery, ...val, page: 1 } })
}
})
function debounce(fn: Function, delay = 400) {
let t: any
return (...args: any[]) => {
clearTimeout(t)
t = setTimeout(() => fn(...args), delay)
}
}
const updateFilter = debounce((columnId: string, val: string) => {
const newFilters = { ...filters.value }
if (val) newFilters[columnId] = val
else delete newFilters[columnId]
filters.value = newFilters
}, 400)
const usersList = ref<Customer[]>([])
const total = ref(0)
const loading = ref(true)
const error = ref<string | null>(null)
async function fetchUsersList() {
loading.value = true
error.value = null
const params = new URLSearchParams(route.query as any).toString()
const url = `/api/v1/restricted/customer/list?elems=${perPage.value}&${params}`
try {
const res = await useFetchJson<{ items: { items: Customer[] }; count: number }>(url)
usersList.value = res.items?.items || []
total.value = res.count || 0
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Failed to load users'
} finally {
loading.value = false
}
}
function getIcon(name: string) {
if (sortField.value[0] === name) {
if (sortField.value[1] === 'asc') return 'i-lucide-arrow-up-narrow-wide'
if (sortField.value[1] === 'desc') return 'i-lucide-arrow-down-wide-narrow'
}
return 'i-lucide-arrow-up-down'
}
const UInput = resolveComponent('UInput')
const UIcon = resolveComponent('UIcon')
const UButton = resolveComponent('UButton')
const columns: TableColumn<Customer>[] = [
{
accessorKey: 'user_id',
header: ({ column }) => h('div', { class: 'flex flex-col gap-1' }, [
h('div', {
class: 'flex items-center gap-2 cursor-pointer',
onClick: () => (sortField.value = ['user_id', 'asc'])
}, [h('span', 'Client ID'), h(UIcon, { name: getIcon('user_id') })]),
h(UInput, {
placeholder: 'Search...',
modelValue: filters.value[column.id] ?? '',
'onUpdate:modelValue': (val: string) => updateFilter(column.id, val),
size: 'xs'
})
]),
cell: ({ row }) => `#${row.getValue('user_id')}`
},
{
accessorKey: 'name',
header: ({ column }) => h('div', { class: 'flex flex-col gap-1' }, [
h('div', {
class: 'flex items-center gap-2 cursor-pointer',
onClick: () => (sortField.value = ['last_name, first_name', 'asc'])
}, [h('span', 'Name/Surname'), h(UIcon, { name: getIcon('name') })]),
h(UInput, {
placeholder: 'Search...',
modelValue: filters.value[column.id] ?? '',
'onUpdate:modelValue': (val: string) => updateFilter(column.id, val),
size: 'xs'
})
]),
cell: ({ row }) => `${row.original.first_name} ${row.original.last_name}`
},
{
accessorKey: 'email',
header: ({ column }) => h('div', { class: 'flex flex-col gap-1' }, [
h('div', {
class: 'flex items-center gap-2 cursor-pointer',
onClick: () => (sortField.value = ['email', 'asc'])
}, [h('span', 'Email'), h(UIcon, { name: getIcon('email') })]),
h(UInput, {
placeholder: 'Search...',
modelValue: filters.value[column.id] ?? '',
'onUpdate:modelValue': (val: string) => updateFilter(column.id, val),
size: 'xs'
})
]),
cell: ({ row }) => row.getValue('email')
},
{
accessorKey: 'count',
header: '',
cell: ({ row }) => {
return h(UButton, {
// onClick: () => {
// goToProduct(row.original.product_id, row.original.link_rewrite)
// },
class: 'cursor-pointer',
color: 'info',
variant: 'soft'
}, () => 'Manage')
},
},
{
accessorKey: 'profile',
header: '',
cell: ({ row }) => {
const userId = row.original.user_id
return h(UButton, {
color: 'info',
size: 'sm',
variant: 'soft',
onClick: () => {
router.push({
name: 'customer-management-profile',
params: { user_id: userId }
})
}
}, () => 'Go to profile')
}
}
]
watch(() => route.query, fetchUsersList, { immediate: true })
</script>

View File

@@ -0,0 +1,242 @@
<template>
<div class="pt-70! flex flex-col items-center justify-center bg-gray-50 dark:bg-(--main-dark)">
<h1 class="text-6xl font-bold text-black dark:text-white mb-14">Search Users</h1>
<div class="w-full max-w-4xl">
<UInput icon="i-lucide-search" type="text" placeholder="Type user name or ID..." v-model="searchQuery"
class="w-full!" :ui="{ base: 'py-4! rounded-full!' }" />
</div>
<p v-if="loading">Loading...</p>
<p v-else-if="error" class="text-red-600">{{ error }}</p>
<div v-else-if="clients.length" class="w-full max-w-4xl mt-7">
<UTable :columns="columns" :data="clients" :ui="{ root: 'w-full!' }" />
</div>
<p v-else-if="searchQuery.length" class="pt-4 text-gray-700">
No users found with that name or ID
</p>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, resolveComponent, h } from 'vue'
import type { TableColumn } from '@nuxt/ui';
import { useRoute, useRouter } from 'vue-router';
import { useFetchJson } from '@/composable/useFetchJson';
interface Customer {
user_id: number;
email: string;
first_name: string;
last_name: string;
}
const searchQuery = ref('');
const clients = ref<Customer[]>([]);
const loading = ref(false);
const error = ref<string | null>(null);
const limit = ref(10);
const page = ref(1);
function debounce(fn: Function, delay = 400) {
let t: any;
return (...args: any[]) => {
clearTimeout(t);
t = setTimeout(() => fn(...args), delay);
};
}
const searchClients = async () => {
if (!searchQuery.value) {
clients.value = [];
return;
}
loading.value = true;
error.value = null;
try {
const result = await useFetchJson(
`/api/v1/restricted/customer/list?search=${encodeURIComponent(searchQuery.value)}&elems=${limit.value}&page=${page.value}`
);
clients.value = result.items?.items || [];
} catch (err: unknown) {
error.value = err instanceof Error ? err.message : 'Failed to fetch clients';
clients.value = [];
} finally {
loading.value = false;
}
};
watch(searchQuery, debounce(searchClients, 300));
const router = useRouter()
const route = useRoute()
const UInput = resolveComponent('UInput')
const UIcon = resolveComponent('UIcon')
const UButton = resolveComponent('UButton')
const sortField = computed({
get: () => [
route.query.sort as string | undefined,
route.query.direction as 'asc' | 'desc' | undefined
],
set: ([sort]: [string, 'asc' | 'desc']) => {
const currentSort = route.query.sort as string | undefined
const currentDirection = route.query.direction as 'asc' | 'desc' | undefined
const query = { ...route.query }
if (currentSort === sort) {
if (currentDirection === 'asc') query.direction = 'desc'
else if (currentDirection === 'desc') {
delete query.sort
delete query.direction
} else {
query.direction = 'asc'
query.sort = sort
}
} else {
query.sort = sort
query.direction = 'asc'
}
router.push({ query })
}
})
function getIcon(name: string) {
if (sortField.value[0] === name) {
if (sortField.value[1] === 'asc') return 'i-lucide-arrow-up-narrow-wide'
if (sortField.value[1] === 'desc') return 'i-lucide-arrow-down-wide-narrow'
}
return 'i-lucide-arrow-up-down'
}
const filters = computed<Record<string, string>>({
get: () => {
const q = { ...route.query }
delete q.page
delete q.sort
delete q.direction
return q as Record<string, string>
},
set: (val) => {
const baseQuery = { ...route.query }
Object.keys(baseQuery).forEach(k => {
if (!['page', 'sort', 'direction'].includes(k)) delete baseQuery[k]
})
router.push({ query: { ...baseQuery, ...val, page: 1 } })
}
})
const updateFilter = debounce((columnId: string, val: string) => {
const newFilters = { ...filters.value }
if (val) newFilters[columnId] = val
else delete newFilters[columnId]
filters.value = newFilters
}, 400)
const columns: TableColumn<Customer>[] = [
{
accessorKey: 'user_id',
header: ({ column }) => h('div', { class: 'flex flex-col gap-1' }, [
h('div', {
class: 'flex items-center gap-2 cursor-pointer',
onClick: () => (sortField.value = ['user_id', 'asc'])
}, [h('span', 'Client ID'), h(UIcon, { name: getIcon('user_id') })]),
h(UInput, {
placeholder: 'Search...',
modelValue: filters.value[column.id] ?? '',
'onUpdate:modelValue': (val: string) => updateFilter(column.id, val),
size: 'xs'
})
]),
cell: ({ row }) => `#${row.getValue('user_id')}`
},
{
accessorKey: 'name',
header: ({ column }) => h('div', { class: 'flex flex-col gap-1' }, [
h('div', {
class: 'flex items-center gap-2 cursor-pointer',
onClick: () => (sortField.value = ['last_name, first_name', 'asc'])
}, [h('span', 'Name/Surname'), h(UIcon, { name: getIcon('name') })]),
h(UInput, {
placeholder: 'Search...',
modelValue: filters.value[column.id] ?? '',
'onUpdate:modelValue': (val: string) => updateFilter(column.id, val),
size: 'xs'
})
]),
cell: ({ row }) => `${row.original.first_name} ${row.original.last_name}`
},
{
accessorKey: 'email',
header: ({ column }) => h('div', { class: 'flex flex-col gap-1' }, [
h('div', {
class: 'flex items-center gap-2 cursor-pointer',
onClick: () => (sortField.value = ['email', 'asc'])
}, [h('span', 'Email'), h(UIcon, { name: getIcon('email') })]),
h(UInput, {
placeholder: 'Search...',
modelValue: filters.value[column.id] ?? '',
'onUpdate:modelValue': (val: string) => updateFilter(column.id, val),
size: 'xs'
})
]),
cell: ({ row }) => row.getValue('email')
},
{
accessorKey: 'count',
header: '',
cell: ({ row }) => {
return h(UButton, {
// onClick: () => {
// goToProduct(row.original.product_id, row.original.link_rewrite)
// },
class: 'cursor-pointer',
color: 'info',
variant: 'soft'
}, () => 'Manage')
},
},
{
accessorKey: 'profile',
header: '',
cell: ({ row }) => {
const userId = row.original.user_id
return h(UButton, {
color: 'info',
size: 'sm',
variant: 'soft',
onClick: () => {
router.push({
name: 'customer-management-profile',
params: { user_id: userId }
})
}
}, () => 'Go to profile')
}
}
]
</script>
<style scoped>
input::placeholder {
color: #9ca3af;
}
</style>

View File

@@ -0,0 +1,7 @@
<template>
<div>customer-management</div>
</template>
<script setup lang="ts">
</script>

View File

@@ -1,6 +1,5 @@
<template>
<component :is="Default || 'div'">
<div class="container mx-auto">
<div class="">
<h2
class="font-semibold text-black dark:text-white pb-6 text-2xl">
{{ t('Cart Items') }}
@@ -48,15 +47,13 @@
</UButton>
</div>
</div>
</component>
</template>
</template>
<script setup lang="ts">
import { useCartStore } from '@/stores/cart'
import { useCartStore } from '@/stores/customer/cart'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import Default from '@/layouts/default.vue'
const cartStore = useCartStore()
const { t } = useI18n()
const router = useRouter()

View File

@@ -1,180 +1,246 @@
<template>
<component :is="Default || 'div'">
<div class="container mx-auto">
<div class="flex flex-col gap-5 mb-6">
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Addresses') }}</h1>
<div class="flex md:flex-row flex-col justify-between items-start md:items-center gap-5 md:gap-0">
<div class="flex gap-2 items-center">
<UInput v-model="searchQuery" type="text" :placeholder="t('Search address')"
class="bg-white dark:bg-gray-800 text-black dark:text-white absolute" />
<UIcon name="ic:baseline-search"
class="text-[20px] text-(--accent-blue-light) dark:text-(--accent-blue-dark) relative left-40" />
</div>
<UButton color="primary" @click="openCreateModal"
class="bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) text-white hover:bg-(--accent-blue-dark) dark:hover:bg-(--accent-blue-light)">
<UIcon name="mdi:add-bold" />
{{ t('Add Address') }}
</UButton>
</div>
</div>
<div v-if="paginatedAddresses.length" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
<div v-for="address in paginatedAddresses" :key="address.id"
class="border border-(--border-light) dark:border-(--border-dark) rounded-md p-4 bg-(--second-light) dark:bg-(--main-dark) hover:shadow-md transition-shadow flex justify-between">
<div class="flex flex-col gap-2 items-strat justify-end">
<p class="text-black dark:text-white">{{ address.street }}</p>
<p class="text-black dark:text-white">{{ address.zipCode }}, {{ address.city }}</p>
<p class="text-black dark:text-white">{{ address.country }}</p>
</div>
<div class="flex flex-col items-end justify-between gap-2">
<button @click="confirmDelete(address.id)"
class="p-2 text-red-500 bg-red-100 dark:bg-(--main-dark) rounded transition-colors"
:title="t('Remove')">
<UIcon name="material-symbols:delete" class="text-[18px]" />
</button>
<UButton size="sm" color="neutral" variant="outline" @click="openEditModal(address)"
class="text-(--accent-blue-light) dark:text-(--accent-blue-dark) text-[13px]">
{{ t('edit') }}
<UIcon name="ic:sharp-edit" class="text-[15px]" />
</UButton>
<div class="">
<div class="flex flex-col gap-5 mb-6">
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Addresses') }}</h1>
<div class="flex md:flex-row flex-col justify-between items-start md:items-center gap-5 md:gap-0">
<div class="flex gap-2 items-center">
<UInput v-model="searchQuery" type="text" :placeholder="t('Search address')"
class="bg-white dark:bg-gray-800 text-black dark:text-white absolute" />
<UIcon name="ic:baseline-search"
class="text-[20px] text-(--text-sky-light) dark:text-(--text-sky-dark) relative left-40" />
</div>
<UButton color="info" @click="openCreateModal">
<UIcon name="mdi:add-bold" />
{{ t('Add Address') }}
</UButton>
</div>
</div>
</div>
<div v-else class="text-center py-8 text-gray-500 dark:text-gray-400">{{ t('No addresses found') }}</div>
<div class="mt-6 flex justify-center">
<UPagination v-model:page="page" :total="totalItems" :page-size="pageSize" />
</div>
<UModal v-model:open="showModal" :overlay="true" class="max-w-md mx-auto">
<template #content>
<div class="p-6 flex flex-col gap-6">
<p class="text-[20px] text-black dark:text-white ">Address</p>
<UForm @submit.prevent="saveAddress" class="space-y-4" :validate="validate">
<div>
<label class="block text-sm font-medium text-black dark:text-white mb-1">Street *</label>
<UInput v-model="formData.street" placeholder="Enter street" name="street" class="w-full" />
</div>
<div>
<label class="block text-sm font-medium text-black dark:text-white mb-1">Zip Code *</label>
<UInput v-model="formData.zipCode" placeholder="Enter zip code" name="zipCode"
class="w-full" />
</div>
<div>
<label class="block text-sm font-medium text-black dark:text-white mb-1">City *</label>
<UInput v-model="formData.city" placeholder="Enter city" name="city" class="w-full" />
</div>
<div>
<label class="block text-sm font-medium text-black dark:text-white mb-1">Country *</label>
<UInput v-model="formData.country" placeholder="Enter country" name="country"
class="w-full" />
</div>
</UForm>
<div class="flex justify-end gap-2">
<UButton variant="outline" color="neutral" @click="closeModal"
class="text-black dark:text-white">{{ t('Cancel') }}</UButton>
<UButton variant="outline" color="neutral" @click="saveAddress"
class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) hover:bg-(--accent-blue-dark) dark:hover:bg-(--accent-blue-light)">
{{ t('Save') }}</UButton>
<div v-if="cartStore.addressLoading" class="text-center py-8 text-gray-500 dark:text-gray-400">
{{ t('Loading addresses...') }}
</div>
<div v-else-if="cartStore.addressError" class="text-center py-8 text-red-500 dark:text-red-400">
{{ cartStore.addressError }}
</div>
<div v-else-if="cartStore.paginatedAddresses.length"
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
<div v-for="address in cartStore.paginatedAddresses" :key="address.id"
class="border border-(--border-light) dark:border-(--border-dark) rounded-md p-4 bg-(--second-light) dark:bg-(--main-dark) hover:shadow-md transition-shadow flex justify-between">
<div class="flex flex-col gap-2 items-start justify-end">
<p class="text-black dark:text-white font-semibold">{{ address.address_info.recipient }}</p>
<p class="text-black dark:text-white">{{ address.address_info.street }} {{
address.address_info.building_no }}{{ address.address_info.apartment_no ? '/' +
address.address_info.apartment_no : '' }}</p>
<p class="text-black dark:text-white">{{ address.address_info.postal_code }}, {{
address.address_info.city }}</p>
<p class="text-black dark:text-white">{{ address.address_info.voivodeship }}</p>
<p v-if="address.address_info.address_line2" class="text-black dark:text-white">{{
address.address_info.address_line2 }}</p>
</div>
</div>
</template>
</UModal>
<UModal v-model:open="showDeleteConfirm" :overlay="true" class="max-w-md mx-auto">
<template #content>
<div class="p-6 flex flex-col gap-3">
<div class="flex flex-col gap-2 justify-center items-center">
<p class="flex items-end gap-2 dark:text-white text-black">
<UIcon name='f7:exclamationmark-triangle' class="text-[35px] text-red-700" />
Confirm Delete
</p>
<p class="text-gray-700 dark:text-gray-300">
{{ t('Are you sure you want to delete this address?') }}</p>
</div>
<div class="flex justify-center gap-5">
<UButton variant="outline" color="neutral" @click="showDeleteConfirm = false"
class="dark:text-white text-black">{{ t('Cancel') }}
<div class="flex flex-col items-end justify-between gap-2">
<button @click="confirmDelete(address.id)"
class="p-2 text-red-500 bg-red-100 dark:bg-(--main-dark) rounded transition-colors"
:title="t('Remove')">
<UIcon name="material-symbols:delete" class="text-[18px]" />
</button>
<UButton size="sm" color="neutral" variant="outline" @click="openEditModal(address)"
class="text-(--text-sky-light) dark:text-(--text-sky-dark) text-[13px]">
{{ t('edit') }}
<UIcon name="ic:sharp-edit" class="text-[15px]" />
</UButton>
<UButton variant="outline" color="neutral" @click="deleteAddress" class="text-red-700">
{{ t('Delete') }}</UButton>
</div>
</div>
</template>
</UModal>
</div>
</component>
</template>
</div>
<div v-else class="text-center py-8 text-gray-500 dark:text-gray-400">{{ t('No addresses found') }}</div>
<div class="mt-6 flex justify-center">
<UPagination v-model:page="page" :total="totalItems" :page-size="pageSize" />
</div>
<UModal v-model:open="showModal" :overlay="true" class="max-w-md mx-auto">
<template #content>
<div class="p-6 flex flex-col gap-6">
<p class="text-[20px] text-black dark:text-white ">Address</p>
<UForm @submit="saveAddress" class="space-y-4" :validate="validate" :state="formData">
<template v-for="field in formFieldKeys" :key="field">
<UFormField :label="fieldLabel(field)" :name="field"
:required="field !== 'address_line2'">
<UInput v-model="formData[field]" :placeholder="fieldLabel(field)" class="w-full" />
</UFormField>
</template>
<div class="flex justify-end gap-2">
<UButton variant="outline" color="neutral" @click="closeModal">
{{ t('Cancel') }}
</UButton>
<UButton type="submit" color="info" class="cursor-pointer">
{{ t('Save') }}
</UButton>
</div>
</UForm>
</div>
</template>
</UModal>
<UModal v-model:open="showDeleteConfirm" :overlay="true" class="max-w-md mx-auto">
<template #content>
<div class="p-6 flex flex-col gap-3">
<div class="flex flex-col gap-2 justify-center items-center">
<p class="flex items-end gap-2 dark:text-white text-black">
<UIcon name='f7:exclamationmark-triangle' class="text-[35px] text-red-700" />
Confirm Delete
</p>
<p class="text-gray-700 dark:text-gray-300">
{{ t('Are you sure you want to delete this address?') }}</p>
</div>
<div class="flex justify-center gap-5">
<UButton variant="outline" color="neutral" @click="showDeleteConfirm = false"
class="dark:text-white text-black">{{ t('Cancel') }}
</UButton>
<UButton variant="outline" color="neutral" @click="deleteAddress" class="text-red-700">
{{ t('Delete') }}</UButton>
</div>
</div>
</template>
</UModal>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useAddressStore } from '@/stores/address'
import { ref, reactive, computed, watch, onMounted } from 'vue'
import { useCartStore } from '@/stores/customer/cart'
import { useI18n } from 'vue-i18n'
import Default from '@/layouts/default.vue'
const addressStore = useAddressStore()
import { currentCountry } from '@/router/langs'
type AddressFormState = Record<string, string>
const cartStore = useCartStore()
const { t } = useI18n()
const searchQuery = ref('')
const searchQuery = ref(cartStore.addressSearchQuery)
const showModal = ref(false)
const isEditing = ref(false)
const editingAddressId = ref<number | null>(null)
const formData = ref({ street: '', zipCode: '', city: '', country: '' })
const addressTemplate = ref<AddressFormState | null>(null)
const formData = reactive<AddressFormState>({})
const showDeleteConfirm = ref(false)
const addressToDelete = ref<number | null>(null)
const page = ref(addressStore.currentPage)
const paginatedAddresses = computed(() => addressStore.paginatedAddresses)
const totalItems = computed(() => addressStore.totalItems)
const pageSize = addressStore.pageSize
watch(page, (newPage) => addressStore.setPage(newPage))
watch(searchQuery, (val) => {
addressStore.setSearchQuery(val)
const page = computed<number>({
get: () => cartStore.addressCurrentPage,
set: (value: number) => cartStore.setAddressPage(value)
})
function openCreateModal() {
const totalItems = computed(() => cartStore.totalAddressItems)
const pageSize = cartStore.addressPageSize
const formFieldKeys = computed(() => (addressTemplate.value ? Object.keys(addressTemplate.value) : []))
watch(searchQuery, (val) => {
cartStore.setAddressSearchQuery(val)
})
onMounted(() => {
cartStore.fetchAddresses()
})
function clearFormData() {
Object.keys(formData).forEach((key) => delete formData[key])
}
function fieldLabel(key: string) {
const labels: Record<string, string> = {
postal_code: 'Zip Code',
post_town: 'City',
city: 'City',
county: 'County',
region: 'Region',
voivodeship: 'Region / Voivodeship',
street: 'Street',
thoroughfare: 'Street',
building_no: 'Building No',
building_name: 'Building Name',
house_number: 'House Number',
orientation_number: 'Orientation Number',
apartment_no: 'Apartment No',
sub_building: 'Sub Building',
address_line2: 'Address Line 2',
recipient: 'Recipient'
}
return t(labels[key] ?? key.replace(/_/g, ' ').replace(/\b\w/g, (chr) => chr.toUpperCase()))
}
async function openCreateModal() {
resetForm()
isEditing.value = false
const template = await cartStore.getAddressTemplate(Number(currentCountry.value?.id) | 2).catch(() => null)
if (template) {
addressTemplate.value = template
clearFormData()
Object.assign(formData, template)
}
showModal.value = true
}
function openEditModal(address: any) {
formData.value = {
street: address.street,
zipCode: address.zipCode,
city: address.city,
country: address.country
async function openEditModal(address: any) {
currentCountry.value = address.country_id || 1
const template = await cartStore.getAddressTemplate(address.country_id | 2).catch(() => null)
if (template) {
addressTemplate.value = template
clearFormData()
Object.assign(formData, template)
}
if (address.address_info) {
formFieldKeys.value.forEach((key) => {
formData[key] = address.address_info[key] ?? ''
})
}
isEditing.value = true
editingAddressId.value = address.id
showModal.value = true
}
function resetForm() {
formData.value = { street: '', zipCode: '', city: '', country: '' }
clearFormData()
editingAddressId.value = null
}
function closeModal() {
showModal.value = false
resetForm()
}
function validate() {
const errors = []
if (!formData.value.street) errors.push({ name: 'street', message: 'Street required' })
if (!formData.value.zipCode) errors.push({ name: 'zipCode', message: 'Zip Code required' })
if (!formData.value.city) errors.push({ name: 'city', message: 'City required' })
if (!formData.value.country) errors.push({ name: 'country', message: 'Country required' })
return errors.length ? errors : null
const errors: Array<{ name: string; message: string }> = []
const optionalFields = new Set(['address_line2'])
formFieldKeys.value.forEach((key) => {
if (!optionalFields.has(key) && !formData[key]?.trim()) {
errors.push({ name: key, message: `${fieldLabel(key)} required` })
}
})
return errors
}
function saveAddress() {
if (validate()) return
async function saveAddress() {
if (isEditing.value && editingAddressId.value) {
addressStore.updateAddress(editingAddressId.value, formData.value)
await cartStore.updateAddress(editingAddressId.value, currentCountry.value?.id || 2, formData)
} else {
addressStore.addAddress(formData.value)
await cartStore.addAddress(currentCountry.value?.id || 2, formData)
}
closeModal()
}
function confirmDelete(id: number) {
addressToDelete.value = id
showDeleteConfirm.value = true
}
function deleteAddress() {
async function deleteAddress() {
if (addressToDelete.value) {
addressStore.deleteAddress(addressToDelete.value)
await cartStore.deleteAddress(addressToDelete.value)
}
showDeleteConfirm.value = false
addressToDelete.value = null

View File

@@ -1,6 +1,5 @@
<template>
<component :is="Default || 'div'">
<div class="container mx-auto flex flex-col gap-5 md:gap-10">
<div class="flex flex-col gap-5 md:gap-10">
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Shopping Cart') }}</h1>
<div class="flex flex-col lg:flex-row gap-5 md:gap-10">
<div class="flex-1">
@@ -43,7 +42,7 @@
name: 'customer-product', params: {
product_id: '51'
}
}" class="inline-block mt-4 text-(--accent-blue-light) dark:text-(--accent-blue-dark) hover:underline">
}" class="inline-block mt-4 text-(--text-sky-light) dark:text-(--text-sky-dark) hover:underline">
{{ t('Continue Shopping') }}
</RouterLink>
</div>
@@ -72,7 +71,7 @@
</div>
<div class="flex justify-between mb-6">
<span class="text-black dark:text-white font-semibold text-lg">{{ t('Total') }}</span>
<span class="text-(--accent-blue-light) dark:text-(--accent-blue-dark) font-bold text-lg">${{
<span class="text-(--text-sky-light) dark:text-(--text-sky-dark) font-bold text-lg">${{
cartStore.orderTotal.toFixed(2) }}</span>
</div>
<div class="flex flex-col gap-3">
@@ -103,7 +102,7 @@
? 'border-(--accent-blue-light) dark:border-(--accent-blue-dark) bg-blue-50 dark:bg-blue-900/20'
: 'border-(--border-light) dark:border-(--border-dark) hover:border-gray-400'">
<input type="radio" :value="address.id" v-model="selectedAddress"
class="mt-1 w-4 h-4 text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
class="mt-1 w-4 h-4 text-(--text-sky-light) dark:text-(--text-sky-dark)" />
<div class="flex-1">
<p class="text-black dark:text-white font-medium">{{ address.street }}</p>
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ address.zipCode }}, {{ address.city }}</p>
@@ -115,7 +114,7 @@
<UIcon name="mdi:map-marker-outline" class="text-4xl text-gray-400 mb-2" />
<p class="text-gray-500 dark:text-gray-400">{{ t('No addresses found') }}</p>
<RouterLink :to="{ name: 'addresses' }"
class="inline-block mt-2 text-(--accent-blue-light) dark:text-(--accent-blue-dark) hover:underline">
class="inline-block mt-2 text-(--text-sky-light) dark:text-(--text-sky-dark) hover:underline">
{{ t('Add Address') }}
</RouterLink>
</div>
@@ -131,11 +130,11 @@
? 'border-(--accent-blue-light) dark:border-(--accent-blue-dark) bg-blue-50 dark:bg-blue-900/20'
: 'border-(--border-light) dark:border-(--border-dark) hover:border-gray-400'">
<input type="radio" :value="method.id" v-model="selectedDeliveryMethod"
class="w-4 h-4 text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
class="w-4 h-4 text-(--text-sky-light) dark:text-(--text-sky-dark)" />
<div class="flex-1">
<div class="flex justify-between items-center">
<span class="text-black dark:text-white font-medium">{{ method.name }}</span>
<span class="text-(--accent-blue-light) dark:text-(--accent-blue-dark) font-medium">
<span class="text-(--text-sky-light) dark:text-(--text-sky-dark) font-medium">
{{ method.price > 0 ? `$${method.price.toFixed(2)}` : t('Free') }}
</span>
</div>
@@ -147,16 +146,14 @@
</div>
</div>
</div>
</component>
</template>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useCartStore } from '@/stores/cart'
import { useAddressStore } from '@/stores/address'
import { useCartStore } from '@/stores/customer/cart'
import { useAddressStore } from '@/stores/customer/address'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import Default from '@/layouts/default.vue'
const cartStore = useCartStore()
const addressStore = useAddressStore()
const { t } = useI18n()

View File

@@ -1,9 +1,6 @@
<template>
<component :is="Default || 'div'">
Orders page
</component>
</template>
Orders page
</template>
<script lang="ts" setup>
import Default from '@/layouts/default.vue'
</script>

View File

@@ -1,83 +1,91 @@
<template>
<component :is="Default || 'div'">
<div class="container mx-auto">
<div class="flex md:flex-row flex-col justify-between gap-8 my-6">
<div class="flex-1">
<div class="bg-gray-100 dark:bg-gray-800 rounded-lg p-8 flex items-center justify-center min-h-[300px] ">
<img :src="selectedColor?.image || productData.image" :alt="productData.name"
class="max-w-full h-auto object-contain" />
</div>
</div>
<div class="flex-1 flex flex-col gap-4">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
{{ productData.name }}
</h1>
<p class="text-gray-600 dark:text-gray-300">
{{ productData.description }}
</p>
<div class="text-3xl font-bold text-(--accent-blue-light) dark:text-(--accent-blue-dark)">
{{ productData.price }}
</div>
<div class="flex flex-col">
<div class="flex gap-2">
<span class="text-gray-500 dark:text-gray-400">Dimensions:</span>
<p class="font-medium dark:text-white">{{ productData.dimensions }}</p>
<div class="">
<div class="flex md:flex-row flex-col justify-between gap-8 my-6">
<div class="flex-1">
<div
class="bg-gray-100 dark:bg-gray-800 rounded-lg p-8 flex items-center justify-center min-h-[300px] ">
<img :src="selectedColor?.image || productData.image" :alt="productData.name"
class="max-w-full h-auto object-contain" />
</div>
<div class="flex gap-2">
<span class="text-gray-500 dark:text-gray-400">Seat Height:</span>
<p class="font-medium dark:text-white">{{ productData.seatHeight }}</p>
</div>
<div class="flex-1 flex flex-col gap-4">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
{{ productData.name }}
</h1>
<UIcon name="material-symbols:favorite"
class="cursor-pointer text-2xl transition hover:scale-110"
:class="productData.is_favorite ? 'text-red-500' : 'text-gray-400'"
@click="toggleFavorite" />
</div>
<p class="text-gray-600 dark:text-gray-300">
{{ productData.description }}
</p>
<div class="text-3xl font-bold text-(--text-sky-light) dark:text-(--text-sky-dark)">
{{ productData.price }}
</div>
<div class="flex flex-col">
<div class="flex gap-2">
<span class="text-gray-500 dark:text-gray-400">Dimensions:</span>
<p class="font-medium dark:text-white">{{ productData.dimensions }}</p>
</div>
<div class="flex gap-2">
<span class="text-gray-500 dark:text-gray-400">Seat Height:</span>
<p class="font-medium dark:text-white">{{ productData.seatHeight }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="flex md:flex-row flex-col justify-between md:items-end items-start gap-5 md:gap-0 md:mb-8 mb-4">
<div class="flex flex-col gap-3">
<span class="text-sm text-(--accent-blue-light) dark:text-(--accent-blue-dark) ">Colors:</span>
<div class="flex gap-2">
<button v-for="color in productData.colors" :key="color.id" @click="selectedColor = color"
class="w-10 h-10 border-2 transition-all" :class="selectedColor?.id === color.id
? 'border-(--accent-blue-light) ring-2 ring-blue-600 ring-offset-2'
: 'border-gray-300 dark:border-gray-600 hover:border-gray-400'"
:style="{ backgroundColor: color.hex }" :title="color.name" />
<div class="flex md:flex-row flex-col justify-between md:items-end items-start gap-5 md:gap-0 md:mb-8 mb-4">
<div class="flex flex-col gap-3">
<span class="text-sm text-(--text-sky-light) dark:text-(--text-sky-dark) ">Colors:</span>
<div class="flex gap-2">
<button v-for="color in productData.colors" :key="color.id" @click="selectedColor = color"
class="w-10 h-10 border-2 transition-all" :class="selectedColor?.id === color.id
? 'border-(--accent-blue-light) ring-2 ring-blue-600 ring-offset-2'
: 'border-gray-300 dark:border-gray-600 hover:border-gray-400'"
:style="{ backgroundColor: color.hex }" :title="color.name" />
</div>
</div>
<div class="flex gap-5 items-end">
<UInputNumber v-model="value" />
<UButton color="primary"
class="px-14! bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) text-white">
Add to Cart
</UButton>
</div>
</div>
<div class="flex gap-5 items-end">
<UInputNumber v-model="value" />
<UButton color="primary" class="px-14! bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) text-white">
Add to Cart
</UButton>
<ProductCustomization />
<hr class="border-t border-(--border-light) dark:border-(--border-dark) mb-8" />
<div class="mb-6 w-[100%] xl:w-[60%]">
<div class="grid grid-cols-2 lg:grid-cols-4 gap-10 mb-8">
<UButton v-for="tab in tabs" :key="tab.id" @click="activeTab = tab.id" :class="[
'px-15 py-2 cursor-pointer sm:text-nowrap flex items-center! justify-center!',
activeTab === tab.id
? 'bg-blue-600 hover:text-black hover:dark:text-white text-white'
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700'
]" variant="ghost">
{{ tab.label }}
</UButton>
</div>
<div class="py-5 px-3 bg-(--second-light) dark:bg-(--main-dark) rounded-md">
<p class="dark:text-white whitespace-pre-line">
{{ activeTabContent }}
</p>
</div>
</div>
<hr class="border-t border-(--border-light) dark:border-(--border-dark) mb-8" />
<ProductVariants />
</div>
<ProductCustomization />
<hr class="border-t border-(--border-light) dark:border-(--border-dark) mb-8" />
<div class="mb-6 w-[100%] xl:w-[60%]">
<div class="grid grid-cols-2 lg:grid-cols-4 gap-10 mb-8">
<UButton v-for="tab in tabs" :key="tab.id" @click="activeTab = tab.id" :class="[
'px-15 py-2 cursor-pointer sm:text-nowrap flex items-center! justify-center!',
activeTab === tab.id
? 'bg-blue-600 hover:text-black hover:dark:text-white text-white'
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700'
]" variant="ghost">
{{ tab.label }}
</UButton>
</div>
<div class="py-5 px-3 bg-(--second-light) dark:bg-(--main-dark) rounded-md">
<p class="dark:text-white whitespace-pre-line">
{{ activeTabContent }}
</p>
</div>
</div>
<hr class="border-t border-(--border-light) dark:border-(--border-dark) mb-8" />
<ProductVariants />
</div>
</component>
</template>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import ProductCustomization from './components/ProductCustomization.vue'
import ProductVariants from './components/ProductVariants.vue'
import Default from '@/layouts/default.vue'
import { useFetchJson } from '@/composable/useFetchJson'
import { useRoute } from 'vue-router'
interface Color {
id: string
name: string
@@ -97,6 +105,7 @@ interface ProductData {
howToUseText: string
productDetailsText: string
documentsText: string
is_favorite: boolean
}
const activeTab = ref('description')
@@ -157,6 +166,24 @@ const activeTabContent = computed(() => {
if (productData.colors.length > 0) {
selectedColor.value = productData.colors[0] as Color
}
const route = useRoute()
async function toggleFavorite() {
const url = `/api/v1/restricted/product/favorite/${route.params.product_id}`
try {
if (!productData.is_favorite) {
await useFetchJson(url, { method: 'POST' })
} else {
await useFetchJson(url, { method: 'DELETE' })
}
productData.is_favorite = !productData.is_favorite
} catch (e: unknown) {
console.error(e)
}
}
</script>
<style scoped>

View File

@@ -1,7 +1,6 @@
<template>
<suspense>
<component :is="Default || 'div'">
<div class="container mx-auto">
<div class="">
<!-- <UNavigationMenu orientation="vertical" :items="listing" class="data-[orientation=vertical]:w-48">
<template #item="{ item, active }">
<div class="flex items-center gap-2 px-3 py-2">
@@ -11,51 +10,47 @@
</template>
</UNavigationMenu> -->
<h1 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">Products</h1>
<div v-if="loading" class="text-center py-8">
<div v-if="customerProductStore.loading" class="text-center py-8">
<span class="text-gray-600 dark:text-gray-400">Loading products...</span>
</div>
<div v-else-if="error" class="mb-4 p-3 bg-red-100 text-red-700 rounded">
{{ error }}
<div v-else-if="customerProductStore.error" class="mb-4 p-3 bg-red-100 text-red-700 rounded">
{{ customerProductStore.error }}
</div>
<div v-else class="overflow-x-auto">
<div class="flex gap-2">
<CategoryMenu />
<UTable :data="productsList" :columns="columns" class="flex-1">
<UTable :data="customerProductStore.productsList" :columns="columns" class="flex-1">
<template #expanded="{ row }">
<UTable :data="productsList.slice(0, 3)" :columns="columnsChild" :ui="{
thead: 'hidden'
}" />
<UTable :data="customerProductStore.productsList.slice(0, 3)" :columns="columnsChild"
:ui="{
thead: 'hidden'
}" />
</template>
</UTable>
</div>
<div class="flex justify-center items-center py-8">
<UPagination v-model:page="page" :total="total" :page-size="perPage" />
<UPagination v-model:page="page" :total="customerProductStore.total"
:page-size="customerProductStore.perPage" />
</div>
<div v-if="productsList.length === 0" class="text-center py-8 text-gray-500 dark:text-gray-400">
<div v-if="customerProductStore.productsList.length === 0"
class="text-center py-8 text-gray-500 dark:text-gray-400">
No products found
</div>
</div>
</div>
</component>
</suspense>
</suspense>
</template>
<script setup lang="ts">
import { ref, watch, h, resolveComponent, computed } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
import Default from '@/layouts/default.vue'
import { useRoute, useRouter } from 'vue-router'
import type { TableColumn } from '@nuxt/ui'
import CategoryMenu from '../inner/categoryMenu.vue'
import CategoryMenu from '../inner/CategoryMenu.vue'
import { useCustomerProductStore } from '@/stores/customer/customer-product'
import type { Product } from '@/stores/customer/customer-product'
interface Product {
reference: number
product_id: number
name: string
image_link: string
link_rewrite: string
}
const customerProductStore = useCustomerProductStore()
const router = useRouter()
const route = useRoute()
@@ -101,18 +96,6 @@ const sortField = computed({
}
})
const perPage = ref(15)
const total = ref(0)
interface ApiResponse {
message: string
items: Product[]
count: number
}
const productsList = ref<Product[]>([])
const loading = ref(true)
const error = ref<string | null>(null)
const filters = computed<Record<string, string>>({
get: () => {
const q = { ...route.query }
@@ -157,36 +140,16 @@ const updateFilter = debounce((columnId: string, val: string) => {
filters.value = newFilters
}, 400)
async function fetchProductList() {
loading.value = true
error.value = null
const params = new URLSearchParams()
Object.entries(route.query).forEach(([key, value]) => {
if (value) params.append(key, String(value))
})
const url = `/api/v1/restricted/list/list-products?${params}`
try {
const response = await useFetchJson<ApiResponse>(url)
productsList.value = response.items || []
total.value = response.count || 0
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Failed to load products'
} finally {
loading.value = false
}
}
function goToProduct(productId: number) {
router.push({
name: 'product-detail',
params: { id: productId }
name: 'customer-product-details',
params: { product_id: productId }
})
}
const selectedCount = ref({
product_id: null,
count: 0
@@ -205,7 +168,7 @@ const UInput = resolveComponent('UInput')
const UButton = resolveComponent('UButton')
const UIcon = resolveComponent('UIcon')
const columns: TableColumn<Payment>[] = [
const columns: TableColumn<Product>[] = [
{
id: 'expand',
cell: ({ row }) =>
@@ -351,6 +314,35 @@ const columns: TableColumn<Payment>[] = [
variant: 'solid'
}, 'Add to cart')
},
},
{
accessorKey: 'count',
header: '',
cell: ({ row }) => {
return h(UButton, {
onClick: () => {
goToProduct(row.original.product_id)
},
class: 'cursor-pointer',
color: 'info',
variant: 'soft'
}, () => 'Show product')
},
},
{
accessorKey: 'counta',
header: '',
cell: ({ row }) => {
return h(UIcon, {
onClick: () => customerProductStore.toggleFavorite(row.original),
class: [
'cursor-pointer text-[20px] transition-transform duration-200 hover:scale-125',
row.original.is_favorite ? 'text-red-500' : 'text-blue-500'
],
name: 'material-symbols:favorite',
variant: 'soft',
})
}
}
]
@@ -417,13 +409,27 @@ const columnsChild: TableColumn<Payment>[] = [
variant: 'solid'
}, 'Add to cart')
},
},
{
accessorKey: 'count',
header: '',
cell: ({ row }) => {
return h(UButton, {
onClick: () => {
goToProduct(row.original.product_id)
},
class: 'cursor-pointer',
color: 'info',
variant: 'soft'
}, () => 'Show product')
},
}
]
watch(
() => route.query,
() => {
fetchProductList()
customerProductStore.fetchProductList()
},
{ immediate: true }
)

View File

@@ -1,6 +1,5 @@
<template>
<component :is="Default || 'div'">
<div class="container mx-auto">
<div class="">
<div class="flex flex-col gap-5 mb-6">
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Customer Data') }}</h1>
@@ -24,7 +23,7 @@
class="bg-(--second-light) dark:bg-(--main-dark) rounded-lg border border-(--border-light) dark:border-(--border-dark) p-4">
<h2 class="text-xl font-semibold text-black dark:text-white mb-4 flex items-center gap-2">
<UIcon name="mdi:domain"
class="text-[24px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
class="text-[24px] text-(--text-sky-light) dark:text-(--text-sky-dark)" />
{{ t('Company Information') }}
</h2>
<div class="grid grid-cols-1 gap-10">
@@ -65,7 +64,7 @@
<h2
class="text-xl font-semibold text-black dark:text-white mb-2 flex items-center gap-2">
<UIcon name="mdi:map-marker"
class="text-[24px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
class="text-[24px] text-(--text-sky-light) dark:text-(--text-sky-dark)" />
{{ t('Addresses') }}
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
@@ -88,7 +87,7 @@
</div>
<div class="flex justify-end">
<UButton color="primary" variant="outline"
class="text-(--accent-blue-light) dark:text-(--accent-blue-dark) border-(--accent-blue-light) dark:border-(--accent-blue-dark)"
class="text-(--text-sky-light) dark:text-(--text-sky-dark) border-(--accent-blue-light) dark:border-(--accent-blue-dark)"
@click="goToCreateAccount">
<UIcon name="ic:sharp-edit" />
{{ t('Edit Account') }}
@@ -97,16 +96,14 @@
</div>
</div>
</div>
</component>
</template>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { useCustomerStore } from '@/stores/customer'
import { useAddressStore } from '@/stores/address'
import { useAddressStore } from '@/stores/customer/address'
import { useI18n } from 'vue-i18n'
import Default from '@/layouts/default.vue'
const router = useRouter()
const customerStore = useCustomerStore()
const addressStore = useAddressStore()

View File

@@ -1,6 +1,5 @@
<template>
<component :is="Default || 'div'">
<div class="container mx-auto">
<div class="">
<div class="max-w-2xl mx-auto">
<div class="flex flex-col gap-5 mb-6">
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Create Account') }}</h1>
@@ -11,7 +10,7 @@
<h2
class="text-lg font-semibold text-black dark:text-white mb-4 flex items-center gap-2">
<UIcon name="mdi:domain"
class="text-[20px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
class="text-[20px] text-(--text-sky-light) dark:text-(--text-sky-dark)" />
{{ t('Company Information') }}
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
@@ -54,7 +53,7 @@
<h2
class="text-lg font-semibold text-black dark:text-white mb-4 flex items-center gap-2">
<UIcon name="mdi:map-marker"
class="text-[20px] text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
class="text-[20px] text-(--text-sky-light) dark:text-(--text-sky-dark)" />
{{ t('Select Addresses') }}
</h2>
<div class="bg-(--second-light) dark:bg-(--main-dark)">
@@ -70,7 +69,7 @@
? 'border-(--accent-blue-light) dark:border-(--accent-blue-dark) bg-blue-50 dark:bg-blue-900/20'
: 'border-(--border-light) dark:border-(--border-dark) hover:border-gray-400'">
<input type="radio" :value="address.id" v-model="selectedAddress"
class="mt-1 w-4 h-4 text-(--accent-blue-light) dark:text-(--accent-blue-dark)" />
class="mt-1 w-4 h-4 text-(--text-sky-light) dark:text-(--text-sky-dark)" />
<div class="flex-1">
<p class="text-black dark:text-white font-medium">{{ address.street }}
</p>
@@ -87,7 +86,7 @@
<UIcon name="mdi:map-marker-outline" class="text-4xl text-gray-400 mb-2" />
<p class="text-gray-500 dark:text-gray-400">{{ t('No addresses found') }}</p>
<RouterLink :to="{ name: 'addresses' }"
class="inline-block mt-2 text-(--accent-blue-light) dark:text-(--accent-blue-dark) hover:underline">
class="inline-block mt-2 text-(--text-sky-light) dark:text-(--text-sky-dark) hover:underline">
{{ t('Add Address') }}
</RouterLink>
</div>
@@ -109,17 +108,15 @@
</div>
</div>
</div>
</component>
</template>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useCustomerStore } from '@/stores/customer'
import { useAddressStore } from '@/stores/address'
import { useAddressStore } from '@/stores/customer/address'
import { useI18n } from 'vue-i18n'
import { useCartStore } from '@/stores/cart'
import Default from '@/layouts/default.vue'
import { useCartStore } from '@/stores/customer/cart'
const router = useRouter()
const customerStore = useCustomerStore()
const addressStore = useAddressStore()

View File

@@ -1,9 +1,6 @@
<template>
<component :is="Default || 'div'">
Statistic page
</component>
</template>
Statistic page
</template>
<script lang="ts" setup>
import Default from '@/layouts/default.vue'
</script>

View File

@@ -0,0 +1,158 @@
<template>
<div class="p-4">
<div v-if="loading" class="flex justify-center py-8">
<ULoader />
</div>
<div v-else-if="error" class="text-red-500">
{{ error }}
</div>
<UTree v-if="showTree" :items="treeItems" v-model:expanded="expandedFolders" :key="treeKey" @toggle="onToggle" :get-key="item => item.value">
<template #item-wrapper="{ item }">
<div class="flex items-start cursor-pointer" @click.stop="!item.isFolder">
<div class="flex items-center gap-1">
<UIcon :name="item.icon" :size="30" />
<div class="flex gap-1 items-center">
<span class="text-[15px] font-medium">
{{ item.label }}
</span>
<UButton v-if="!item.isFolder && item.fileName" size="xxs" color="neutral"
variant="outline" icon="i-lucide-download"
@click.stop="downloadFile(item.path, item.fileName)" :ui="{ base: 'ring-0!' }" />
</div>
</div>
</div>
</template>
</UTree>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
interface FileItemRaw {
Name: string
IsFolder: boolean
}
interface FileItem {
name: string
type: 'file' | 'folder'
}
interface TreeItem {
label: string
icon: string
children?: TreeItem[]
isFolder: boolean
path: string
value: string
fileName?: string
}
const props = defineProps<{ initialPath?: string }>()
const currentPath = ref(props.initialPath || '')
const allData = ref<Record<string, FileItem[]>>({})
const expandedFolders = ref<string[]>([])
const treeKey = ref(0)
const loading = ref(false)
const error = ref<string | null>(null)
const showTree = computed(() => !error.value)
async function fetchFolderContents(path: string): Promise<FileItem[]> {
const url = `/api/v1/restricted/storage/list-content/${path}`
const data = await useFetchJson<FileItemRaw[]>(url)
return (data.items || []).map(i => ({
name: i.Name,
type: i.IsFolder ? 'folder' : 'file'
}))
}
async function loadFolder(path: string) {
if (allData.value[path]) return
try {
const items = await fetchFolderContents(path)
allData.value[path] = items
} catch (e) {
error.value = e instanceof Error ? e.message : 'Failed to load folder contents'
}
}
function buildTree(path: string): TreeItem[] {
const items = allData.value[path] || []
return items.map(item => {
const itemPath = path ? `${path}/${item.name}` : item.name
const isFolder = item.type === 'folder'
const isExpanded = expandedFolders.value.includes(itemPath)
const isLoaded = !!allData.value[itemPath]
return {
label: item.name,
icon: isFolder ? 'fxemoji:folder' : 'flat-color-icons:file',
isFolder,
path: isFolder ? itemPath : path,
value: itemPath,
fileName: isFolder ? undefined : item.name,
children: isFolder && isExpanded && isLoaded
? buildTree(itemPath)
: []
}
})
}
const treeItems = computed(() => buildTree(currentPath.value))
async function toggleFolder(item: TreeItem) {
if (!item.isFolder) return
const isOpen = expandedFolders.value.includes(item.value)
if (!isOpen) {
await loadFolder(item.value)
treeKey.value++
} else {
treeKey.value++
}
}
function onToggle(_event: unknown, item: TreeItem) {
console.log('Toggle:', item)
if (item.isFolder) {
toggleFolder(item)
}
}
async function downloadFile(path: string, fileName: string) {
try {
const response = await fetch(`/api/v1/restricted/storage/download-file/${path}/${fileName}`)
if (!response.ok) throw new Error('Download failed')
const blob = await response.blob()
const url = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = fileName
document.body.appendChild(a)
a.click()
a.remove()
window.URL.revokeObjectURL(url)
} catch (e) {
console.error(e)
alert('Download failed')
}
}
loadFolder(currentPath.value)
</script>

View File

@@ -1,5 +1,7 @@
<template>
<UNavigationMenu orientation="vertical" type="single" :items="items" class="data-[orientation=vertical]:w-72" />
<UNavigationMenu orientation="vertical" type="single" :items="items" class="data-[orientation=vertical]:w-72" :ui="{
root: ''
}" />
</template>
<script setup lang="ts">
@@ -37,9 +39,10 @@ function adaptMenu(menu: NavigationMenuItem[]) {
if (item.children && item.children.length > 0) {
item.open = path && path.includes(item.category_id) ? true : openAll.value
adaptMenu(item.children);
item.children.unshift({
label: item.label, icon: 'i-lucide-book-open', popover: item.label, to: {
name: 'customer-products-category', params: {
name: item.params.to, params: {
category_id: item.params.category_id,
link_rewrite: item.params.link_rewrite
}
@@ -47,7 +50,7 @@ function adaptMenu(menu: NavigationMenuItem[]) {
})
} else {
item.to = {
name: 'customer-products-category', params: {
name: item.params.to, params: {
category_id: item.params.category_id,
link_rewrite: item.params.link_rewrite
}

View File

@@ -0,0 +1,53 @@
<template>
<USelectMenu v-model="country" :items="countries" value-key="id"
class="w-48 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm" :searchInput="false">
<template #default>
<div class="flex flex-col items-start leading-tight">
<span class="text-xs text-gray-400">
Country/Currency
</span>
<span v-if="country" class="font-medium dark:text-white text-black">
{{ country?.name || 'Country' }} / {{ country?.ps_currency || 'Currency' }}
</span>
</div>
</template>
<template #item-leading="{ item }">
<div class="flex items-center gap-2 cursor-pointer">
<span class="text-lg">{{ item.flag }}</span>
<span class="font-medium dark:text-white text-black">
{{ item.name }}
</span>
</div>
</template>
</USelectMenu>
</template>
<script setup lang="ts">
import { countries, currentCountry, switchLocalization } from '@/router/langs'
import { useCookie } from '@/composable/useCookie'
import { computed, watch } from 'vue'
const cookie = useCookie()
const country = computed({
get() {
return currentCountry.value
},
set(value: string) {
currentCountry.value = countries.find((x) => x.id == Number(value))
cookie.setCookie('country_id', `${countries.find((x) => x.id == Number(value))?.id}`, { days: 60, secure: true, sameSite: 'Lax' })
switchLocalization()
},
})
watch(
() => country,
(newCountry) => {
if (newCountry) {
currentCountry.value = countries.find((x) => x.id == Number(newCountry.value?.id))
}
},
{ immediate: true },
)
</script>

View File

@@ -1,34 +1,47 @@
<template>
<USelectMenu v-model="locale" :items="langs"
class="w-40 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm hover:none!" valueKey="iso_code"
:searchInput="false">
<template #default="{ modelValue }">
<div class="flex items-center gap-1">
<!-- <span class="text-md dark:text-white text-black">{{langs.find(x => x.iso_code == modelValue)?.flag}}</span> -->
<span class="font-medium dark:text-white text-black">{{langs.find(x => x.iso_code == modelValue)?.name}}</span>
<USelectMenu v-model="locale" :items="langs" value-key="iso_code"
class="w-48 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm" :searchInput="false">
<template #default>
<div class="flex items-center gap-2">
<!-- <span class="text-lg">{{ selectedLang?.flag }}</span> -->
<div class="flex flex-col leading-tight items-start">
<span class="text-xs text-gray-400">
Language
</span>
<span class="font-medium dark:text-white text-black">
{{ selectedLang?.name || 'Select language' }}
</span>
</div>
</div>
</template>
<template #item-leading="{ item }">
<div class="flex items-center rounded-md cursor-pointer transition-colors">
<!-- <span class="text-md ">{{ item.flag }}</span> -->
<span class="ml-2 dark:text-white text-black font-medium">{{ item.name }}</span>
<div class="flex items-center gap-2">
<span class="text-lg">{{ item.flag }}</span>
<span class="font-medium dark:text-white text-black">
{{ item.name }}
</span>
</div>
</template>
</USelectMenu>
</template>
<script setup lang="ts">
import { langs, currentLang } from '@/router/langs'
import { langs, currentLang, switchLocalization } from '@/router/langs'
import { useRouter, useRoute } from 'vue-router'
import { useCookie } from '@/composable/useCookie'
import { computed, watch } from 'vue'
import { i18n } from '@/plugins/02_i18n'
import { useFetchJson } from '@/composable/useFetchJson'
const router = useRouter()
const route = useRoute()
const cookie = useCookie()
const selectedLang = computed(() =>
langs.find(item => item.iso_code === locale.value)
)
const cookie = useCookie()
const locale = computed({
get() {
return currentLang.value?.iso_code || i18n.locale.value
@@ -52,21 +65,10 @@ const locale = computed({
}
}
changeLang()
switchLocalization()
},
})
async function changeLang() {
try {
const { items } = await useFetchJson('/api/v1/public/auth/update-choice', {
method: 'POST'
})
} catch (error) {
console.log(error)
}
}
watch(
() => route.params.locale,
(newLocale) => {

View File

@@ -0,0 +1,160 @@
<template>
<UEditor v-slot="{ editor }" v-model="localValue" content-type="html"
:ui="{ base: 'p-8 sm:px-16', root: 'p-2' }"
class="min-w-full border rounded-md bg-white! border-(--border-light)" placeholder="Write there ...">
<UEditorToolbar :editor="editor" :items="toolbarItems" class="sm:px-8 flex-wrap!">
<template #link>
<EditorLinkPopover :editor="editor" auto-open />
</template>
</UEditorToolbar>
</UEditor>
</template>
<script lang="ts" setup>
import type { EditorToolbarItem } from '@nuxt/ui';
import { computed } from 'vue';
const props = defineProps<{
modelValue: string
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void
}>()
const localValue = computed({
get: () => props.modelValue,
set: (value: string) => emit('update:modelValue', value)
})
const toolbarItems: EditorToolbarItem[][] = [
// History controls
[{
kind: 'undo',
icon: 'i-lucide-undo',
tooltip: { text: 'Undo' }
}, {
kind: 'redo',
icon: 'i-lucide-redo',
tooltip: { text: 'Redo' }
}],
// Block types
[{
icon: 'i-lucide-heading',
tooltip: { text: 'Headings' },
content: {
align: 'start'
},
items: [{
kind: 'heading',
level: 1,
icon: 'i-lucide-heading-1',
label: 'Heading 1'
}, {
kind: 'heading',
level: 2,
icon: 'i-lucide-heading-2',
label: 'Heading 2'
}, {
kind: 'heading',
level: 3,
icon: 'i-lucide-heading-3',
label: 'Heading 3'
}, {
kind: 'heading',
level: 4,
icon: 'i-lucide-heading-4',
label: 'Heading 4'
}]
}, {
icon: 'i-lucide-list',
tooltip: { text: 'Lists' },
content: {
align: 'start'
},
items: [{
kind: 'bulletList',
icon: 'i-lucide-list',
label: 'Bullet List'
}, {
kind: 'orderedList',
icon: 'i-lucide-list-ordered',
label: 'Ordered List'
}]
}, {
kind: 'blockquote',
icon: 'i-lucide-text-quote',
tooltip: { text: 'Blockquote' }
}, {
kind: 'codeBlock',
icon: 'i-lucide-square-code',
tooltip: { text: 'Code Block' }
}, {
kind: 'horizontalRule',
icon: 'i-lucide-separator-horizontal',
tooltip: { text: 'Horizontal Rule' }
}],
// Text formatting
[{
kind: 'mark',
mark: 'bold',
icon: 'i-lucide-bold',
tooltip: { text: 'Bold' }
}, {
kind: 'mark',
mark: 'italic',
icon: 'i-lucide-italic',
tooltip: { text: 'Italic' }
}, {
kind: 'mark',
mark: 'underline',
icon: 'i-lucide-underline',
tooltip: { text: 'Underline' }
}, {
kind: 'mark',
mark: 'strike',
icon: 'i-lucide-strikethrough',
tooltip: { text: 'Strikethrough' }
}, {
kind: 'mark',
mark: 'code',
icon: 'i-lucide-code',
tooltip: { text: 'Code' }
}],
// Link
[{
kind: 'link',
icon: 'i-lucide-link',
tooltip: { text: 'Link' }
}],
// Text alignment
[{
icon: 'i-lucide-align-justify',
tooltip: { text: 'Text Align' },
content: {
align: 'end'
},
items: [{
kind: 'textAlign',
align: 'left',
icon: 'i-lucide-align-left',
label: 'Align Left'
}, {
kind: 'textAlign',
align: 'center',
icon: 'i-lucide-align-center',
label: 'Align Center'
}, {
kind: 'textAlign',
align: 'right',
icon: 'i-lucide-align-right',
label: 'Align Right'
}, {
kind: 'textAlign',
align: 'justify',
icon: 'i-lucide-align-justify',
label: 'Align Justify'
}]
}]
]
</script>

View File

@@ -0,0 +1,37 @@
<template>
<UButton variant="outline" size="sm" color="info" @click="themeStorage.setTheme()">
<span class="hidden sm:inline">
<UIcon class="size-5" :name="themeStorage.themeIcon" />
</span>
</UButton>
<!-- <UButton variant="solid" size="sm" color="info" @click="themeStorage.setTheme()">
<span class="hidden sm:inline">
<UIcon class="size-5" :name="themeStorage.themeIcon" />
</span>
</UButton>
<UButton variant="soft" size="sm" color="info" @click="themeStorage.setTheme()">
<span class="hidden sm:inline">
<UIcon class="size-5" :name="themeStorage.themeIcon" />
</span>
</UButton>
<UButton variant="subtle" size="sm" color="info" @click="themeStorage.setTheme()">
<span class="hidden sm:inline">
<UIcon class="size-5" :name="themeStorage.themeIcon" />
</span>
</UButton>
<UButton variant="ghost" size="sm" color="info" @click="themeStorage.setTheme()">
<span class="hidden sm:inline">
<UIcon class="size-5" :name="themeStorage.themeIcon" />
</span>
</UButton>
<UButton variant="link" size="sm" color="info" @click="themeStorage.setTheme()">
<span class="hidden sm:inline">
<UIcon class="size-5" :name="themeStorage.themeIcon" />
</span>
</UButton> -->
</template>
<script setup lang="ts">
import { useThemeStore } from '@/stores/admin/theme'
const themeStorage = useThemeStore()
</script>

View File

@@ -1,12 +0,0 @@
<template>
<UButton variant="ghost" size="sm" @click="themeStorage.setTheme()">
<span class="hidden sm:inline">
<UIcon class="size-5" :name="themeStorage.themeIcon" />
</span>
</UButton>
</template>
<script setup lang="ts">
import { useThemeStore } from '@/stores/theme'
const themeStorage = useThemeStore()
</script>

View File

@@ -29,7 +29,7 @@ export async function useFetchJson<T = unknown>(url: string, opt?: RequestInit):
// Handle 401 — access token expired; try to refresh via the HTTPOnly refresh_token cookie
if (res.status === 401) {
const { useAuthStore } = await import('@/stores/auth')
const { useAuthStore } = await import('../stores/customer/auth')
const authStore = useAuthStore()
const refreshed = await authStore.refreshAccessToken()

View File

@@ -1,14 +1,301 @@
<script setup lang="ts">
import TopBar from '@/components/TopBar.vue';
</script>
<template>
<div class="h-screen grid grid-rows-[auto_1fr_auto]">
<main class="pt-20 pb-10">
<TopBar />
<div class="container mx-auto px-4">
<div class="flex flex-1 overflow-x-hidden h-svh">
<USidebar v-model:open="open" collapsible="icon" rail :ui="{
container: 'h-full z-80',
inner: 'bg-elevated/25 divide-transparent',
body: 'py-0'
}">
<template #header>
<UDropdownMenu :items="teamsItems" :content="{ align: 'start', collisionPadding: 12 }"
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-48' }">
<UButton v-bind="selectedTeam" trailing-icon="i-lucide-chevrons-up-down" color="neutral" variant="ghost"
square class="w-full data-[state=open]:bg-elevated overflow-hidden" :ui="{
trailingIcon: 'text-dimmed ms-auto'
}" />
</UDropdownMenu>
</template>
<template #default="{ state }">
<UNavigationMenu :key="state" :items="menuItems" orientation="vertical"
:ui="{ link: 'p-1.5 overflow-hidden' }" />
</template>
<template #footer>
<UDropdownMenu :items="userItems" :content="{ align: 'center', collisionPadding: 12 }"
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-48' }">
<UButton v-bind="userStore.user" :label="userStore.user?.email" trailing-icon="i-lucide-chevrons-up-down"
color="neutral" variant="ghost" square class="w-full data-[state=open]:bg-elevated overflow-hidden" :ui="{
trailingIcon: 'text-dimmed ms-auto'
}" />
</UDropdownMenu>
<!-- first_name: '', last_name: '' -->
</template>
</USidebar>
<div class="flex-1 flex flex-col">
<div class="flex h-(--ui-header-height) shrink-0 items-center justify-between px-4 border-b border-default">
<div class="flex items-center gap-2">
<UButton icon="i-lucide-panel-left" color="neutral" variant="ghost" aria-label="Toggle sidebar"
@click="open = !open" />
<span class="text-[20px] font-medium">{{ pageTitle }}</span>
</div>
<div class="hidden md:flex items-center gap-12">
<div class="flex items-center gap-2">
<CountryCurrencySwitch />
<LangSwitch />
</div>
<div class="flex items-center gap-2">
<ThemeSwitch />
<button v-if="authStore.isAuthenticated" @click="authStore.logout()"
class="flex gap-2 items-center px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark) whitespace-nowrap">
{{ $t('general.logout') }}
<UIcon name="ic:baseline-logout" class="text-red-700 dark:text-red-500"/>
</button>
</div>
</div>
</div>
<div class="flex-1 p-4 bg-slate-50 dark:bg-(--main-dark)">
<slot />
</div>
</main>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useColorMode } from '@vueuse/core'
import type { DropdownMenuItem, NavigationMenuItem } from '@nuxt/ui'
import { defineShortcuts, extractShortcuts } from '@nuxt/ui/runtime/composables/defineShortcuts.js'
import { useAuthStore } from '../stores/customer/auth'
const authStore = useAuthStore()
const userStore = useUserStore()
const route = useRoute()
const pageTitle = computed(() => route.meta.name ?? 'Default Page')
await userStore.getUser()
const open = ref(true)
const colorMode = useColorMode()
const teams = ref([
{
label: 'Nuxt',
avatar: {
src: 'https://github.com/nuxt.png',
alt: 'Nuxt'
}
},
{
label: 'Vue',
avatar: {
src: 'https://github.com/vuejs.png',
alt: 'Vue'
}
},
{
label: 'UnJS',
avatar: {
src: 'https://github.com/unjs.png',
alt: 'UnJS'
}
}
])
const selectedTeam = ref(teams.value[0])
const teamsItems = computed<DropdownMenuItem[][]>(() => {
return [
teams.value.map((team, index) => ({
...team,
kbds: ['meta', String(index + 1)],
onSelect() {
selectedTeam.value = team
}
})),
[
{
label: 'Create team',
icon: 'i-lucide-circle-plus'
}
]
]
})
function getItems(state: 'collapsed' | 'expanded') {
return [
{
label: 'Inbox',
icon: 'i-lucide-inbox',
badge: '4'
},
{
label: 'Issues',
icon: 'i-lucide-square-dot'
},
{
label: 'Activity',
icon: 'i-lucide-square-activity'
},
{
label: 'Settings',
icon: 'i-lucide-settings',
defaultOpen: true,
children:
state === 'expanded'
? [
{
label: 'General',
icon: 'i-lucide-house'
},
{
label: 'Team',
icon: 'i-lucide-users'
},
{
label: 'Billing',
icon: 'i-lucide-credit-card'
}
]
: []
}
] satisfies NavigationMenuItem[]
}
//
import { useRoute, useRouter } from 'vue-router'
import { currentLang } from '@/router/langs'
import { useFetchJson } from '@/composable/useFetchJson'
import CountryCurrencySwitch from '@/components/inner/CountryCurrencySwitch.vue'
import LangSwitch from '@/components/inner/LangSwitch.vue'
import ThemeSwitch from '@/components/inner/ThemeSwitch.vue'
import type { LabelTrans, TopMenuItem } from '@/types'
import { useUserStore } from '@/stores/user'
const router = useRouter()
const menu = ref<TopMenuItem[] | null>(null)
async function getTopMenu() {
try {
const { items } = await useFetchJson<TopMenuItem[]>('/api/v1/restricted/menu/get-top-menu')
menu.value = items
} catch (err) {
console.log(err)
}
}
onMounted(() => {
getTopMenu()
})
const menuItems = computed(() => {
if (!menu.value?.length) return []
return transformMenu(
menu.value || [],
currentLang.value?.iso_code
)
})
function transformMenu(
items: TopMenuItem[],
locale: string | undefined
): NavigationMenuItem[] {
return items.map((item) => {
const route: NavigationMenuItem = {
icon: item.label.icon || 'i-lucide-house',
label:
item.label.trans?.[locale as keyof LabelTrans]?.label ||
item.label.trans?.en?.label ||
'—',
children: item.children
? transformMenu(item.children, locale)
: undefined,
onSelect: () => {
router.push({
name: item.params.route.name,
params: {
...(item.params.route.params || {}),
locale: currentLang.value?.iso_code
}
})
}
}
return route
})
}
const userItems = computed<DropdownMenuItem[][]>(() => [
[
{
label: 'Profile',
icon: 'i-lucide-user'
},
{
label: 'Billing',
icon: 'i-lucide-credit-card'
},
{
label: 'Settings',
icon: 'i-lucide-settings',
to: '/settings'
}
],
[
{
label: 'Appearance',
icon: 'i-lucide-sun-moon',
children: [
{
label: 'Light',
icon: 'i-lucide-sun',
type: 'checkbox',
checked: colorMode.value === 'light',
onUpdateChecked(checked: boolean) {
if (checked) {
colorMode.preference = 'light'
}
},
onSelect(e: Event) {
e.preventDefault()
}
},
{
label: 'Dark',
icon: 'i-lucide-moon',
type: 'checkbox',
checked: colorMode.value === 'dark',
onUpdateChecked(checked: boolean) {
if (checked) {
colorMode.preference = 'dark'
}
},
onSelect(e: Event) {
e.preventDefault()
}
}
]
}
],
[
{
label: 'GitHub',
icon: 'i-simple-icons-github',
to: 'https://github.com/nuxt/ui',
target: '_blank'
},
{
label: 'Log out',
icon: 'i-lucide-log-out'
}
]
])
defineShortcuts(extractShortcuts(teamsItems.value))
</script>

View File

@@ -0,0 +1,309 @@
<template>
<div class="flex flex-1 overflow-x-hidden h-svh">
<USidebar v-model:open="open" collapsible="icon" rail :ui="{
container: 'h-full z-80',
inner: 'bg-elevated/25 divide-transparent',
body: 'py-0'
}">
<template #header>
<UDropdownMenu :items="teamsItems" :content="{ align: 'start', collisionPadding: 12 }"
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-48' }">
<UButton v-bind="selectedTeam" trailing-icon="i-lucide-chevrons-up-down" color="neutral"
variant="ghost" square class="w-full data-[state=open]:bg-elevated overflow-hidden" :ui="{
trailingIcon: 'text-dimmed ms-auto'
}" />
</UDropdownMenu>
</template>
<template #default="{ state }">
<UNavigationMenu :key="state" :items="menuItems" orientation="vertical"
:ui="{ link: 'p-1.5 overflow-hidden' }" />
</template>
<template #footer>
<UDropdownMenu :items="userItems" :content="{ align: 'center', collisionPadding: 12 }"
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-48' }">
<UButton v-bind="userStore.user" :label="userStore.user?.email"
trailing-icon="i-lucide-chevrons-up-down" color="neutral" variant="ghost" square
class="w-full data-[state=open]:bg-elevated overflow-hidden" :ui="{
trailingIcon: 'text-dimmed ms-auto'
}" />
</UDropdownMenu>
<!-- first_name: '', last_name: '' -->
</template>
</USidebar>
<div class="flex-1 flex flex-col">
<div class="flex h-(--ui-header-height) shrink-0 items-center justify-between px-4 border-b border-default">
<div class="flex items-center gap-2">
<UButton icon="i-lucide-panel-left" color="neutral" variant="ghost" aria-label="Toggle sidebar"
@click="open = !open" />
<p class="font-bold text-xl">Customer-Management: <span class="text-[20px] font-medium">{{ pageTitle
}}</span></p>
</div>
<div class="hidden md:flex items-center gap-12">
<div class="flex items-center gap-2">
<CountryCurrencySwitch />
<LangSwitch />
</div>
<div class="flex items-center gap-2">
<ThemeSwitch />
<button v-if="authStore.isAuthenticated" @click="authStore.logout()"
class="flex gap-2 items-center px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark) whitespace-nowrap">
{{ $t('general.logout') }}
<UIcon name="ic:baseline-logout" class="text-red-700 dark:text-red-500" />
</button>
</div>
</div>
</div>
<div class="flex-1 p-4 bg-slate-50 dark:bg-(--main-dark)">
<slot />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useColorMode } from '@vueuse/core'
import type { DropdownMenuItem, NavigationMenuItem } from '@nuxt/ui'
import { defineShortcuts, extractShortcuts } from '@nuxt/ui/runtime/composables/defineShortcuts.js'
import { useAuthStore } from '../stores/customer/auth'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageTitle = computed(() => route.meta.name ?? 'Default Page')
const authStore = useAuthStore()
const userStore = useUserStore()
const open = ref(true)
const colorMode = useColorMode()
const teams = ref([
{
label: 'Nuxt',
avatar: {
src: 'https://github.com/nuxt.png',
alt: 'Nuxt'
}
},
{
label: 'Vue',
avatar: {
src: 'https://github.com/vuejs.png',
alt: 'Vue'
}
},
{
label: 'UnJS',
avatar: {
src: 'https://github.com/unjs.png',
alt: 'UnJS'
}
}
])
const selectedTeam = ref(teams.value[0])
const teamsItems = computed<DropdownMenuItem[][]>(() => {
return [
teams.value.map((team, index) => ({
...team,
kbds: ['meta', String(index + 1)],
onSelect() {
selectedTeam.value = team
}
})),
[
{
label: 'Create team',
icon: 'i-lucide-circle-plus'
}
]
]
})
function getItems(state: 'collapsed' | 'expanded') {
return [
{
label: 'Inbox',
icon: 'i-lucide-inbox',
badge: '4'
},
{
label: 'Issues',
icon: 'i-lucide-square-dot'
},
{
label: 'Activity',
icon: 'i-lucide-square-activity'
},
{
label: 'Settings',
icon: 'i-lucide-settings',
defaultOpen: true,
children:
state === 'expanded'
? [
{
label: 'General',
icon: 'i-lucide-house'
},
{
label: 'Team',
icon: 'i-lucide-users'
},
{
label: 'Billing',
icon: 'i-lucide-credit-card'
}
]
: []
}
] satisfies NavigationMenuItem[]
}
//
import { useRouter } from 'vue-router'
import { currentLang } from '@/router/langs'
import { useFetchJson } from '@/composable/useFetchJson'
import CountryCurrencySwitch from '@/components/inner/CountryCurrencySwitch.vue'
import LangSwitch from '@/components/inner/LangSwitch.vue'
import ThemeSwitch from '@/components/inner/ThemeSwitch.vue'
import type { LabelTrans, TopMenuItem } from '@/types'
import { useUserStore } from '@/stores/user'
import { watch } from 'vue'
const router = useRouter()
const menu = ref<TopMenuItem[] | null>(null)
const Id = Number(route.params.user_id)
async function cmGetTopMenu() {
try {
const { items } = await useFetchJson<TopMenuItem[]>(`/api/v1/restricted/menu/get-top-menu?target_user_id=${Id}`)
menu.value = items
} catch (err) {
console.log(err)
}
}
watch(
() => route.params.user_id,
() => {
if (route.params.user_id) {
cmGetTopMenu()
}
},
{ immediate: true }
)
const menuItems = computed(() => {
if (!menu.value?.length) return []
return transformMenu(
menu.value || [],
currentLang.value?.iso_code
)
})
function transformMenu(
items: TopMenuItem[],
locale: string | undefined
): NavigationMenuItem[] {
return items.map((item) => {
const route: NavigationMenuItem = {
icon: item.label.icon || 'i-lucide-house',
label:
item.label.trans?.[locale as keyof LabelTrans]?.label ||
item.label.trans?.en?.label ||
'—',
children: item.children
? transformMenu(item.children, locale)
: undefined,
onSelect: () => {
router.push({
name: item.params.route.name,
params: {
...(item.params.route.params || {}),
locale: currentLang.value?.iso_code
}
})
}
}
return route
})
}
const userItems = computed<DropdownMenuItem[][]>(() => [
[
{
label: 'Profile',
icon: 'i-lucide-user'
},
{
label: 'Billing',
icon: 'i-lucide-credit-card'
},
{
label: 'Settings',
icon: 'i-lucide-settings',
to: '/settings'
}
],
[
{
label: 'Appearance',
icon: 'i-lucide-sun-moon',
children: [
{
label: 'Light',
icon: 'i-lucide-sun',
type: 'checkbox',
checked: colorMode.value === 'light',
onUpdateChecked(checked: boolean) {
if (checked) {
colorMode.preference = 'light'
}
},
onSelect(e: Event) {
e.preventDefault()
}
},
{
label: 'Dark',
icon: 'i-lucide-moon',
type: 'checkbox',
checked: colorMode.value === 'dark',
onUpdateChecked(checked: boolean) {
if (checked) {
colorMode.preference = 'dark'
}
},
onSelect(e: Event) {
e.preventDefault()
}
}
]
}
],
[
{
label: 'GitHub',
icon: 'i-simple-icons-github',
to: 'https://github.com/nuxt/ui',
target: '_blank'
},
{
label: 'Log out',
icon: 'i-lucide-log-out'
}
]
])
defineShortcuts(extractShortcuts(teamsItems.value))
</script>

View File

@@ -1,11 +1,12 @@
import { useFetchJson } from '@/composable/useFetchJson'
import { initLangs, langs } from '@/router/langs'
import { initCountryCurrency, initLangs, langs } from '@/router/langs'
import { watch } from 'vue'
import { createI18n, type PathValue } from 'vue-i18n'
// const x =
await initLangs()
await initCountryCurrency()
export const i18ninstall = createI18n({
legacy: false, // you must set `false`, to use Composition API
locale: 'en',

View File

@@ -1,24 +1,42 @@
import { createRouter, createWebHistory } from 'vue-router'
import { currentLang, langs } from './langs'
import { currentLang, langs, switchLocalization } from './langs'
import { getSettings } from './settings'
import { useAuthStore } from '@/stores/auth'
import { useAuthStore } from '@/stores/customer/auth'
import { getRoutes } from './menu'
function isAuthenticated(): boolean {
if (typeof document === 'undefined') return false
return document.cookie.split('; ').some((c) => c === 'is_authenticated=1')
}
await switchLocalization()
await getSettings()
const routes = await getRoutes()
let newRoutes = []
function getLayoutFromComponent(path: string) {
const emptyLayouts = [
'LoginView.vue',
'RegisterView.vue',
'PasswordRecoveryView.vue',
'VerifyEmailView.vue',
'ResetPasswordForm.vue'
]
return emptyLayouts.some((name) => path.includes(name)) ? 'empty' : 'default'
}
for (let r of routes) {
const component = () => import(/* @vite-ignore */ `..${r.component}`)
const parsedMeta = r.meta ? JSON.parse(r.meta) : {}
const layout = parsedMeta.layout ?? getLayoutFromComponent(r.component)
newRoutes.push({
path: r.path,
component,
name: r.name,
meta: r.meta ? JSON.parse(r.meta) : {},
meta: {
...parsedMeta,
layout,
},
})
}
@@ -59,7 +77,7 @@ async function setRoutes() {
const componentName = item.component
const [, folder] = componentName.split('/')
const componentPath = `/src${componentName}`
let modules =
folder === 'views' ? viewModules : componentModules
@@ -72,14 +90,22 @@ async function setRoutes() {
}
const importedComponent = (await importer()).default
const parsedMeta = item.meta ? JSON.parse(item.meta) : {}
const layout = parsedMeta.layout ?? getLayoutFromComponent(item.component)
router.addRoute('locale', {
path: item.path,
component: importedComponent,
name: item.name,
meta: item.meta ? JSON.parse(item.meta) : {}
meta: {
...parsedMeta,
layout,
}
})
}
console.log(router);
// await router.replace(router.currentRoute.value.fullPath)
}
await setRoutes()

View File

@@ -1,30 +1,67 @@
import { useCookie } from "@/composable/useCookie"
import { useFetchJson } from "@/composable/useFetchJson"
import type { Language } from "@/types"
import type { Country, Language } from "@/types"
import { reactive, ref } from "vue"
export const langs = reactive([] as Language[])
export const currentLang = ref<Language>()
const deflang = ref<Language>()
export const countries = reactive([] as Country[])
export const currentCountry = ref<Country>()
const defLang = ref<Language>()
const defCountry = ref<Country>()
const cookie = useCookie()
// Get available language codes for route matching
// export const availableLocales = computed(() => langs.map((l) => l.lang_code))
// Initialize languages from API
export async function initLangs() {
try {
const { items } = await useFetchJson<Language[]>('/api/v1/langs')
langs.push(...items)
try {
const { items } = await useFetchJson<Language[]>('/api/v1/langs')
langs.push(...items)
let idfromcookie = null
const cc = cookie.getCookie('lang_id')
if (cc) {
idfromcookie = langs.find((x) => x.id == parseInt(cc))
}
deflang.value = items.find((x) => x.is_default == true)
currentLang.value = idfromcookie ?? deflang.value
} catch (error) {
console.error('Failed to fetch languages:', error)
let idfromcookie = null
const cc = cookie.getCookie('lang_id')
if (cc) {
idfromcookie = langs.find((x) => x.id == parseInt(cc))
}
defLang.value = items.find((x) => x.is_default == true)
currentLang.value = idfromcookie ?? defLang.value
} catch (error) {
console.error('Failed to fetch languages:', error)
}
}
// Initialize country/currency from API
export async function initCountryCurrency() {
try {
const { items } = await useFetchJson<Country[]>('/api/v1/restricted/langs-and-countries/get-countries')
countries.push(...items)
let idfromcookie = null
const cc = cookie.getCookie('country_id')
if (cc) {
idfromcookie = langs.find((x) => x.id == parseInt(cc))
}
defCountry.value = items.find((x) => x.id === defLang.value?.id)
currentCountry.value = idfromcookie ?? defCountry.value
console.log(defCountry.value);
console.log(currentCountry.value);
} catch (error) {
console.error('Failed to fetch languages:', error)
}
}
export async function switchLocalization() {
try {
await useFetchJson('/api/v1/public/auth/update-choice', {
method: 'POST'
})
} catch (error) {
console.log(error)
}
}

View File

@@ -1,144 +0,0 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export interface AddressFormData {
street: string
zipCode: string
city: string
country: string
}
export interface Address {
id: number
street: string
zipCode: string
city: string
country: string
}
export const useAddressStore = defineStore('address', () => {
const addresses = ref<Address[]>([])
const loading = ref(false)
const error = ref<string | null>(null)
const currentPage = ref(1)
const pageSize = 20
const searchQuery = ref('')
function initMockData() {
addresses.value = [
{ id: 1, street: 'Main Street 123', zipCode: '10-001', city: 'New York', country: 'United States' },
{ id: 2, street: 'Oak Avenue 123', zipCode: '90-001', city: 'Los Angeles', country: 'United States' },
{ id: 3, street: 'Pine Road 123', zipCode: '60-601', city: 'Chicago', country: 'United States' }
]
}
const filteredAddresses = computed(() => {
if (!searchQuery.value) return addresses.value
const query = searchQuery.value.toLowerCase()
return addresses.value.filter(addr =>
addr.street.toLowerCase().includes(query) ||
addr.city.toLowerCase().includes(query) ||
addr.country.toLowerCase().includes(query) ||
addr.zipCode.toLowerCase().includes(query)
)
})
const totalItems = computed(() => filteredAddresses.value.length)
const totalPages = computed(() => Math.ceil(totalItems.value / pageSize))
const paginatedAddresses = computed(() => {
const start = (currentPage.value - 1) * pageSize
return filteredAddresses.value.slice(start, start + pageSize)
})
function getAddressById(id: number) {
return addresses.value.find(addr => addr.id === id)
}
function normalize(data: AddressFormData): AddressFormData {
return {
street: data.street.trim(),
zipCode: data.zipCode.trim(),
city: data.city.trim(),
country: data.country.trim()
}
}
function generateId(): number {
return Math.max(0, ...addresses.value.map(a => a.id)) + 1
}
function addAddress(formData: AddressFormData): Address {
const newAddress: Address = {
id: generateId(),
...normalize(formData)
}
addresses.value.unshift(newAddress)
resetPagination()
return newAddress
}
function updateAddress(id: number, formData: AddressFormData): boolean {
const index = addresses.value.findIndex(a => a.id === id)
if (index === -1) return false
const existing = addresses.value[index]
if (!existing) return false
addresses.value[index] = {
id: existing.id,
...normalize(formData)
}
return true
}
function deleteAddress(id: number): boolean {
const index = addresses.value.findIndex(a => a.id === id)
if (index === -1) return false
addresses.value.splice(index, 1)
resetPagination()
return true
}
function setPage(page: number) {
currentPage.value = page
}
function setSearchQuery(query: string) {
searchQuery.value = query
currentPage.value = 1
}
function resetPagination() {
currentPage.value = 1
}
initMockData()
return {
addresses,
loading,
error,
currentPage,
pageSize,
totalItems,
totalPages,
searchQuery,
filteredAddresses,
paginatedAddresses,
getAddressById,
addAddress,
updateAddress,
deleteAddress,
setPage,
setSearchQuery,
resetPagination
}
})

View File

@@ -1,6 +1,5 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { Address } from './address'
export interface CustomerData {
companyName: string

View File

@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
import { ref } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
import type { ProductDescription } from '@/types/product'
import { useSettingsStore } from './settings'
export interface Product {
id: number
@@ -23,21 +24,21 @@ export interface ProductResponse {
}
export const useProductStore = defineStore('product', () => {
const productDescription = ref()
const currentProduct = ref<Product | null>(null)
const loading = ref(false)
const error = ref<string | null>(null)
const productDescription = ref()
const copyProductDescription = ref()
async function getProductDescription(langId = 1, productID: number) {
async function getProductDescription(langId: number | null, productID: number) {
loading.value = true
error.value = null
try {
const response = await useFetchJson<ProductDescription>(
`/api/v1/restricted/product-translation/get-product-description?productID=${productID}&productLangID=${langId}`
`/api/v1/restricted/product-translation/get-product-description?productID=${productID}&productLangID=${langId ? langId : settingStore.shopDefaultLanguage}`
)
productDescription.value = response.items
productDescription.value = structuredClone(response.items)
copyProductDescription.value = structuredClone(response.items)
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Failed to load product description'
} finally {
@@ -45,35 +46,13 @@ export const useProductStore = defineStore('product', () => {
}
}
async function saveProductDescription(productID?: number) {
const id = productID || 1
try {
const data = await useFetchJson(
`/api/v1/restricted/product-description/save-product-description?productID=${id}&productShopID=1&productLangID=1`,
{
method: 'POST',
body: JSON.stringify(
{
description: productDescription.value.description,
description_short: productDescription.value.description_short,
meta_description: productDescription.value.meta_description,
available_now: productDescription.value.available_now,
usage: productDescription.value.usage
})
}
)
return data
} catch (e) {
console.error(e)
}
}
async function translateProductDescription(productID: number, fromLangId: number, toLangId: number) {
const settingStore = useSettingsStore()
async function translateProductDescription(productID: number, toLangId: number, model: string = 'Google') {
loading.value = true
error.value = null
try {
const response = await useFetchJson<ProductDescription>(`/api/v1/restricted/product-description/translate-product-description?productID=${productID}&productShopID=1&productFromLangID=${fromLangId}&productToLangID=${toLangId}&model=OpenAI`)
const response = await useFetchJson<ProductDescription>(`/api/v1/restricted/product-translation/translate-product-description?productID=${productID}&productFromLangID=${settingStore.shopDefaultLanguage}&productToLangID=${toLangId}&model=${model}`)
productDescription.value = response.items
return response.items
} catch (e: any) {
@@ -84,18 +63,46 @@ export const useProductStore = defineStore('product', () => {
}
}
function clearCurrentProduct() {
currentProduct.value = null
async function saveProductDescription(productID?: number, langId?: number | null) {
const id = productID || 1
const lang = langId || 1
try {
const data = await useFetchJson(
`/api/v1/restricted/product-translation/save-product-description?productID=${id}&productLangID=${lang}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: productDescription.value?.name || '',
description: productDescription.value?.description || '',
description_short: productDescription.value?.description_short || '',
meta_title: productDescription.value?.meta_title || '',
meta_description: productDescription.value?.meta_description || '',
available_now: productDescription.value?.available_now || '',
available_later: productDescription.value?.available_later || '',
usage: productDescription.value?.usage || '',
})
}
)
await getProductDescription(langId, productID)
return data
} catch (e) {
console.error(e)
}
}
return {
productDescription,
currentProduct,
loading,
error,
getProductDescription,
clearCurrentProduct,
saveProductDescription,
copyProductDescription,
translateProductDescription,
getProductDescription,
saveProductDescription
}
})

View File

@@ -0,0 +1,21 @@
import { useFetchJson } from '@/composable/useFetchJson'
import type { Resp } from '@/types'
import type { Settings } from '@/types/settings'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
export const useSettingsStore = defineStore('settings', () => {
const settings = ref<Settings | null>(null)
const loaded = ref(false)
const shopDefaultLanguage = computed(() => settings.value?.app?.shop_default_language ?? 1)
async function getSettings(): Promise<Settings | null> {
if (loaded.value && settings.value) return settings.value
const resp = await useFetchJson<Settings>('/api/v1/settings')
settings.value = resp.items
loaded.value = true
return resp.items
}
return { settings, loaded, shopDefaultLanguage, getSettings }
})

View File

@@ -0,0 +1,231 @@
import { useFetchJson } from '@/composable/useFetchJson'
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { AddressTemplate } from './cart'
export interface AddressFormData {
street: string
zipCode: string
city: string
country: string
}
export interface Address {
id: number
street: string
zipCode: string
city: string
country: string
}
export const useAddressStore = defineStore('address', () => {
const loading = ref(false)
const error = ref<string | null>(null)
const currentPage = ref(1)
const pageSize = 20
const searchQuery = ref('')
function initMockData() {
addresses.value = [
{ id: 1, street: 'Main Street 123', zipCode: '10-001', city: 'New York', country: 'United States' },
{ id: 2, street: 'Oak Avenue 123', zipCode: '90-001', city: 'Los Angeles', country: 'United States' },
{ id: 3, street: 'Pine Road 123', zipCode: '60-601', city: 'Chicago', country: 'United States' }
]
}
const filteredAddresses = computed(() => {
if (!searchQuery.value) return addresses.value
const query = searchQuery.value.toLowerCase()
return addresses.value.filter(addr =>
addr.street.toLowerCase().includes(query) ||
addr.city.toLowerCase().includes(query) ||
addr.country.toLowerCase().includes(query) ||
addr.zipCode.toLowerCase().includes(query)
)
})
const totalItems = computed(() => filteredAddresses.value.length)
const totalPages = computed(() => Math.ceil(totalItems.value / pageSize))
function getAddressById(id: number) {
return addresses.value.find(addr => addr.id === id)
}
function normalize(data: AddressFormData): AddressFormData {
return {
street: data.street.trim(),
zipCode: data.zipCode.trim(),
city: data.city.trim(),
country: data.country.trim()
}
}
function generateId(): number {
return Math.max(0, ...addresses.value.map(a => a.id)) + 1
}
function setPage(page: number) {
currentPage.value = page
}
function setSearchQuery(query: string) {
searchQuery.value = query
currentPage.value = 1
}
function resetPagination() {
currentPage.value = 1
}
initMockData()
const addresses = ref<Address[]>([])
const addressLoading = ref(false)
const addressError = ref<string | null>(null)
const addressSearchQuery = ref('')
const addressCurrentPage = ref(1)
const addressPageSize = 20
const addressTotalCount = ref(0)
function transformAddressResponse(address: any): Address {
const info = address.address_info || address.addressInfo || {}
return {
id: address.id ?? 0,
country_id: address.country_id ?? address.countryId ?? 1,
customer_id: address.customer_id ?? address.customerId ?? 0,
address_info: info as Record<string, string>
}
}
async function fetchAddresses() {
addressLoading.value = true
addressError.value = null
try {
const queryParam = addressSearchQuery.value ? `&query=${encodeURIComponent(addressSearchQuery.value)}` : ''
const response = await useFetchJson<Address[]>(`/api/v1/restricted/addresses/retrieve-addresses?page=${addressCurrentPage.value}&elems=${addressPageSize}${queryParam}`)
addresses.value = response.items || []
addressTotalCount.value = response.count ?? addresses.value.length
} catch (error: unknown) {
addressError.value = error instanceof Error ? error.message : 'Failed to load addresses'
} finally {
addressLoading.value = false
}
}
async function addAddress(countryId: number, formData: AddressTemplate): Promise<Address | null> {
addressLoading.value = true
addressError.value = null
try {
const response = await useFetchJson<any>(`/api/v1/restricted/addresses/add-new-address?country_id=${countryId}`, {
method: 'POST',
body: JSON.stringify(formData)
})
await fetchAddresses()
return transformAddressResponse(response.items ?? response)
} catch (error: unknown) {
addressError.value = error instanceof Error ? error.message : 'Failed to create address'
return null
} finally {
addressLoading.value = false
}
}
async function getAddressTemplate(countryId: number): Promise<AddressTemplate> {
const response = await useFetchJson<any>(`/api/v1/restricted/addresses/get-template?country_id=${countryId}`)
return response.items ?? {}
}
async function updateAddress(id: number, countryId: number, formData: AddressTemplate): Promise<boolean> {
addressLoading.value = true
addressError.value = null
try {
await useFetchJson<any>(`/api/v1/restricted/addresses/modify-address?country_id=${countryId}&address_id=${id}`, {
method: 'POST',
body: JSON.stringify(formData)
})
await fetchAddresses()
return true
} catch (error: unknown) {
addressError.value = error instanceof Error ? error.message : 'Failed to update address'
return false
} finally {
addressLoading.value = false
}
}
async function deleteAddress(id: number): Promise<boolean> {
addressLoading.value = true
addressError.value = null
try {
await useFetchJson<any>(`/api/v1/restricted/addresses/delete-address?address_id=${id}`, {
method: 'DELETE'
})
await fetchAddresses()
return true
} catch (error: unknown) {
addressError.value = error instanceof Error ? error.message : 'Failed to delete address'
return false
} finally {
addressLoading.value = false
}
}
const totalAddressItems = computed(() => addressTotalCount.value || addresses.value.length)
const totalAddressPages = computed(() => Math.ceil(totalAddressItems.value / addressPageSize))
const paginatedAddresses = computed(() => addresses.value)
function setAddressPage(page: number) {
addressCurrentPage.value = page
return fetchAddresses()
}
function setAddressSearchQuery(query: string) {
addressSearchQuery.value = query
addressCurrentPage.value = 1
return fetchAddresses()
}
return {
addresses,
loading,
error,
currentPage,
pageSize,
totalItems,
totalPages,
searchQuery,
filteredAddresses,
paginatedAddresses,
getAddressById,
addAddress,
updateAddress,
deleteAddress,
setPage,
setSearchQuery,
resetPagination,
addressLoading,
addressError,
addressSearchQuery,
addressCurrentPage,
addressPageSize,
totalAddressItems,
totalAddressPages,
fetchAddresses,
setAddressPage,
setAddressSearchQuery,
getAddressTemplate
}
})

View File

@@ -1,6 +1,7 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
import { useUserStore } from '../user'
export interface User {
id: string
@@ -41,6 +42,8 @@ export const useAuthStore = defineStore('auth', () => {
_isAuthenticated.value = readIsAuthenticatedCookie()
}
// const auth = useAuthStore()
// const userStore = useUserStore()
async function login(email: string, password: string) {
loading.value = true
error.value = null
@@ -60,6 +63,7 @@ export const useAuthStore = defineStore('auth', () => {
user.value = response.user
_syncAuthState()
// await userStore.getUser()
return true
} catch (e: any) {
@@ -99,7 +103,7 @@ export const useAuthStore = defineStore('auth', () => {
error.value = null
try {
const body: any = { first_name, last_name, email, password, confirm_password, lang: lang || 'en' }
// Add company information if provided
if (company_name) body.company_name = company_name
if (company_email) body.company_email = company_email

View File

@@ -1,5 +1,6 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useFetchJson } from '@/composable/useFetchJson'
export interface CartItem {
id: number
@@ -18,6 +19,15 @@ export interface DeliveryMethod {
description: string
}
export interface Address {
id: number
country_id: number
customer_id: number
address_info: Record<string, string>
}
export type AddressTemplate = Record<string, string>
export const useCartStore = defineStore('cart', () => {
const items = ref<CartItem[]>([])
const selectedAddressId = ref<number | null>(null)

View File

@@ -0,0 +1,86 @@
import { useFetchJson } from '@/composable/useFetchJson'
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { useRoute } from 'vue-router'
export interface Product {
id: number
image: string
name: string
productDetails?: string
product_id: number
is_favorite?: boolean
}
export interface ProductResponse {
items: Product[]
items_count: number
}
export interface ApiResponse {
message: string
items: Product[]
count: number
}
export const useCustomerProductStore = defineStore('customer-product', () => {
const loading = ref(true)
const error = ref<string | null>(null)
const route = useRoute()
const productsList = ref<Product[]>([])
const total = ref(0)
const perPage = ref(15)
async function fetchProductList() {
loading.value = true
error.value = null
const params = new URLSearchParams()
Object.entries(route.query).forEach(([key, value]) => {
if (value) params.append(key, String(value))
})
const url = `/api/v1/restricted/product/list?${params}`
try {
const response = await useFetchJson<ApiResponse>(url)
productsList.value = response.items || []
total.value = response.count || 0
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Failed to load products'
} finally {
loading.value = false
}
}
async function toggleFavorite(product: Product) {
const productId = product.product_id
const isFavorite = product.is_favorite
const url = `/api/v1/restricted/product/favorite/${productId}`
try {
if (!isFavorite) {
await useFetchJson(url, { method: 'POST' })
} else {
await useFetchJson(url, { method: 'DELETE' })
}
product.is_favorite = !isFavorite
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Failed to update favorite'
}
}
return {
fetchProductList,
toggleFavorite,
productsList,
total,
loading,
error,
perPage
}
})

View File

@@ -1,14 +0,0 @@
import { useFetchJson } from '@/composable/useFetchJson'
import type { Resp } from '@/types'
import type { Settings } from '@/types/settings'
import { defineStore } from 'pinia'
export const useSettingsStore = defineStore('settings', () => {
async function getSettings() {
const { items } = await useFetchJson<Resp<Settings>>('/api/v1/settings',)
console.log(items);
}
getSettings()
return {}
})

32
bo/src/stores/user.ts Normal file
View File

@@ -0,0 +1,32 @@
import type { User } from '@/types/user'
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { useFetchJson } from '@/composable/useFetchJson'
export const useUserStore = defineStore('user', () => {
const error = ref<string | null>(null)
const user = ref<User | null>(null)
async function getUser() {
error.value = null
try {
const data = await useFetchJson<User>(`/api/v1/restricted/customer`)
console.log('getUser API response:', data)
const response: User = (data as any).items ?? data
console.log('User response:', response)
user.value = response
return response
} catch (err: any) {
error.value = err?.message ?? 'Unknown error'
return null
}
}
return {
error,
user,
getUser
}
})

View File

@@ -12,3 +12,20 @@ export interface Language {
active: boolean
flag: string
}
export interface Country {
id: number
name: string
flag: string
currency_id: string
ps_currency: {
id_currency: string
name: string
iso_code: string
numeric_iso_code: string
precision: number
conversion_rate: number
deleted: boolean
active: boolean
}
}

View File

@@ -5,7 +5,10 @@ export interface ProductDescription {
description_short: string
meta_description: string
available_now: string
delivery_in_stock?: string
usage: string
image_link: string
link_rewrite: string
}
export interface Product {

View File

@@ -12,6 +12,7 @@ export interface App {
environment: string
base_url: string
password_regex: string
shop_default_language: number
}
export interface Server {

23
bo/src/types/user.d.ts vendored Normal file
View File

@@ -0,0 +1,23 @@
export interface User {
id: string
email: string
name: string
first_name?: string
last_name?: string
company_name?: string
company_email?: string
company_address?: Address
billing_address?: Address
regon?: string
nip?: string
vat?: string
}
interface Customer {
user_id: number
email: string
first_name: string
last_name: string
}

View File

@@ -1,42 +0,0 @@
<template>
<component :is="Default || 'div'">
<div class="container mt-24">
<div class="row">
<!-- <div class="col-12">
<h2 class="text-2xl">Category ID: {{ $route.params.category_id }}</h2>
<div v-for="(p, i) in products" :key="i">
<p>
<span class="border-b-1 bg-red-100 px-4">{{ p.name }}</span>
<span class="border-b-1 bg-red-100 px-4">{{ p.price }}</span>
</p>
</div>
</div> -->
</div>
</div>
</component>
</template>
<script setup lang="ts">
// import { useRoute } from 'vue-router';
import Default from '@/layouts/default.vue';
import { useCategoryStore } from '@/stores/category';
import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';
// const route = useRoute()
// console.log(route);
const categoryStore = useCategoryStore()
const route = useRoute()
const products = ref([])
watch(() => route.params, async (n) => {
categoryStore.setCategoryID(parseInt(n.category_id as string))
const res = await categoryStore.getCategoryProducts()
// products.value = res
}, { immediate: true })
</script>

View File

@@ -1,9 +1,6 @@
<template>
<component :is="Default || 'div'">
home View
</component>
</template>
home View
</template>
<script setup lang="ts">
import Default from '@/layouts/default.vue';
</script>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, defineAsyncComponent, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useAuthStore } from '@/stores/customer/auth'
import { useValidation } from '@/composable/useValidation'
import type { FormError } from '@nuxt/ui'
import { i18n } from '@/plugins/02_i18n'
@@ -107,7 +107,7 @@ const PrivacyComponent = computed(() =>
<div class="flex items-center justify-between w-full dark:text-white text-black">
<button variant="link" size="sm" @click="goToPasswordRecovery"
class="text-[15px] w-full flex justify-end text-(--accent-blue-light) dark:text-(--accent-blue-dark) cursor-pointer">
class="text-[15px] w-full flex justify-end text-(--text-sky-light) dark:text-(--text-sky-dark) cursor-pointer">
{{ $t('general.forgot_password') }}?
</button>
</div>
@@ -145,18 +145,18 @@ const PrivacyComponent = computed(() =>
<p class="dark:text-white text-black">
{{ $t('general.dont_have_an_account') }}?
<button variant="link" size="sm"
class="text-[15px] text-(--accent-blue-light) dark:text-(--accent-blue-dark) cursor-pointer"
class="text-[15px] text-(--text-sky-light) dark:text-(--text-sky-dark) cursor-pointer"
@click="goToRegister">{{ $t('general.create_account_now') }}</button>
</p>
</div>
<p class="mt-8 text-center text-xs dark:text-white text-black">
{{ $t('general.by_signing_in_you_agree_to_our') }}
<span @click="showTherms = !showTherms"
class="cursor-pointer underline text-(--accent-blue-light) dark:text-(--accent-blue-dark) cursor-pointer">{{
class="cursor-pointer underline text-(--text-sky-light) dark:text-(--text-sky-dark) cursor-pointer">{{
$t('general.terms_of_service') }}</span>
{{ $t('general.and') }}
<span @click="showPrivacy = !showPrivacy"
class="cursor-pointer underline text-(--accent-blue-light) dark:text-(--accent-blue-dark) cursor-pointer">{{
class="cursor-pointer underline text-(--text-sky-light) dark:text-(--text-sky-dark) cursor-pointer">{{
$t('general.privacy_policy') }}</span>
</p>
</div>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useAuthStore } from '@/stores/customer/auth'
import { useValidation } from '@/composable/useValidation'
import type { FormError } from '@nuxt/ui'
import { i18n } from '@/plugins/02_i18n'
@@ -92,13 +92,13 @@ function validate(): FormError[] {
class="w-full flex items-center gap-2 justify-center text-[15px] dark:text-white text-black cursor-pointer"
@click="goToLogin">
<UIcon name="mingcute:arrow-left-line"
class="text-(--accent-blue-light) dark:text-(--accent-blue-dark) text-[16px]" />
class="text-(--text-sky-light) dark:text-(--text-sky-dark) text-[16px]" />
{{ $t('general.back_to_sign_in') }}
</button>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ $t('general.dont_have_an_account') }}
<button variant="link" size="sm" @click="goToRegister"
class=" text-[15px] text-(--accent-blue-light) dark:text-(--accent-blue-dark) cursor-pointer">{{
class=" text-[15px] text-(--text-sky-light) dark:text-(--text-sky-dark) cursor-pointer">{{
$t('general.create_account_now') }}
</button>
</p>

View File

@@ -83,12 +83,12 @@
<span class="dark:text-white text-black">
{{ $t('general.i_agree_to_the') }}
<span @click="showTherms = !showTherms"
class="cursor-pointer underline text-(--accent-blue-light) dark:text-(--accent-blue-dark)">{{
class="cursor-pointer underline text-(--text-sky-light) dark:text-(--text-sky-dark)">{{
$t('general.terms_of_service')
}}</span>
{{ $t('general.and') }}
<span @click="showPrivacy = !showPrivacy"
class="cursor-pointer underline text-(--accent-blue-light) dark:text-(--accent-blue-dark)">{{
class="cursor-pointer underline text-(--text-sky-light) dark:text-(--text-sky-dark)">{{
$t('general.privacy_policy')
}}</span>
</span>
@@ -117,7 +117,7 @@
<script setup lang="ts">
import { ref, computed, defineAsyncComponent } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useAuthStore } from '@/stores/customer/auth'
import { useValidation } from '@/composable/useValidation'
import type { FormError } from '@nuxt/ui'
import { useI18n } from 'vue-i18n'

View File

@@ -11,11 +11,10 @@ import {
LinearScale,
} from 'chart.js'
import { getYears, getQuarters, getIssues, type QuarterData, type IssueTimeSummary } from '@/composable/useRepoApi'
import { useAuthStore } from '@/stores/auth'
import { useAuthStore } from '@/stores/customer/auth'
import { i18n } from '@/plugins/02_i18n'
import type { TableColumn } from '@nuxt/ui'
import { useI18n } from 'vue-i18n'
import Default from '@/layouts/default.vue'
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
@@ -182,8 +181,7 @@ const columns = computed<TableColumn<IssueTimeSummary>[]>(() => [
</script>
<template>
<component :is="Default || 'div'">
<div class="container mx-auto">
<div class="">
<div class="p-6 bg-(--main-light) dark:bg-(--black) font-sans">
<h1 class="text-2xl font-bold mb-6 text-black dark:text-white">{{ $t('repo_chart.repository_work_chart') }}
</h1>
@@ -256,5 +254,4 @@ const columns = computed<TableColumn<IssueTimeSummary>[]>(() => [
</div>
</div>
</div>
</component>
</template>
</template>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useAuthStore } from '@/stores/customer/auth'
import { useValidation } from '@/composable/useValidation'
import type { FormError } from '@nuxt/ui'
import { i18n } from '@/plugins/02_i18n'
@@ -120,7 +120,7 @@ function validate(): FormError[] {
<div class="text-center border-t dark:border-(--border-dark) border-(--border-light) pt-4">
<button color="neutral" variant="ghost" @click="goToLogin"
class="text-[15px] flex items-center gap-2 text-(--accent-blue-light) dark:text-(--accent-blue-dark) cursor-pointer">
class="text-[15px] flex items-center gap-2 text-(--text-sky-light) dark:text-(--text-sky-dark) cursor-pointer">
<UIcon name="mingcute:arrow-left-line" />
{{ $t('general.back_to_sign_in') }}
</button>

View File

@@ -0,0 +1,11 @@
<template>
<Default>
<div class="h-full">
<StorageFileBrowser initial-path="dest/src" />
</div>
</Default>
</template>
<script setup lang="ts">
import StorageFileBrowser from '@/components/customer/StorageFileBrowser.vue'
</script>

View File

@@ -135,7 +135,7 @@ function goToLogin() {
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ $t('verify_email.already_registered') }}
<button variant="link" size="sm" @click="goToLogin"
class="cursor-pointer text-(--accent-blue-light) dark:text-(--accent-blue-dark)"> {{
class="cursor-pointer text-(--text-sky-light) dark:text-(--text-sky-dark)"> {{
$t('general.sign_in')
}}
</button>

View File

@@ -0,0 +1,15 @@
info:
name: Routes
type: http
seq: 1
http:
method: GET
url: ""
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5

View File

@@ -0,0 +1,7 @@
info:
name: routes
type: folder
seq: 10
request:
auth: inherit

View File

@@ -5,7 +5,7 @@ info:
http:
method: GET
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&amount=1
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&amount=1&set_amount=false
params:
- name: cart_id
value: "1"
@@ -16,6 +16,9 @@ http:
- name: amount
value: "1"
type: query
- name: set_amount
value: "false"
type: query
auth: inherit
settings:

View File

@@ -5,7 +5,7 @@ info:
http:
method: GET
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&product_attribute_id=1115&amount=1
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&product_attribute_id=1115&amount=1&set_amount=true
params:
- name: cart_id
value: "1"
@@ -19,6 +19,9 @@ http:
- name: amount
value: "1"
type: query
- name: set_amount
value: "true"
type: query
auth: inherit
settings:

View File

@@ -0,0 +1 @@
name: dev

704
bun.lock
View File

@@ -1,719 +1,15 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"dependencies": {
"@nuxt/ui": "^4.5.1",
"chart.js": "^4.5.1",
"dompurify": "^3.3.3",
"vue-chartjs": "^5.3.3",
},
},
},
"packages": {
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
"@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
"@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
"@capsizecss/unpack": ["@capsizecss/unpack@4.0.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
"@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="],
"@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="],
"@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="],
"@floating-ui/vue": ["@floating-ui/vue@1.1.11", "", { "dependencies": { "@floating-ui/dom": "^1.7.6", "@floating-ui/utils": "^0.2.11", "vue-demi": ">=0.13.0" } }, "sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw=="],
"@iconify/collections": ["@iconify/collections@1.0.656", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-X17vsrStihw4gEdgT2+46E+ioM506JJh/Jp/reJGZ2URcWhhS4aMnsi9onoGTQ8ppydZ0GJrPuvOyhySiteKsA=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
"@iconify/utils": ["@iconify/utils@3.1.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.0" } }, "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw=="],
"@iconify/vue": ["@iconify/vue@5.0.0", "", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "vue": ">=3" } }, "sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg=="],
"@internationalized/date": ["@internationalized/date@3.11.0", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q=="],
"@internationalized/number": ["@internationalized/number@3.6.5", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="],
"@nuxt/devtools-kit": ["@nuxt/devtools-kit@3.2.2", "", { "dependencies": { "@nuxt/kit": "^4.3.1", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-07E1phqoVPNlexlkrYuOMPhTzLIRjcl9iEqyc/vZLH2zWeH/T1X3v+RLTVW5Oio40f/XBp9yQuyihmX34ddjgQ=="],
"@nuxt/fonts": ["@nuxt/fonts@0.14.0", "", { "dependencies": { "@nuxt/devtools-kit": "^3.2.1", "@nuxt/kit": "^4.2.2", "consola": "^3.4.2", "defu": "^6.1.4", "fontless": "^0.2.1", "h3": "^1.15.5", "magic-regexp": "^0.10.0", "ofetch": "^1.5.1", "pathe": "^2.0.3", "sirv": "^3.0.2", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unifont": "^0.7.4", "unplugin": "^3.0.0", "unstorage": "^1.17.4" } }, "sha512-4uXQl9fa5F4ibdgU8zomoOcyMdnwgdem+Pi8JEqeDYI5yPR32Kam6HnuRr47dTb97CstaepAvXPWQUUHMtjsFQ=="],
"@nuxt/icon": ["@nuxt/icon@2.2.1", "", { "dependencies": { "@iconify/collections": "^1.0.641", "@iconify/types": "^2.0.0", "@iconify/utils": "^3.1.0", "@iconify/vue": "^5.0.0", "@nuxt/devtools-kit": "^3.1.1", "@nuxt/kit": "^4.2.2", "consola": "^3.4.2", "local-pkg": "^1.1.2", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinyglobby": "^0.2.15" } }, "sha512-GI840yYGuvHI0BGDQ63d6rAxGzG96jQcWrnaWIQKlyQo/7sx9PjXkSHckXUXyX1MCr9zY6U25Td6OatfY6Hklw=="],
"@nuxt/kit": ["@nuxt/kit@4.3.1", "", { "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.8", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^3.0.0", "scule": "^1.3.0", "semver": "^7.7.4", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unctx": "^2.5.0", "untyped": "^2.0.0" } }, "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA=="],
"@nuxt/schema": ["@nuxt/schema@4.3.1", "", { "dependencies": { "@vue/shared": "^3.5.27", "defu": "^6.1.4", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "std-env": "^3.10.0" } }, "sha512-S+wHJdYDuyk9I43Ej27y5BeWMZgi7R/UVql3b3qtT35d0fbpXW7fUenzhLRCCDC6O10sjguc6fcMcR9sMKvV8g=="],
"@nuxt/ui": ["@nuxt/ui@4.5.1", "", { "dependencies": { "@floating-ui/dom": "^1.7.5", "@iconify/vue": "^5.0.0", "@internationalized/date": "^3.11.0", "@internationalized/number": "^3.6.5", "@nuxt/fonts": "^0.14.0", "@nuxt/icon": "^2.2.1", "@nuxt/kit": "^4.3.1", "@nuxt/schema": "^4.3.1", "@nuxtjs/color-mode": "^3.5.2", "@standard-schema/spec": "^1.1.0", "@tailwindcss/postcss": "^4.2.1", "@tailwindcss/vite": "^4.2.1", "@tanstack/vue-table": "^8.21.3", "@tanstack/vue-virtual": "^3.13.19", "@tiptap/core": "^3.20.0", "@tiptap/extension-bubble-menu": "^3.20.0", "@tiptap/extension-code": "^3.20.0", "@tiptap/extension-collaboration": "^3.20.0", "@tiptap/extension-drag-handle": "^3.20.0", "@tiptap/extension-drag-handle-vue-3": "^3.20.0", "@tiptap/extension-floating-menu": "^3.20.0", "@tiptap/extension-horizontal-rule": "^3.20.0", "@tiptap/extension-image": "^3.20.0", "@tiptap/extension-mention": "^3.20.0", "@tiptap/extension-node-range": "^3.20.0", "@tiptap/extension-placeholder": "^3.20.0", "@tiptap/markdown": "^3.20.0", "@tiptap/pm": "^3.20.0", "@tiptap/starter-kit": "^3.20.0", "@tiptap/suggestion": "^3.20.0", "@tiptap/vue-3": "^3.20.0", "@unhead/vue": "^2.1.10", "@vueuse/core": "^14.2.1", "@vueuse/integrations": "^14.2.1", "@vueuse/shared": "^14.2.1", "colortranslator": "^5.0.0", "consola": "^3.4.2", "defu": "^6.1.4", "embla-carousel-auto-height": "^8.6.0", "embla-carousel-auto-scroll": "^8.6.0", "embla-carousel-autoplay": "^8.6.0", "embla-carousel-class-names": "^8.6.0", "embla-carousel-fade": "^8.6.0", "embla-carousel-vue": "^8.6.0", "embla-carousel-wheel-gestures": "^8.1.0", "fuse.js": "^7.1.0", "hookable": "^5.5.3", "knitwork": "^1.3.0", "magic-string": "^0.30.21", "mlly": "^1.8.0", "motion-v": "^1.10.3", "ohash": "^2.0.11", "pathe": "^2.0.3", "reka-ui": "2.8.2", "scule": "^1.3.0", "tailwind-merge": "^3.5.0", "tailwind-variants": "^3.2.2", "tailwindcss": "^4.2.1", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unplugin": "^3.0.0", "unplugin-auto-import": "^21.0.0", "unplugin-vue-components": "^31.0.0", "vaul-vue": "0.4.1", "vue-component-type-helpers": "^3.2.5" }, "peerDependencies": { "@inertiajs/vue3": "^2.0.7", "@nuxt/content": "^3.0.0", "joi": "^18.0.0", "superstruct": "^2.0.0", "tailwindcss": "^4.0.0", "typescript": "^5.9.3", "valibot": "^1.0.0", "vue-router": "^4.5.0", "yup": "^1.7.0", "zod": "^3.24.0 || ^4.0.0" }, "optionalPeers": ["@inertiajs/vue3", "@nuxt/content", "joi", "superstruct", "valibot", "vue-router", "yup", "zod"], "bin": { "nuxt-ui": "cli/index.mjs" } }, "sha512-5hWgreVPX6EsNCZNoOd2o7m9fTA3fwUMDw+zeYTSAjhSKtAuvkZrBtmez4MUeTv+LO1gknesgvErdIvlUnElTg=="],
"@nuxtjs/color-mode": ["@nuxtjs/color-mode@3.5.2", "", { "dependencies": { "@nuxt/kit": "^3.13.2", "pathe": "^1.1.2", "pkg-types": "^1.2.1", "semver": "^7.6.3" } }, "sha512-cC6RfgZh3guHBMLLjrBB2Uti5eUoGM9KyauOaYS9ETmxNWBMTvpgjvSiSJp1OFljIXPIqVTJ3xtJpSNZiO3ZaA=="],
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
"@remirror/core-constants": ["@remirror/core-constants@3.0.0", "", {}, "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg=="],
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@swc/helpers": ["@swc/helpers@0.5.19", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA=="],
"@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.1", "", { "cpu": "none" }, "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ=="],
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.1", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "postcss": "^8.5.6", "tailwindcss": "4.2.1" } }, "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw=="],
"@tailwindcss/vite": ["@tailwindcss/vite@4.2.1", "", { "dependencies": { "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "tailwindcss": "4.2.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w=="],
"@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="],
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.19", "", {}, "sha512-/BMP7kNhzKOd7wnDeB8NrIRNLwkf5AhCYCvtfZV2GXWbBieFm/el0n6LOAXlTi6ZwHICSNnQcIxRCWHrLzDY+g=="],
"@tanstack/vue-table": ["@tanstack/vue-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "vue": ">=3.2" } }, "sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw=="],
"@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.19", "", { "dependencies": { "@tanstack/virtual-core": "3.13.19" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-07Fp1TYuIziB4zIDA/moeDKHODePy3K1fN4c4VIAGnkxo1+uOvBJP7m54CoxKiQX6Q9a1dZnznrwOg9C86yvvA=="],
"@tiptap/core": ["@tiptap/core@3.20.0", "", { "peerDependencies": { "@tiptap/pm": "^3.20.0" } }, "sha512-aC9aROgia/SpJqhsXFiX9TsligL8d+oeoI8W3u00WI45s0VfsqjgeKQLDLF7Tu7hC+7F02teC84SAHuup003VQ=="],
"@tiptap/extension-blockquote": ["@tiptap/extension-blockquote@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-LQzn6aGtL4WXz2+rYshl/7/VnP2qJTpD7fWL96GXAzhqviPEY1bJES7poqJb3MU/gzl8VJUVzVzU1VoVfUKlbA=="],
"@tiptap/extension-bold": ["@tiptap/extension-bold@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-sQklEWiyf58yDjiHtm5vmkVjfIc/cBuSusmCsQ0q9vGYnEF1iOHKhGpvnCeEXNeqF3fiJQRlquzt/6ymle3Iwg=="],
"@tiptap/extension-bubble-menu": ["@tiptap/extension-bubble-menu@3.20.0", "", { "dependencies": { "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-MDosUfs8Tj+nwg8RC+wTMWGkLJORXmbR6YZgbiX4hrc7G90Gopdd6kj6ht5/T8t7dLLaX7N0+DEHdUEPGED7dw=="],
"@tiptap/extension-bullet-list": ["@tiptap/extension-bullet-list@3.20.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.0" } }, "sha512-OcKMeopBbqWzhSi6o8nNz0aayogg1sfOAhto3NxJu3Ya32dwBFqmHXSYM6uW4jOphNvVPyjiq9aNRh3qTdd1dw=="],
"@tiptap/extension-code": ["@tiptap/extension-code@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-TYDWFeSQ9umiyrqsT6VecbuhL8XIHkUhO+gEk0sVvH67ZLwjFDhAIIgWIr1/dbIGPcvMZM19E7xUUhAdIaXaOQ=="],
"@tiptap/extension-code-block": ["@tiptap/extension-code-block@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-lBbmNek14aCjrHcBcq3PRqWfNLvC6bcRa2Osc6e/LtmXlcpype4f6n+Yx+WZ+f2uUh0UmDRCz7BEyUETEsDmlQ=="],
"@tiptap/extension-collaboration": ["@tiptap/extension-collaboration@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0", "@tiptap/y-tiptap": "^3.0.2", "yjs": "^13" } }, "sha512-JItmI4U0i4kqorO114u24hM9k945IdaQ6Uc2DEtPBFFuS8cepJf2zw+ulAT1kAx6ZRiNvNpT9M7w+J0mWRn+Sg=="],
"@tiptap/extension-document": ["@tiptap/extension-document@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-oJfLIG3vAtZo/wg29WiBcyWt22KUgddpP8wqtCE+kY5Dw8znLR9ehNmVWlSWJA5OJUMO0ntAHx4bBT+I2MBd5w=="],
"@tiptap/extension-drag-handle": ["@tiptap/extension-drag-handle@3.20.0", "", { "dependencies": { "@floating-ui/dom": "^1.6.13" }, "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/extension-collaboration": "^3.20.0", "@tiptap/extension-node-range": "^3.20.0", "@tiptap/pm": "^3.20.0", "@tiptap/y-tiptap": "^3.0.2" } }, "sha512-CzLRyxZe5QddQey0RUWJUvICyhuRnU/jvzMIYlFvMxM7W97sZ2ggk0cRThlRt2pRUoSr8mmmUnobiorpISmksA=="],
"@tiptap/extension-drag-handle-vue-3": ["@tiptap/extension-drag-handle-vue-3@3.20.0", "", { "peerDependencies": { "@tiptap/extension-drag-handle": "^3.20.0", "@tiptap/pm": "^3.20.0", "@tiptap/vue-3": "^3.20.0", "vue": "^3.0.0" } }, "sha512-Jx6LHYRI5uRaJVNQGkQsTFQkAM84rYQh3Q+WBePhGF4yPBUJQFn7Nv+5fQhKKV3A5PVQ6kTAjvW6SSUcD6ON8A=="],
"@tiptap/extension-dropcursor": ["@tiptap/extension-dropcursor@3.20.0", "", { "peerDependencies": { "@tiptap/extensions": "^3.20.0" } }, "sha512-d+cxplRlktVgZPwatnc34IArlppM0IFKS1J5wLk+ba1jidizsbMVh45tP/BTK2flhyfRqcNoB5R0TArhUpbkNQ=="],
"@tiptap/extension-floating-menu": ["@tiptap/extension-floating-menu@3.20.0", "", { "peerDependencies": { "@floating-ui/dom": "^1.0.0", "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-rYs4Bv5pVjqZ/2vvR6oe7ammZapkAwN51As/WDbemvYDjfOGRqK58qGauUjYZiDzPOEIzI2mxGwsZ4eJhPW4Ig=="],
"@tiptap/extension-gapcursor": ["@tiptap/extension-gapcursor@3.20.0", "", { "peerDependencies": { "@tiptap/extensions": "^3.20.0" } }, "sha512-P/LasfvG9/qFq43ZAlNbAnPnXC+/RJf49buTrhtFvI9Zg0+Lbpjx1oh6oMHB19T88Y28KtrckfFZ8aTSUWDq6w=="],
"@tiptap/extension-hard-break": ["@tiptap/extension-hard-break@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-rqvhMOw4f+XQmEthncbvDjgLH6fz8L9splnKZC7OeS0eX8b0qd7+xI1u5kyxF3KA2Z0BnigES++jjWuecqV6mA=="],
"@tiptap/extension-heading": ["@tiptap/extension-heading@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-JgJhurnCe3eN6a0lEsNQM/46R1bcwzwWWZEFDSb1P9dR8+t1/5v7cMZWsSInpD7R4/74iJn0+M5hcXLwCmBmYA=="],
"@tiptap/extension-horizontal-rule": ["@tiptap/extension-horizontal-rule@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-6uvcutFMv+9wPZgptDkbRDjAm3YVxlibmkhWD5GuaWwS9L/yUtobpI3GycujRSUZ8D3q6Q9J7LqpmQtQRTalWA=="],
"@tiptap/extension-image": ["@tiptap/extension-image@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-0t7HYncV0kYEQS79NFczxdlZoZ8zu8X4VavDqt+mbSAUKRq3gCvgtZ5Zyd778sNmtmbz3arxkEYMIVou2swD0g=="],
"@tiptap/extension-italic": ["@tiptap/extension-italic@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-/DhnKQF8yN8RxtuL8abZ28wd5281EaGoE2Oha35zXSOF1vNYnbyt8Ymkv/7u1BcWEWTvRPgaju0YCGXisPRLYw=="],
"@tiptap/extension-link": ["@tiptap/extension-link@3.20.0", "", { "dependencies": { "linkifyjs": "^4.3.2" }, "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-qI/5A+R0ZWBxo/8HxSn1uOyr7odr3xHBZ/gzOR1GUJaZqjlJxkWFX0RtXMbLKEGEvT25o345cF7b0wFznEh8qA=="],
"@tiptap/extension-list": ["@tiptap/extension-list@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-+V0/gsVWAv+7vcY0MAe6D52LYTIicMSHw00wz3ISZgprSb2yQhJ4+4gurOnUrQ4Du3AnRQvxPROaofwxIQ66WQ=="],
"@tiptap/extension-list-item": ["@tiptap/extension-list-item@3.20.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.0" } }, "sha512-qEtjaaGPuqaFB4VpLrGDoIe9RHnckxPfu6d3rc22ap6TAHCDyRv05CEyJogqccnFceG/v5WN4znUBER8RWnWHA=="],
"@tiptap/extension-list-keymap": ["@tiptap/extension-list-keymap@3.20.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.0" } }, "sha512-Z4GvKy04Ms4cLFN+CY6wXswd36xYsT2p/YL0V89LYFMZTerOeTjFYlndzn6svqL8NV1PRT5Diw4WTTxJSmcJPA=="],
"@tiptap/extension-mention": ["@tiptap/extension-mention@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0", "@tiptap/suggestion": "^3.20.0" } }, "sha512-wUjsq7Za0JJdJzrGNG+g8nrCpek/85GQ0Rm9bka3PynIVRwus+xQqW6IyWVPBdl1BSkrbgMAUqtrfoh1ymznbg=="],
"@tiptap/extension-node-range": ["@tiptap/extension-node-range@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-XeKKTV88VuJ4Mh0Rxvc/PPzG76cb44sE+rB4u0J/ms63R/WFTm6yJQlCgUVGnGeHleSlrWuZY8gGSuoljmQzqg=="],
"@tiptap/extension-ordered-list": ["@tiptap/extension-ordered-list@3.20.0", "", { "peerDependencies": { "@tiptap/extension-list": "^3.20.0" } }, "sha512-jVKnJvrizLk7etwBMfyoj6H2GE4M+PD4k7Bwp6Bh1ohBWtfIA1TlngdS842Mx5i1VB2e3UWIwr8ZH46gl6cwMA=="],
"@tiptap/extension-paragraph": ["@tiptap/extension-paragraph@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-mM99zK4+RnEXIMCv6akfNATAs0Iija6FgyFA9J9NZ6N4o8y9QiNLLa6HjLpAC+W+VoCgQIekyoF/Q9ftxmAYDQ=="],
"@tiptap/extension-placeholder": ["@tiptap/extension-placeholder@3.20.0", "", { "peerDependencies": { "@tiptap/extensions": "^3.20.0" } }, "sha512-ZhYD3L5m16ydSe2z8vqz+RdtAG/iOQaFHHedFct70tKRoLqi2ajF5kgpemu8DwpaRTcyiCN4G99J/+MqehKNjQ=="],
"@tiptap/extension-strike": ["@tiptap/extension-strike@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-0vcTZRRAiDfon3VM1mHBr9EFmTkkUXMhm0Xtdtn0bGe+sIqufyi+hUYTEw93EQOD9XNsPkrud6jzQNYpX2H3AQ=="],
"@tiptap/extension-text": ["@tiptap/extension-text@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-tf8bE8tSaOEWabCzPm71xwiUhyMFKqY9jkP5af3Kr1/F45jzZFIQAYZooHI/+zCHRrgJ99MQHKHe1ZNvODrKHQ=="],
"@tiptap/extension-underline": ["@tiptap/extension-underline@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0" } }, "sha512-LzNXuy2jwR/y+ymoUqC72TiGzbOCjioIjsDu0MNYpHuHqTWPK5aV9Mh0nbZcYFy/7fPlV1q0W139EbJeYBZEAQ=="],
"@tiptap/extensions": ["@tiptap/extensions@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-HIsXX942w3nbxEQBlMAAR/aa6qiMBEP7CsSMxaxmTIVAmW35p6yUASw6GdV1u0o3lCZjXq2OSRMTskzIqi5uLg=="],
"@tiptap/markdown": ["@tiptap/markdown@3.20.0", "", { "dependencies": { "marked": "^17.0.1" }, "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-3vUxs8tsVIf/KWKLWjFsTqrjuaTYJY9rawDL5sio9NwlqFWDuWpHEVJcqbQXJUrgQSh12AZoTKyfgiEqkAGI3Q=="],
"@tiptap/pm": ["@tiptap/pm@3.20.0", "", { "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", "prosemirror-commands": "^1.6.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", "prosemirror-history": "^1.4.1", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", "prosemirror-markdown": "^1.13.1", "prosemirror-menu": "^1.2.4", "prosemirror-model": "^1.24.1", "prosemirror-schema-basic": "^1.2.3", "prosemirror-schema-list": "^1.5.0", "prosemirror-state": "^1.4.3", "prosemirror-tables": "^1.6.4", "prosemirror-trailing-node": "^3.0.0", "prosemirror-transform": "^1.10.2", "prosemirror-view": "^1.38.1" } }, "sha512-jn+2KnQZn+b+VXr8EFOJKsnjVNaA4diAEr6FOazupMt8W8ro1hfpYtZ25JL87Kao/WbMze55sd8M8BDXLUKu1A=="],
"@tiptap/starter-kit": ["@tiptap/starter-kit@3.20.0", "", { "dependencies": { "@tiptap/core": "^3.20.0", "@tiptap/extension-blockquote": "^3.20.0", "@tiptap/extension-bold": "^3.20.0", "@tiptap/extension-bullet-list": "^3.20.0", "@tiptap/extension-code": "^3.20.0", "@tiptap/extension-code-block": "^3.20.0", "@tiptap/extension-document": "^3.20.0", "@tiptap/extension-dropcursor": "^3.20.0", "@tiptap/extension-gapcursor": "^3.20.0", "@tiptap/extension-hard-break": "^3.20.0", "@tiptap/extension-heading": "^3.20.0", "@tiptap/extension-horizontal-rule": "^3.20.0", "@tiptap/extension-italic": "^3.20.0", "@tiptap/extension-link": "^3.20.0", "@tiptap/extension-list": "^3.20.0", "@tiptap/extension-list-item": "^3.20.0", "@tiptap/extension-list-keymap": "^3.20.0", "@tiptap/extension-ordered-list": "^3.20.0", "@tiptap/extension-paragraph": "^3.20.0", "@tiptap/extension-strike": "^3.20.0", "@tiptap/extension-text": "^3.20.0", "@tiptap/extension-underline": "^3.20.0", "@tiptap/extensions": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-W4+1re35pDNY/7rpXVg+OKo/Fa4Gfrn08Bq3E3fzlJw6gjE3tYU8dY9x9vC2rK9pd9NOp7Af11qCFDaWpohXkw=="],
"@tiptap/suggestion": ["@tiptap/suggestion@3.20.0", "", { "peerDependencies": { "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0" } }, "sha512-OA9Fe+1Q/Ex0ivTcpRcVFiLnNsVdIBmiEoctt/gu4H2ayCYmZ906veioXNdc1m/3MtVVUIuEnvwwsrOZXlfDEw=="],
"@tiptap/vue-3": ["@tiptap/vue-3@3.20.0", "", { "optionalDependencies": { "@tiptap/extension-bubble-menu": "^3.20.0", "@tiptap/extension-floating-menu": "^3.20.0" }, "peerDependencies": { "@floating-ui/dom": "^1.0.0", "@tiptap/core": "^3.20.0", "@tiptap/pm": "^3.20.0", "vue": "^3.0.0" } }, "sha512-u8UfDKsbIOF+mVsXwJ946p1jfrLGFUyqp9i/DAeGGg2I85DPOkhZgz67bUPVXkpossoEk+jKCkRN0eBHl9+eZQ=="],
"@tiptap/y-tiptap": ["@tiptap/y-tiptap@3.0.2", "", { "dependencies": { "lib0": "^0.2.100" }, "peerDependencies": { "prosemirror-model": "^1.7.1", "prosemirror-state": "^1.2.3", "prosemirror-view": "^1.9.10", "y-protocols": "^1.0.1", "yjs": "^13.5.38" } }, "sha512-flMn/YW6zTbc6cvDaUPh/NfLRTXDIqgpBUkYzM74KA1snqQwhOMjnRcnpu4hDFrTnPO6QGzr99vRyXEA7M44WA=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="],
"@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="],
"@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="],
"@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
"@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="],
"@unhead/vue": ["@unhead/vue@2.1.10", "", { "dependencies": { "hookable": "^6.0.1", "unhead": "2.1.10" }, "peerDependencies": { "vue": ">=3.5.18" } }, "sha512-VP78Onh2HNezLPfhYjfHqn4dxlcQsE6PJgTTs61NksO/thvilNswtgBq0N0MWCLtn43N5akEPGW2y2zxM3PWgQ=="],
"@vue/compiler-core": ["@vue/compiler-core@3.5.29", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.29", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw=="],
"@vue/compiler-dom": ["@vue/compiler-dom@3.5.29", "", { "dependencies": { "@vue/compiler-core": "3.5.29", "@vue/shared": "3.5.29" } }, "sha512-n0G5o7R3uBVmVxjTIYcz7ovr8sy7QObFG8OQJ3xGCDNhbG60biP/P5KnyY8NLd81OuT1WJflG7N4KWYHaeeaIg=="],
"@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.29", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-core": "3.5.29", "@vue/compiler-dom": "3.5.29", "@vue/compiler-ssr": "3.5.29", "@vue/shared": "3.5.29", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-oJZhN5XJs35Gzr50E82jg2cYdZQ78wEwvRO6Y63TvLVTc+6xICzJHP1UIecdSPPYIbkautNBanDiWYa64QSFIA=="],
"@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.29", "", { "dependencies": { "@vue/compiler-dom": "3.5.29", "@vue/shared": "3.5.29" } }, "sha512-Y/ARJZE6fpjzL5GH/phJmsFwx3g6t2KmHKHx5q+MLl2kencADKIrhH5MLF6HHpRMmlRAYBRSvv347Mepf1zVNw=="],
"@vue/reactivity": ["@vue/reactivity@3.5.29", "", { "dependencies": { "@vue/shared": "3.5.29" } }, "sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA=="],
"@vue/runtime-core": ["@vue/runtime-core@3.5.29", "", { "dependencies": { "@vue/reactivity": "3.5.29", "@vue/shared": "3.5.29" } }, "sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg=="],
"@vue/runtime-dom": ["@vue/runtime-dom@3.5.29", "", { "dependencies": { "@vue/reactivity": "3.5.29", "@vue/runtime-core": "3.5.29", "@vue/shared": "3.5.29", "csstype": "^3.2.3" } }, "sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg=="],
"@vue/server-renderer": ["@vue/server-renderer@3.5.29", "", { "dependencies": { "@vue/compiler-ssr": "3.5.29", "@vue/shared": "3.5.29" }, "peerDependencies": { "vue": "3.5.29" } }, "sha512-G/1k6WK5MusLlbxSE2YTcqAAezS+VuwHhOvLx2KnQU7G2zCH6KIb+5Wyt6UjMq7a3qPzNEjJXs1hvAxDclQH+g=="],
"@vue/shared": ["@vue/shared@3.5.29", "", {}, "sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg=="],
"@vueuse/core": ["@vueuse/core@14.2.1", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.2.1", "@vueuse/shared": "14.2.1" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ=="],
"@vueuse/integrations": ["@vueuse/integrations@14.2.1", "", { "dependencies": { "@vueuse/core": "14.2.1", "@vueuse/shared": "14.2.1" }, "peerDependencies": { "async-validator": "^4", "axios": "^1", "change-case": "^5", "drauu": "^0.4", "focus-trap": "^7 || ^8", "fuse.js": "^7", "idb-keyval": "^6", "jwt-decode": "^4", "nprogress": "^0.2", "qrcode": "^1.5", "sortablejs": "^1", "universal-cookie": "^7 || ^8", "vue": "^3.5.0" }, "optionalPeers": ["async-validator", "axios", "change-case", "drauu", "focus-trap", "idb-keyval", "jwt-decode", "nprogress", "qrcode", "sortablejs", "universal-cookie"] }, "sha512-2LIUpBi/67PoXJGqSDQUF0pgQWpNHh7beiA+KG2AbybcNm+pTGWT6oPGlBgUoDWmYwfeQqM/uzOHqcILpKL7nA=="],
"@vueuse/metadata": ["@vueuse/metadata@14.2.1", "", {}, "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw=="],
"@vueuse/shared": ["@vueuse/shared@14.2.1", "", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw=="],
"acorn": ["acorn@8.16.0", "", { "bin": "bin/acorn" }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
"c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="],
"chart.js": ["chart.js@4.5.1", "", { "dependencies": { "@kurkle/color": "^0.3.0" } }, "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw=="],
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="],
"colortranslator": ["colortranslator@5.0.0", "", {}, "sha512-Z3UPUKasUVDFCDYAjP2fmlVRf1jFHJv1izAmPjiOa0OCIw1W7iC8PZ2GsoDa8uZv+mKyWopxxStT9q05+27h7w=="],
"confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="],
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
"cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="],
"crelt": ["crelt@1.0.6", "", {}, "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="],
"css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
"destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"dompurify": ["dompurify@3.3.3", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA=="],
"dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
"embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="],
"embla-carousel-auto-height": ["embla-carousel-auto-height@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-/HrJQOEM6aol/oF33gd2QlINcXy3e19fJWvHDuHWp2bpyTa+2dm9tVVJak30m2Qy6QyQ6Fc8DkImtv7pxWOJUQ=="],
"embla-carousel-auto-scroll": ["embla-carousel-auto-scroll@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-WT9fWhNXFpbQ6kP+aS07oF5IHYLZ1Dx4DkwgCY8Hv2ZyYd2KMCPfMV1q/cA3wFGuLO7GMgKiySLX90/pQkcOdQ=="],
"embla-carousel-autoplay": ["embla-carousel-autoplay@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-OBu5G3nwaSXkZCo1A6LTaFMZ8EpkYbwIaH+bPqdBnDGQ2fh4+NbzjXjs2SktoPNKCtflfVMc75njaDHOYXcrsA=="],
"embla-carousel-class-names": ["embla-carousel-class-names@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-l1hm1+7GxQ+zwdU2sea/LhD946on7XO2qk3Xq2XWSwBaWfdgchXdK567yzLtYSHn4sWYdiX+x4nnaj+saKnJkw=="],
"embla-carousel-fade": ["embla-carousel-fade@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-qaYsx5mwCz72ZrjlsXgs1nKejSrW+UhkbOMwLgfRT7w2LtdEB03nPRI06GHuHv5ac2USvbEiX2/nAHctcDwvpg=="],
"embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="],
"embla-carousel-vue": ["embla-carousel-vue@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "vue": "^3.2.37" } }, "sha512-v8UO5UsyLocZnu/LbfQA7Dn2QHuZKurJY93VUmZYP//QRWoCWOsionmvLLAlibkET3pGPs7++03VhJKbWD7vhQ=="],
"embla-carousel-wheel-gestures": ["embla-carousel-wheel-gestures@8.1.0", "", { "dependencies": { "wheel-gestures": "^2.2.5" }, "peerDependencies": { "embla-carousel": "^8.0.0 || ~8.0.0-rc03" } }, "sha512-J68jkYrxbWDmXOm2n2YHl+uMEXzkGSKjWmjaEgL9xVvPb3HqVmg6rJSKfI3sqIDVvm7mkeTy87wtG/5263XqHQ=="],
"enhanced-resolve": ["enhanced-resolve@5.20.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"errx": ["errx@0.1.0", "", {}, "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q=="],
"esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": "bin/esbuild" }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
"execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fontaine": ["fontaine@0.8.0", "", { "dependencies": { "@capsizecss/unpack": "^4.0.0", "css-tree": "^3.1.0", "magic-regexp": "^0.10.0", "magic-string": "^0.30.21", "pathe": "^2.0.3", "ufo": "^1.6.1", "unplugin": "^2.3.10" } }, "sha512-eek1GbzOdWIj9FyQH/emqW1aEdfC3lYRCHepzwlFCm5T77fBSRSyNRKE6/antF1/B1M+SfJXVRQTY9GAr7lnDg=="],
"fontkitten": ["fontkitten@1.0.2", "", { "dependencies": { "tiny-inflate": "^1.0.3" } }, "sha512-piJxbLnkD9Xcyi7dWJRnqszEURixe7CrF/efBfbffe2DPyabmuIuqraruY8cXTs19QoM8VJzx47BDRVNXETM7Q=="],
"fontless": ["fontless@0.2.1", "", { "dependencies": { "consola": "^3.4.2", "css-tree": "^3.1.0", "defu": "^6.1.4", "esbuild": "^0.27.0", "fontaine": "0.8.0", "jiti": "^2.6.1", "lightningcss": "^1.30.2", "magic-string": "^0.30.21", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1", "unifont": "^0.7.4", "unstorage": "^1.17.1" }, "peerDependencies": { "vite": "*" } }, "sha512-mUWZ8w91/mw2KEcZ6gHNoNNmsAq9Wiw2IypIux5lM03nhXm+WSloXGUNuRETNTLqZexMgpt7Aj/v63qqrsWraQ=="],
"framer-motion": ["framer-motion@12.34.4", "", { "dependencies": { "motion-dom": "^12.34.3", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-q1PwNhc1XJ3qYG7nc9+pEU5P3tnjB6Eh9vv5gGzy61nedDLB4+xk5peMCWhKM0Zn6sfhgunf/q9n0UgCoyKOBA=="],
"fuse.js": ["fuse.js@7.1.0", "", {}, "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ=="],
"get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
"giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": "dist/cli.mjs" }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"h3": ["h3@1.15.5", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg=="],
"hey-listen": ["hey-listen@1.0.8", "", {}, "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="],
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
"is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"isomorphic.js": ["isomorphic.js@0.2.5", "", {}, "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw=="],
"jiti": ["jiti@2.6.1", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
"klona": ["klona@2.0.6", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="],
"knitwork": ["knitwork@1.3.0", "", {}, "sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw=="],
"lib0": ["lib0@0.2.117", "", { "dependencies": { "isomorphic.js": "^0.2.4" }, "bin": { "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js", "0gentesthtml": "bin/gentesthtml.js", "0serve": "bin/0serve.js" } }, "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw=="],
"lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
"linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="],
"linkifyjs": ["linkifyjs@4.3.2", "", {}, "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA=="],
"local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="],
"lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="],
"magic-regexp": ["magic-regexp@0.10.0", "", { "dependencies": { "estree-walker": "^3.0.3", "magic-string": "^0.30.12", "mlly": "^1.7.2", "regexp-tree": "^0.1.27", "type-level-regexp": "~0.1.17", "ufo": "^1.5.4", "unplugin": "^2.0.0" } }, "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": "bin/markdown-it.mjs" }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="],
"marked": ["marked@17.0.3", "", { "bin": "bin/marked.js" }, "sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A=="],
"mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="],
"mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="],
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
"mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
"mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="],
"motion-dom": ["motion-dom@12.34.3", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ=="],
"motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="],
"motion-v": ["motion-v@1.10.3", "", { "dependencies": { "framer-motion": "^12.25.0", "hey-listen": "^1.0.8", "motion-dom": "^12.23.23" }, "peerDependencies": { "@vueuse/core": ">=10.0.0", "vue": ">=3.0.0" } }, "sha512-9Ewo/wwGv7FO3PqYJpllBF/Efc7tbeM1iinVrM73s0RUQrnXHwMZCaRX98u4lu0PQCrZghPPfCsQ14pWKIEbnQ=="],
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
"node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
"npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
"nypm": ["nypm@0.6.5", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": "dist/cli.mjs" }, "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ=="],
"obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="],
"ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
"onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
"orderedmap": ["orderedmap@2.1.1", "", {}, "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g=="],
"package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
"postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="],
"prosemirror-changeset": ["prosemirror-changeset@2.4.0", "", { "dependencies": { "prosemirror-transform": "^1.0.0" } }, "sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng=="],
"prosemirror-collab": ["prosemirror-collab@1.3.1", "", { "dependencies": { "prosemirror-state": "^1.0.0" } }, "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ=="],
"prosemirror-commands": ["prosemirror-commands@1.7.1", "", { "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.10.2" } }, "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w=="],
"prosemirror-dropcursor": ["prosemirror-dropcursor@1.8.2", "", { "dependencies": { "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0", "prosemirror-view": "^1.1.0" } }, "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw=="],
"prosemirror-gapcursor": ["prosemirror-gapcursor@1.4.0", "", { "dependencies": { "prosemirror-keymap": "^1.0.0", "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", "prosemirror-view": "^1.0.0" } }, "sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ=="],
"prosemirror-history": ["prosemirror-history@1.5.0", "", { "dependencies": { "prosemirror-state": "^1.2.2", "prosemirror-transform": "^1.0.0", "prosemirror-view": "^1.31.0", "rope-sequence": "^1.3.0" } }, "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg=="],
"prosemirror-inputrules": ["prosemirror-inputrules@1.5.1", "", { "dependencies": { "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.0.0" } }, "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw=="],
"prosemirror-keymap": ["prosemirror-keymap@1.2.3", "", { "dependencies": { "prosemirror-state": "^1.0.0", "w3c-keyname": "^2.2.0" } }, "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw=="],
"prosemirror-markdown": ["prosemirror-markdown@1.13.4", "", { "dependencies": { "@types/markdown-it": "^14.0.0", "markdown-it": "^14.0.0", "prosemirror-model": "^1.25.0" } }, "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw=="],
"prosemirror-menu": ["prosemirror-menu@1.3.0", "", { "dependencies": { "crelt": "^1.0.0", "prosemirror-commands": "^1.0.0", "prosemirror-history": "^1.0.0", "prosemirror-state": "^1.0.0" } }, "sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg=="],
"prosemirror-model": ["prosemirror-model@1.25.4", "", { "dependencies": { "orderedmap": "^2.0.0" } }, "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA=="],
"prosemirror-schema-basic": ["prosemirror-schema-basic@1.2.4", "", { "dependencies": { "prosemirror-model": "^1.25.0" } }, "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ=="],
"prosemirror-schema-list": ["prosemirror-schema-list@1.5.1", "", { "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.7.3" } }, "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q=="],
"prosemirror-state": ["prosemirror-state@1.4.4", "", { "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-transform": "^1.0.0", "prosemirror-view": "^1.27.0" } }, "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw=="],
"prosemirror-tables": ["prosemirror-tables@1.8.5", "", { "dependencies": { "prosemirror-keymap": "^1.2.3", "prosemirror-model": "^1.25.4", "prosemirror-state": "^1.4.4", "prosemirror-transform": "^1.10.5", "prosemirror-view": "^1.41.4" } }, "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw=="],
"prosemirror-trailing-node": ["prosemirror-trailing-node@3.0.0", "", { "dependencies": { "@remirror/core-constants": "3.0.0", "escape-string-regexp": "^4.0.0" }, "peerDependencies": { "prosemirror-model": "^1.22.1", "prosemirror-state": "^1.4.2", "prosemirror-view": "^1.33.8" } }, "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ=="],
"prosemirror-transform": ["prosemirror-transform@1.11.0", "", { "dependencies": { "prosemirror-model": "^1.21.0" } }, "sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw=="],
"prosemirror-view": ["prosemirror-view@1.41.6", "", { "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0" } }, "sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg=="],
"punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="],
"quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="],
"radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
"rc9": ["rc9@3.0.0", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.5" } }, "sha512-MGOue0VqscKWQ104udASX/3GYDcKyPI4j4F8gu/jHHzglpmy9a/anZK3PNe8ug6aZFl+9GxLtdhe3kVZuMaQbA=="],
"readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"regexp-tree": ["regexp-tree@0.1.27", "", { "bin": "bin/regexp-tree" }, "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA=="],
"reka-ui": ["reka-ui@2.8.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^14.1.0", "@vueuse/shared": "^14.1.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.2.0" } }, "sha512-8lTKcJhmG+D3UyJxhBnNnW/720sLzm0pbA9AC1MWazmJ5YchJAyTSl+O00xP/kxBmEN0fw5JqWVHguiFmsGjzA=="],
"rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "bin": "dist/bin/rollup" }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="],
"rope-sequence": ["rope-sequence@1.3.4", "", {}, "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ=="],
"scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="],
"semver": ["semver@7.7.4", "", { "bin": "bin/semver.js" }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
"strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
"strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
"tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
"tailwind-variants": ["tailwind-variants@3.2.2", "", { "peerDependencies": { "tailwind-merge": ">=3.0.0", "tailwindcss": "*" } }, "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg=="],
"tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="],
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
"tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
"tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"type-level-regexp": ["type-level-regexp@0.1.17", "", {}, "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="],
"ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
"unctx": ["unctx@2.5.0", "", { "dependencies": { "acorn": "^8.15.0", "estree-walker": "^3.0.3", "magic-string": "^0.30.21", "unplugin": "^2.3.11" } }, "sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg=="],
"unhead": ["unhead@2.1.10", "", { "dependencies": { "hookable": "^6.0.1" } }, "sha512-We8l9uNF8zz6U8lfQaVG70+R/QBfQx1oPIgXin4BtZnK2IQpz6yazQ0qjMNVBDw2ADgF2ea58BtvSK+XX5AS7g=="],
"unifont": ["unifont@0.7.4", "", { "dependencies": { "css-tree": "^3.1.0", "ofetch": "^1.5.1", "ohash": "^2.0.11" } }, "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg=="],
"unimport": ["unimport@5.7.0", "", { "dependencies": { "acorn": "^8.16.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "pathe": "^2.0.3", "picomatch": "^4.0.3", "pkg-types": "^2.3.0", "scule": "^1.3.0", "strip-literal": "^3.1.0", "tinyglobby": "^0.2.15", "unplugin": "^2.3.11", "unplugin-utils": "^0.3.1" } }, "sha512-njnL6sp8lEA8QQbZrt+52p/g4X0rw3bnGGmUcJnt1jeG8+iiqO779aGz0PirCtydAIVcuTBRlJ52F0u46z309Q=="],
"unplugin": ["unplugin@3.0.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg=="],
"unplugin-auto-import": ["unplugin-auto-import@21.0.0", "", { "dependencies": { "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "picomatch": "^4.0.3", "unimport": "^5.6.0", "unplugin": "^2.3.11", "unplugin-utils": "^0.3.1" }, "peerDependencies": { "@nuxt/kit": "^4.0.0", "@vueuse/core": "*" } }, "sha512-vWuC8SwqJmxZFYwPojhOhOXDb5xFhNNcEVb9K/RFkyk/3VnfaOjzitWN7v+8DEKpMjSsY2AEGXNgt6I0yQrhRQ=="],
"unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
"unplugin-vue-components": ["unplugin-vue-components@31.0.0", "", { "dependencies": { "chokidar": "^5.0.0", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "obug": "^2.1.1", "picomatch": "^4.0.3", "tinyglobby": "^0.2.15", "unplugin": "^2.3.11", "unplugin-utils": "^0.3.1" }, "peerDependencies": { "@nuxt/kit": "^3.2.2 || ^4.0.0", "vue": "^3.0.0" } }, "sha512-4ULwfTZTLuWJ7+S9P7TrcStYLsSRkk6vy2jt/WTfgUEUb0nW9//xxmrfhyHUEVpZ2UKRRwfRb8Yy15PDbVZf+Q=="],
"unstorage": ["unstorage@1.17.4", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.5", "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw=="],
"untyped": ["untyped@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "defu": "^6.1.4", "jiti": "^2.4.2", "knitwork": "^1.2.0", "scule": "^1.3.0" }, "bin": "dist/cli.mjs" }, "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g=="],
"vaul-vue": ["vaul-vue@0.4.1", "", { "dependencies": { "@vueuse/core": "^10.8.0", "reka-ui": "^2.0.0", "vue": "^3.4.5" }, "peerDependencies": { "reka-ui": "^2.0.0", "vue": "^3.3.0" } }, "sha512-A6jOWOZX5yvyo1qMn7IveoWN91mJI5L3BUKsIwkg6qrTGgHs1Sb1JF/vyLJgnbN1rH4OOOxFbtqL9A46bOyGUQ=="],
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": "bin/vite.js" }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
"vue": ["vue@3.5.29", "", { "dependencies": { "@vue/compiler-dom": "3.5.29", "@vue/compiler-sfc": "3.5.29", "@vue/runtime-dom": "3.5.29", "@vue/server-renderer": "3.5.29", "@vue/shared": "3.5.29" }, "peerDependencies": { "typescript": "*" } }, "sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA=="],
"vue-chartjs": ["vue-chartjs@5.3.3", "", { "peerDependencies": { "chart.js": "^4.1.1", "vue": "^3.0.0-0 || ^2.7.0" } }, "sha512-jqxtL8KZ6YJ5NTv6XzrzLS7osyegOi28UGNZW0h9OkDL7Sh1396ht4Dorh04aKrl2LiSalQ84WtqiG0RIJb0tA=="],
"vue-component-type-helpers": ["vue-component-type-helpers@3.2.5", "", {}, "sha512-tkvNr+bU8+xD/onAThIe7CHFvOJ/BO6XCOrxMzeytJq40nTfpGDJuVjyCM8ccGZKfAbGk2YfuZyDMXM56qheZQ=="],
"vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
"webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
"wheel-gestures": ["wheel-gestures@2.2.48", "", {}, "sha512-f+Gy33Oa5Z14XY9679Zze+7VFhbsQfBFXodnU2x589l4kxGM9L5Y8zETTmcMR5pWOPQyRv4Z0lNax6xCO0NSlA=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"y-protocols": ["y-protocols@1.0.7", "", { "dependencies": { "lib0": "^0.2.85" }, "peerDependencies": { "yjs": "^13.0.0" } }, "sha512-YSVsLoXxO67J6eE/nV4AtFtT3QEotZf5sK5BHxFBXso7VDUT3Tx07IfA6hsu5Q5OmBdMkQVmFZ9QOA7fikWvnw=="],
"yjs": ["yjs@13.6.29", "", { "dependencies": { "lib0": "^0.2.99" } }, "sha512-kHqDPdltoXH+X4w1lVmMtddE3Oeqq48nM40FD5ojTd8xYhQpzIDcfE2keMSU5bAgRPJBe225WTUdyUgj1DtbiQ=="],
"@nuxtjs/color-mode/@nuxt/kit": ["@nuxt/kit@3.21.1", "", { "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.8", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.3.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^3.0.0", "scule": "^1.3.0", "semver": "^7.7.4", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unctx": "^2.5.0", "untyped": "^2.0.0" } }, "sha512-QORZRjcuTKgo++XP1Pc2c2gqwRydkaExrIRfRI9vFsPA3AzuHVn5Gfmbv1ic8y34e78mr5DMBvJlelUaeOuajg=="],
"@nuxtjs/color-mode/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"@nuxtjs/color-mode/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
"@unhead/vue/hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="],
"@vue/compiler-core/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
"@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"c12/rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
"fontaine/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"magic-regexp/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"nypm/citty": ["citty@0.2.1", "", {}, "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg=="],
"unctx/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unhead/hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="],
"unimport/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"unimport/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unplugin-auto-import/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unplugin-vue-components/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"vaul-vue/@vueuse/core": ["@vueuse/core@10.11.1", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "10.11.1", "@vueuse/shared": "10.11.1", "vue-demi": ">=0.14.8" } }, "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww=="],
"@nuxtjs/color-mode/@nuxt/kit/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"@nuxtjs/color-mode/@nuxt/kit/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
"@nuxtjs/color-mode/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
"@nuxtjs/color-mode/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
"vaul-vue/@vueuse/core/@types/web-bluetooth": ["@types/web-bluetooth@0.0.20", "", {}, "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="],
"vaul-vue/@vueuse/core/@vueuse/metadata": ["@vueuse/metadata@10.11.1", "", {}, "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw=="],
"vaul-vue/@vueuse/core/@vueuse/shared": ["@vueuse/shared@10.11.1", "", { "dependencies": { "vue-demi": ">=0.14.8" } }, "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA=="],
"vaul-vue/@vueuse/core/vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
"vaul-vue/@vueuse/core/@vueuse/shared/vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
}
}

View File

@@ -10,17 +10,67 @@ CREATE TABLE IF NOT EXISTS b2b_routes (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT IGNORE INTO b2b_routes
(name, path, component, meta, active)
VALUES
('root', '', '', '{"trans": "route.root"}', 0),
('home', '', '/views/HomeView.vue', '{"trans": "route.home"}', 1),
('login', 'login', '/views/LoginView.vue', '{"guest":true}', 1),
('register', 'register', '/views/RegisterView.vue', '{"guest":true}', 1),
('password-recovery', 'password-recovery', '/views/PasswordRecoveryView.vue', '{"guest":true}', 1),
('reset-password', 'reset-password', '/views/ResetPasswordView.vue', '{"guest":true}', 1),
('verify-email', 'verify-email', '/views/VerifyEmailView.vue', '{"guest":true}', 1);
INSERT IGNORE INTO `b2b_routes` (`id`, `name`, `path`, `component`, `meta`, `active`) VALUES
(1, 'root', '', '', '{"trans": "route.root"}', 0),
(2, 'home', '', '/views/HomeView.vue', '{"trans": "route.home"}', 1),
(3, 'login', 'login', '/views/LoginView.vue', '{"guest":true}', 1),
(4, 'register', 'register', '/views/RegisterView.vue', '{"guest":true}', 1),
(5, 'password-recovery', 'password-recovery', '/views/PasswordRecoveryView.vue', '{"guest":true}', 1),
(6, 'reset-password', 'reset-password', '/views/ResetPasswordForm.vue', '{"guest":true}', 1),
(7, 'verify-email', 'verify-email', '/views/VerifyEmailView.vue', '{"guest":true}', 1),
(9, 'admin-products-category', 'products/:category_id-:link_rewrite', '/components/admin/PageProducts.vue', '{
"guest":true,
"name": "Products Category"
}', 1),
(10, 'customer-addresses', 'addresses', '/components/customer/PageAddresses.vue', '{
"guest":true,
"name": "Addresses"
}', 1),
(11, 'customer-cart', 'cart/:id', '/components/customer/PageCart.vue', '{
"guest":true,
"name": "Cart"
}', 1),
(12, 'customer-orders', 'orders', '/components/customer/PageOrders.vue', '{
"guest":true,
"name": "Order"
}', 1),
(13, 'customer-statistic', 'statistic', '/components/customer/PageStatistic.vue', '{
"guest":true,
"name": "Statistic"
}
', 1),
(14, 'admin-product-details', 'products/:product_id', '/components/admin/ProductDetailView.vue', '{
"guest":true,
"name": "Products"
}
', 1),
(15, 'admin-products', 'products', '/components/admin/PageProducts.vue', '{
"guest":true,
"name": "Products"
}
', 1),
(16, 'admin-users-list', 'users-list', '/components/admin/UsersList.vue', '{
"guest":true,
"name": "Client List"
}
', 1),
(17, 'customer-management-profile', ':user_id/profile', '/components/customer-management/Profile.vue', '{
"guest":true,
"name": "Profile"
}
', 1),
(18, 'admin-users-search', 'users-search', '/components/admin/UsersSearch.vue', '{
"guest":true,
"name": "Search Clients"
}
', 1),
(19, 'customer-storage-file', 'file-storage', '/components/customer/StorageFileBrowser.vue', '{
"guest":true,
"name": "File Storage"
}', 1),
(20, 'customer-products', 'products', '/components/customer/PageProducts.vue', '{ "guest":true, "name": "Products" }', 1),
(21, 'customer-product-details', 'products/:product_id', '/components/customer/PageProduct.vue', '{ "guest":true, "name": "Products" }', 1),
(22, 'customer-page-carts', 'carts', '/components/customer/PageCarts.vue', '{ "guest":true, "name": "Carts" }', 1);
CREATE TABLE IF NOT EXISTS b2b_top_menu (
menu_id INT AUTO_INCREMENT NOT NULL,
@@ -36,12 +86,207 @@ CREATE TABLE IF NOT EXISTS b2b_top_menu (
INDEX FK_b2b_top_menu_parent_id_idx (parent_id ASC)
) ENGINE = InnoDB;
INSERT IGNORE INTO `b2b_top_menu` (`menu_id`, `label`, `parent_id`, `params`, `active`, `position`) VALUES
(1, JSON_COMPACT('{"name":"root","trans":{"pl":{"label":"Menu główne"},"en":{"label":"Main Menu"},"de":{"label":"Hauptmenü"}}}'),NULL,JSON_COMPACT('{}'),1,1),
(3, JSON_COMPACT('{"name":"admin-products","trans":{"pl":{"label":"admin-products"},"en":{"label":"admin-products"},"de":{"label":"admin-products"}}}'),1,JSON_COMPACT('{}'),1,1),
(9, JSON_COMPACT('{"name":"carts","trans":{"pl":{"label":"Koszyki"},"en":{"label":"Carts"},"de":{"label":"Warenkörbe"}}}'),3,JSON_COMPACT('{"route": {"name": "home", "params":{"locale": ""}}}'),1,1);
INSERT IGNORE INTO `b2b_top_menu` (`menu_id`, `label`, `parent_id`, `params`, `active`, `position`) VALUES
(1, '{"name":"root","trans":{"pl":{"label":"Menu główne"},"en":{"label":"Main Menu"},"de":{"label":"Hauptmenü"}}}', NULL, '{}', 1, 1),
(2, '{
"name": "admin-products",
"trans": {
"pl": {
"label": "Products"
},
"en": {
"label": "Products"
},
"de": {
"label": "Products"
}
},
"icon" : "quill:list"
}', 1, '{"route":{"name":"admin-products","params":{"locale":""}}}', 1, 1),
(4, '{
"name": "customer-addresses",
"trans": {
"pl": {
"label": "Addresses"
},
"en": {
"label": "Addresses"
},
"de": {
"label": "Addresses"
}
},
"icon" : "ph:address-book"
}', 1, '{"route":{"name":"customer-addresses","params":{"locale":""}}}', 1, 1),
(5, '{
"name": "customer-orders",
"trans": {
"pl": {
"label": "Orders"
},
"en": {
"label": "Orders"
},
"de": {
"label": "Orders"
}
},
"icon" : "lsicon:order-integral-outline"
}', 1, '{"route":{"name":"customer-orders","params":{"locale":""}}}', 1, 1),
(6, '{
"name": "customer-statistic",
"trans": {
"pl": {
"label": "Statistic"
},
"en": {
"label": "Statistic"
},
"de": {
"label": "Statistic"
}
},
"icon" : "akar-icons:statistic-up"
}', 1, '{
"route": {
"name": "customer-statistic",
"params": {
"locale": ""
}
}
}', 1, 1),
(10, '{
"name": "customer-storage-file",
"trans": {
"pl": {
"label": "File Storage"
},
"en": {
"label": "File Storage"
},
"de": {
"label": "File Storage"
}
},
"icon": "carbon:volume-file-storage"
}', 1, '{
"route": {
"name": "customer-storage-file",
"params": {
"locale": ""
}
}
}', 1, 1),
(12, '{
"name": "admin-users-list",
"trans": {
"pl": {
"label": "Client List"
},
"en": {
"label": "Client List"
},
"de": {
"label": "Client List"
}
},
"icon": "tdesign:user-list"
}', 1, '{
"route": {
"name": "admin-users-list",
"params": {
"locale": ""
}
}
}', 1, 1),
(13, '{
"name": "admin-users-search",
"trans": {
"pl": {
"label": "Search Clients"
},
"en": {
"label": "Search Clients"
},
"de": {
"label": "Search Clients"
}
},
"icon": "material-symbols:search"
}', 1, '{
"route": {
"name": "admin-users-search",
"params": {
"locale": ""
}
}
}', 1, 1),
(14, '{
"name": "customer-management-profile",
"trans": {
"pl": {
"label": "Profile"
},
"en": {
"label": "Profile"
},
"de": {
"label": "Profile"
}
},
"icon": "akar-icons:statistic-up"
}', 1, '{
"route": {
"name": "customer-management-profile",
"params": {
"locale": ""
}
}
}', 1, 1),
(15, '{
"name": "customer-products",
"trans": {
"pl": {
"label": "Products"
},
"en": {
"label": "Products"
},
"de": {
"label": "Products"
}
},
"icon": "akar-icons:statistic-up"
}', 1, '{
"route": {
"name": "customer-products",
"params": {
"locale": ""
}
}
}', 1, 1),
(16, '{
"name": "customer-page-carts",
"trans": {
"pl": {
"label": "Carts"
},
"en": {
"label": "Carts"
},
"de": {
"label": "Carts"
}
},
"icon": "proicons:cart1"
}', 1, '{
"route": {
"name": "customer-page-carts",
"params": {
"locale": ""
}
}
}', 1, 1);
-- +goose Down

View File

@@ -338,6 +338,24 @@ ON b2b_specific_price_customer (b2b_id_customer);
CREATE INDEX idx_bsp_country_rel
ON b2b_specific_price_country (b2b_id_country);
CREATE TABLE b2b_route_roles (
route_id INT NOT NULL,
role_id BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (route_id, role_id),
INDEX idx_role_id (role_id),
INDEX idx_route_id (route_id),
CONSTRAINT FK_b2b_route_roles_route_id
FOREIGN KEY (route_id)
REFERENCES b2b_routes (id)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT FK_b2b_route_roles_role_id
FOREIGN KEY (role_id)
REFERENCES b2b_roles (id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB;
DELIMITER //
CREATE FUNCTION IF NOT EXISTS slugify_eu(input TEXT)
@@ -438,6 +456,7 @@ DROP TABLE IF EXISTS b2b_customer_carts;
DROP TABLE IF EXISTS b2b_specific_price_country;
DROP TABLE IF EXISTS b2b_specific_price_customer;
DROP TABLE IF EXISTS b2b_specific_price_product_attribute;
DROP TABLE IF EXISTS b2b_route_roles;
DROP TABLE IF EXISTS b2b_specific_price_category;
DROP TABLE IF EXISTS b2b_specific_price_product;
DROP TABLE IF EXISTS b2b_specific_price;

View File

@@ -10,7 +10,7 @@ VALUES
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('user','1');
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('admin','2');
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('super_admin','3');
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('unlogged','4');
-- insert sample admin user admin@ma-al.com/Maal12345678
INSERT IGNORE INTO b2b_customers (id, email, password, first_name, last_name, role_id, provider, provider_id, avatar_url, is_active, email_verified, email_verification_token, email_verification_expires, password_reset_token, password_reset_expires, last_password_reset_request, last_login_at, lang_id, country_id, created_at, updated_at, deleted_at)
@@ -39,6 +39,9 @@ INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('6', 'webdav.create_token')
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('7', 'product_translation.save');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('8', 'product_translation.translate');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('9', 'search.create_index');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('10', 'orders.view_all');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('11', 'orders.modify_all');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('12', 'teleport');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '1');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '2');
@@ -49,6 +52,9 @@ INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '6'
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '7');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '8');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '9');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '10');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '11');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '12');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '1');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '2');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '3');
@@ -58,4 +64,55 @@ INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '6'
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '7');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '8');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '9');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '10');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '11');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '12');
INSERT INTO `b2b_route_roles` (`route_id`, `role_id`) VALUES
(1, '1'),
(1, '2'),
(1, '3'),
(2, '1'),
(2, '2'),
(2, '3'),
(2, '4'),
(3, '1'),
(3, '2'),
(3, '3'),
(3, '4'),
(4, '1'),
(4, '2'),
(4, '3'),
(4, '4'),
(5, '1'),
(5, '2'),
(5, '3'),
(5, '4'),
(6, '1'),
(6, '2'),
(6, '3'),
(6, '4'),
(7, '1'),
(7, '2'),
(7, '3'),
(7, '4'),
(9, '2'),
(9, '3'),
(10, '1'),
(11, '1'),
(12, '1'),
(13, '1'),
(14, '2'),
(14, '3'),
(15, '2'),
(15, '3'),
(16, '2'),
(16, '3'),
(17, '1'),
(18, '2'),
(18, '3'),
(19, '1'),
(20, '1'),
(21, '1'),
(22, '1');
-- +goose Down

View File

@@ -319,7 +319,8 @@ DROP PROCEDURE IF EXISTS get_product_base //
CREATE PROCEDURE get_product_base(
IN p_id_product INT,
IN p_id_shop INT,
IN p_id_lang INT
IN p_id_lang INT,
IN p_id_customer INT
)
BEGIN
SELECT
@@ -376,14 +377,12 @@ BEGIN
-- Relations
m.name AS manufacturer,
cl.name AS category
cl.name AS category,
-- This doesn't fit to base product, I'll add proper is_favorite to product later
-- EXISTS(
-- SELECT 1 FROM b2b_favorites f
-- WHERE f.user_id = p_id_customer AND f.product_id = p_id_product
-- ) AS is_favorite
EXISTS(
SELECT 1 FROM b2b_favorites f
WHERE f.user_id = p_id_customer AND f.product_id = p_id_product
) AS is_favorite

5277
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,5 @@
{
"dependencies": {
"@nuxt/ui": "^4.5.1",
"chart.js": "^4.5.1",
"dompurify": "^3.3.3",
"vue-chartjs": "^5.3.3"
"dompurify": "^3.3.3"
}
}
}