diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 509e808..fe04e64 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,35 +43,4 @@ jobs: build-platform: ${{ matrix.build.platform }} package: true go-version: '1.23' - - build-container: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - - name: Build and push Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 - with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5a56260..7c0bd85 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Wails build +name: Fyne build on: push: @@ -10,6 +10,7 @@ env: NODE_OPTIONS: "--max-old-space-size=4096" REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} + CGO_ENABLED: 1 jobs: build: @@ -19,57 +20,61 @@ jobs: matrix: build: - name: 'gogallery' - platform: 'linux/amd64' os: 'ubuntu-latest' + goos: 'linux' + goarch: 'amd64' - name: 'gogallery' - platform: 'windows/amd64' os: 'windows-latest' + goos: 'windows' + goarch: 'amd64' - name: 'gogallery' - platform: 'darwin/universal' os: 'macos-latest' + goos: 'darwin' + goarch: 'amd64' + - name: 'gogallery' + os: 'macos-latest' + goos: 'darwin' + goarch: 'arm64' runs-on: ${{ matrix.build.os }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive - - name: Build wails - uses: dAppServer/wails-build-action@v2.2 - id: build + - name: Set up Go + uses: actions/setup-go@v4 with: - build-name: ${{ matrix.build.name }} - build-platform: ${{ matrix.build.platform }} - package: false - go-version: '1.21' - build-and-push-image: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write + go-version: '>=1.24.2' + check-latest: true - steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Install Fyne dependencies (Ubuntu) + if: matrix.build.os == 'ubuntu-latest' + run: | + make fyne-deps-ubuntu - - name: Log in to the Container registry - uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Install Fyne dependencies (macOS) + if: matrix.build.os == 'macos-latest' + run: | + # macOS has the necessary frameworks built-in - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Install Fyne CLI + run: make fyne-cli + + - name: Build Fyne app + env: + GOOS: ${{ matrix.build.goos }} + GOARCH: ${{ matrix.build.goarch }} + CGO_ENABLED: 1 + shell: bash + run: | + make fyne-build - - name: Build and push Docker image - uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + - name: Upload artifacts + uses: actions/upload-artifact@v4 with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + name: ${{ matrix.build.name }}-${{ matrix.build.goos }}-${{ matrix.build.goarch }} + path: | + ${{ matrix.build.name }}* + diff --git a/.gitignore b/.gitignore index 07b49cb..6402c95 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,9 @@ temp # production /build -ui +.env +.sql + # misc .DS_Store .env.local @@ -36,6 +38,7 @@ ui .env.test.local .env.production.local +themes/**/package-lock.json npm-debug.log* yarn-debug.log* yarn-error.log* diff --git a/.vscode/launch.json b/.vscode/launch.json index 465bfc0..c667525 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ "mode": "auto", "cwd": "${workspaceFolder}", "program": "main.go", - "args": ["dev"] + // "args": ["serve"] } ] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index fcfcd4e..0000000 --- a/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM node:lts-alpine as UI_BUILDER -ARG VER -WORKDIR /frontend -ADD /frontend . -RUN npm i; npm run build; - -FROM golang:1.23.1 as GO_BUILDER -ARG VER -WORKDIR /server -ADD go.mod . -ADD go.sum . -ADD main.go main.go -ADD backend backend -ADD themes themes -COPY --from=UI_BUILDER /frontend/dist /server/frontend/dist -RUN CGO_ENABLED=1 GOOS=linux go build - -FROM ubuntu -LABEL org.opencontainers.image.source="https://github.com/robrotheram/gogallery" -WORKDIR /app -COPY --from=GO_BUILDER /server/gogallery /app/gogallery -COPY config_sample.yml /app/config.yml -ENV GLLRY_SERVER_PORT ":80" -ENV GLLRY_GALLERY_BASEPATH "/app/pictures" -ENV GLLRY_GALLERY_THEME "default" -WORKDIR /app -ENTRYPOINT ["/app/gogallery", "--config", "/app/config.yml", "serve"] \ No newline at end of file diff --git a/themes/eastnor/assets/logos/logo192.png b/Icon.png similarity index 100% rename from themes/eastnor/assets/logos/logo192.png rename to Icon.png diff --git a/Makefile b/Makefile index b5b955c..617580f 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ GOBUILD=$(GOCMD) build GOCLEAN=$(GOCMD) clean GOTEST=$(GOCMD) test GOGET=$(GOCMD) get -BINARY_NAME=../gogallery -BINARY_UNIX=$(BINARY_NAME)_unix +FYNE=fyne +BINARY_NAME=gogallery ifndef CIRCLE_BRANCH override CIRCLE_BRANCH = latest @@ -12,32 +12,57 @@ else override CIRCLE_BRANCH = $(shell git rev-parse --abbrev-ref HEAD | sed 's/[^a-zA-Z0-9]/-/g') endif -all: clean test build +build-themes: + @echo "Building themes..." + @for theme in themes/*; do \ + if [ -d "$$theme" ]; then \ + echo "Building theme: $$theme"; \ + cd "$$theme" && npm install && npm run build && npm run clean; \ + cd -; \ + fi; \ + done -dep: - go install github.com/wailsapp/wails/v2/cmd/wails@latest +build: + @echo "Building GoGallery..." + $(GOBUILD) -o $(BINARY_NAME) -v . -test: - cd server && $(GOTEST) -v ./... +# Cross-platform Fyne build (mimics CI logic) +.PHONY: fyne-build +fyne-build: + @echo "Building GoGallery with Fyne packaging..." + go mod download + @export GOOS=$(GOOS); export GOARCH=$(GOARCH); export CGO_ENABLED=1; \ + if [ "$(GOOS)" = "windows" ]; then \ + OUTPUT_NAME="$(BINARY_NAME).exe"; \ + $(FYNE) package -os windows -name "$$OUTPUT_NAME" .; \ + elif [ "$(GOOS)" = "darwin" ]; then \ + $(FYNE) package -os darwin -name "$(BINARY_NAME).app" .; \ + else \ + OUTPUT_NAME="$(BINARY_NAME)"; \ + $(FYNE) package -os linux -name "$$OUTPUT_NAME" .; \ + fi -package: - tar -czvf gogallery-linux-amd64.tgz gogallery config_sample.yml ui -# Cross compilation -build-linux: - wails build -tags webkit2_41 -build-windows: - CC=x86_64-w64-mingw32-gccGOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ wails build -skipbindings +# Install Fyne CLI +.PHONY: fyne-cli +fyne-cli: + $(GOCMD) install fyne.io/tools/cmd/fyne@latest -docker: - docker build . -t robrotheram/gogallery:$(CIRCLE_BRANCH) - docker build . -t robrotheram/gogallery:latest -docker-publish: - docker push robrotheram/gogallery:$(CIRCLE_BRANCH) - docker push robrotheram/gogallery:latest +# Install Fyne dependencies (Ubuntu) +.PHONY: fyne-deps-ubuntu +fyne-deps-ubuntu: + sudo apt-get update + sudo apt-get install -y gcc libgl1-mesa-dev xorg-dev libxkbcommon-dev -install: - cp build/bin/gogallery /home/${HOME}/.local/bin/gogallery +# Install Fyne dependencies (RedHat/Fedora) +.PHONY: fyne-deps-fedora +fyne-deps-fedora: + sudo dnf install -y gcc mesa-libGL-devel libX11-devel libxkbcommon-devel -update: - go get -u - go mod tidy \ No newline at end of file +# Build all (default) +.PHONY: all +all: fyne-cli fyne-build + +# Clean +.PHONY: clean +clean: + rm -rf $(BINARY_NAME) $(BINARY_NAME).exe $(BINARY_NAME).app \ No newline at end of file diff --git a/Readme.md b/Readme.md index 666d096..92d66c9 100644 --- a/Readme.md +++ b/Readme.md @@ -25,14 +25,11 @@ gogallery [flags] ### SEE ALSO * [gogallery build](docs/cli/gogallery_build.md) - build static site -* [gogallery completion](docs/cli/gogallery_completion.md) - Generate the autocompletion script for the specified shell -* [gogallery dashboard](docs/cli/gogallery_dashboard.md) - dashboard * [gogallery deploy](docs/cli/gogallery_deploy.md) - deploy static site -* [gogallery docs](docs/cli/gogallery_docs.md) - cli docs -* [gogallery init](docs/cli/gogallery_init.md) - create site * [gogallery serve](docs/cli/gogallery_serve.md) - serve static site * [gogallery template](docs/cli/gogallery_template.md) - extract template + --- ## History @@ -49,104 +46,70 @@ Demo at https://gallery.exceptionerror.io ## Screenshots -### Gallery -![Screenshot1](/docs/img1.jpg?raw=true "Gallery Image") -![Screenshot1](/docs/img2.jpg?raw=true "Gallery Image") - -### Dashboard: - -![Screenshot1](/docs/dashboard1.jpg?raw=true "Gallery Image") -![Screenshot1](/docs/dashboard2.png?raw=true "Gallery Image") -![Screenshot1](/docs/dashboard3.png?raw=true "Gallery Image") - - -## Installation -Makefile to the rescue - -### build all -``` - make -``` +### Dashboard/App -### build dashboard -``` - make build-dashboard -``` -### build server -``` - make build-server -``` - - -## Usage +| Dashboard Home | Settings | Tasks | +|----------------|----------|-------| +| ![Homepage](docs/homepage.png) | ![Settings](docs/settings.png) | ![Tasks](docs/tasks.png) | -Edit the config and change the name basepath and base folder that is used for scanning images +| Album View | Sidebar | +|------------|---------| +| ![Album](docs/album.png) | ![Sidebar](docs/sidebar.png) | -#### Dashboard login -Gogallery on first run will autocreate a admin accound with username `admin` and a 8 character autogenerated password which you will find in the log. Once loged in you can go to settings and user to set it +### Generated Website -Dashboard url `%GALLERY_PATH/dashboard` +| Website Home | Photo Page | Collection Page | +|--------------|------------|-----------------| +| ![Website Home](docs/website-home.png) | ![Website Photo](docs/website-photo.png) | ![Website Collection](docs/website-collection.png) | -If you forget the admin password for any reason you can use the `gogallery --reset-admin` which will recrate the admin username and password +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. -## Themes - -Version 5.x has support for users themes. The theme engine uses Go’s html/template and text/template libraries as the basis for the templating. This is similar to the one hugo uses https://gohugo.io/templates/introduction/ but with the varibles being different. - -All Themes will need to have the following pages in order for the site to work: - - 404.hbs - - albums.hbs - - collections.hbs - - main.hbs - - photo.hbs +Please make sure to update tests as appropriate. -Optionally you can have a *"default.hbs"* to define common heading and footers -The engine has support for partials that can be stored in the subfolder partials and all other assests can be stored the assets folder. +## License +[apache-2.0](https://choosealicense.com/licenses/apache-2.0) -See the example theme **eastnor** for reference -### Caching -The server implements its own caching layer after the page has been visited it will cache the page in memory so next load of that page becomes very quick this can produce 10X improvement of load times. +## Building GoGallery -The Cache gets invalidated if the server restarts or if you have made a change in the dashboard. +You can build GoGallery from source using Go. Make sure you have Go 1.20 or newer installed. +### Standard Build (CLI and Web) -#### Docker Configuration -Config can be also edited via environmental variables - +You can use the provided Makefile for building: +```bash +make build # Build the GoGallery CLI/web binary +make build-themes # Build all theme assets (npm install/build/clean in each theme) +make clean # Remove built binaries ``` -GLLRY_SERVER_PORT -GLLRY_SERVER_WORKERS -GLLRY_SERVER_CAPTIONURL +This will produce the `gogallery` binary in your current directory. -GLLRY_DATABASE_BASEURL +Or, to build manually: -GLLRY_GALLERY_NAME -GLLRY_GALLERY_BASEPATH -GLLRY_GALLERY_URL -GALLRY_GALLERY_THEME -GALLRY_GALLERY_PICTUREBLACKLIST -GALLRY_GALLERY_ALBUMBLACKLIST +```bash +go build -o gogallery main.go +``` -GLLRY_ABOUT_INSTAGRAM -GLLRY_ABOUT_TWITTER -GLLRY_ABOUT_EMAIL +### Building the Fyne Desktop App -GLLRY_ABOUT_WEBSITE -GLLRY_ABOUT_DESCRIPTION -GLLRY_ABOUT_PHOTOGRAPHER -GLLRY_ABOUT_BACKGROUNDPHOTO -GLLRY_ABOUT_PROFILEPHOTO +You can use the Makefile to build the Fyne desktop app and install dependencies: +```bash +make fyne-cli # Install the Fyne CLI tool +make fyne-deps-ubuntu # Install Fyne dependencies (Ubuntu) +make fyne-deps-fedora # Install Fyne dependencies (Fedora/RedHat) +make fyne-build # Build the Fyne desktop app for your platform ``` -## Contributing -Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. +- The `fyne-build` target will auto-detect your OS and build the appropriate package. +- You can also run `make all` to install Fyne CLI and build the desktop app in one step. -Please make sure to update tests as appropriate. +> For more details, see the [Fyne documentation](https://developer.fyne.io/started/packaging) and the GoGallery wiki. -## License -[apache-2.0](https://choosealicense.com/licenses/apache-2.0) +## Theme Development + +See the [Theme Development Guide](themes/DEVELOPER_README.md) for instructions on building and customizing GoGallery templates and themes. diff --git a/backend/api/collections.go b/backend/api/collections.go deleted file mode 100644 index 0e1451f..0000000 --- a/backend/api/collections.go +++ /dev/null @@ -1,142 +0,0 @@ -package api - -import ( - "encoding/json" - "fmt" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/gorilla/mux" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/datastore/models" -) - -type Collections struct { - CaptureDates []string `json:"dates"` - UploadDates []string `json:"uploadDates"` - Albums map[string]models.Album `json:"albums"` -} - -type MoveCollection struct { - Album string `json:"album"` - Photos []models.Picture `json:"photos"` -} - -func (api *GoGalleryAPI) moveCollectionHandler(w http.ResponseWriter, r *http.Request) { - var moveCollection MoveCollection - _ = json.NewDecoder(r.Body).Decode(&moveCollection) - for _, photo := range moveCollection.Photos { - oldPicture := api.db.Pictures.FindByID(photo.Id) - if oldPicture.Album != moveCollection.Album { - api.db.Albums.MovePictureToAlbum(&photo, moveCollection.Album) - photo.Meta.DateModified = time.Now() - api.db.Pictures.Save(&photo) - } - } - -} - -func (api *GoGalleryAPI) updateCollectionHandler(w http.ResponseWriter, r *http.Request) { - albumID := mux.Vars(r)["id"] - oldAlbum := api.db.Albums.FindByID(albumID) - - var album models.Album - _ = json.NewDecoder(r.Body).Decode(&album) - - if oldAlbum.Name != album.Name { - oldPath := fmt.Sprintf("%s/%s", filepath.Dir(oldAlbum.ParenetPath), oldAlbum.Name) - newPath := fmt.Sprintf("%s/%s", filepath.Dir(oldAlbum.ParenetPath), album.Name) - os.Rename(oldPath, newPath) - oldAlbum.Name = album.Name - } - - if oldAlbum.ProfileID != album.ProfileID { - oldAlbum.ProfileID = album.ProfileID - } - - if oldAlbum.GPS.Lat != album.GPS.Lat || oldAlbum.GPS.Lng != album.GPS.Lng { - oldAlbum.GPS = album.GPS - } - - api.db.Albums.Save(&oldAlbum) - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(oldAlbum) -} - -func (api *GoGalleryAPI) createCollectionHandler(w http.ResponseWriter, r *http.Request) { - var album models.Album - _ = json.NewDecoder(r.Body).Decode(&album) - - path := "" - if album.Id != "" { - newAlbum := api.db.Albums.FindByID(album.Id) - path = fmt.Sprintf("%s/%s/%s", newAlbum.ParenetPath, newAlbum.Name, album.Name) - } else { - path = fmt.Sprintf("%s/%s", api.config.Gallery.Basepath, album.Name) - } - - album.Id = config.GetMD5Hash(path) - album.ParenetPath = filepath.Dir(path) - album.ModTime = time.Now() - album.Children = make(map[string]models.Album) - - fmt.Println(album) - if _, err := os.Stat(path); os.IsNotExist(err) { - os.Mkdir(path, 0755) - } - - api.db.Albums.Save(&album) -} - -func (api *GoGalleryAPI) getCollectionPhotosHandler(w http.ResponseWriter, r *http.Request) { - albumID := mux.Vars(r)["id"] - pictures := api.db.Pictures.FindManyFeild("Album", albumID) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(pictures) -} - -func (api *GoGalleryAPI) getCollectionHandler(w http.ResponseWriter, r *http.Request) { - albumID := mux.Vars(r)["id"] - album := api.db.Albums.FindByID(albumID) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(album) -} - -func (api *GoGalleryAPI) getCollectionsHandler(w http.ResponseWriter, r *http.Request) { - - pics := api.db.Pictures.GetAll() - albms := api.db.Albums.GetAll() - newalbms := datastore.SliceToTree(albms, api.config.Gallery.Basepath) - dates := []string{} - uploadDates := []string{} - for _, pic := range pics { - _date := pic.Exif.DateTaken.Format("2006-01-02") - _uploadDate := pic.Meta.DateAdded.Format("2006-01-02 15:04") - - found := false - uploadFound := false - - for _, date := range dates { - if date == _date { - found = true - } - } - for _, date := range uploadDates { - if date == _uploadDate { - uploadFound = true - } - } - if !found { - dates = append(dates, _date) - } - if !uploadFound { - uploadDates = append(uploadDates, _uploadDate) - } - } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(Collections{CaptureDates: dates, UploadDates: uploadDates, Albums: newalbms}) -} diff --git a/backend/api/error.go b/backend/api/error.go deleted file mode 100644 index 7cd8d88..0000000 --- a/backend/api/error.go +++ /dev/null @@ -1,24 +0,0 @@ -package api - -import ( - "encoding/json" - "net/http" -) - -type APIError struct { - Message string `json:"message"` - error -} - -func NewAPIError(err error) *APIError { - return &APIError{ - Message: "Issue Dealing with the request", - error: err, - } -} - -func (a *APIError) HandleError(w http.ResponseWriter) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(a) -} diff --git a/backend/api/photo.go b/backend/api/photo.go deleted file mode 100644 index 8d159ff..0000000 --- a/backend/api/photo.go +++ /dev/null @@ -1,66 +0,0 @@ -package api - -import ( - "encoding/json" - "fmt" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/gorilla/mux" - "github.com/robrotheram/gogallery/backend/datastore/models" -) - -// r.Handle("/api/admin/photo/{id}", auth.AuthMiddleware(getPhotoHandler)).Methods("GET") -// r.Handle("/api/admin/photo/{id}", auth.AuthMiddleware(editPhotoHandler)).Methods("POST") -// r.Handle("/api/admin/photo/{id}", auth.AuthMiddleware(deletePhotoHandler)).Methods("DELETE") - -func (api *GoGalleryAPI) GetPicturesHandler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(models.SortByTime(api.db.Pictures.GetAll())) -} - -func (api *GoGalleryAPI) GetPictureHandler(w http.ResponseWriter, r *http.Request) { - photoID := mux.Vars(r)["id"] - picture := api.db.Pictures.FindByID(photoID) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(picture) -} - -func (api *GoGalleryAPI) UpdatePictureHandler(w http.ResponseWriter, r *http.Request) { - photoID := mux.Vars(r)["id"] - oldPicture := api.db.Pictures.FindByID(photoID) - - var picture models.Picture - err := json.NewDecoder(r.Body).Decode(&picture) - if err != nil { - NewAPIError(err).HandleError(w) - return - } - if oldPicture.Name != picture.Name { - newName := fmt.Sprintf("%s/%s%s", filepath.Dir(oldPicture.Path), picture.Name, filepath.Ext(oldPicture.Path)) - os.Rename(oldPicture.Path, newName) - picture.Path = newName - } - - if oldPicture.Path != picture.Path { - os.Rename(oldPicture.Path, picture.Path) - } - - if oldPicture.Album != picture.Album { - api.db.Albums.MovePictureToAlbum(&picture, picture.Album) - } - picture.Meta.DateModified = time.Now() - api.db.Pictures.Save(&picture) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(picture) -} - -func (api *GoGalleryAPI) DeletePictureHandler(w http.ResponseWriter, r *http.Request) { - photoID := mux.Vars(r)["id"] - picture := api.db.Pictures.FindByID(photoID) - api.db.Pictures.Delete(picture) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(picture) -} diff --git a/backend/api/router.go b/backend/api/router.go deleted file mode 100644 index 926d7e8..0000000 --- a/backend/api/router.go +++ /dev/null @@ -1,214 +0,0 @@ -package api - -import ( - "fmt" - "io" - "log" - "net/http" - "os" - "path" - "path/filepath" - "strings" - - "github.com/gorilla/handlers" - "github.com/gorilla/mux" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/monitor" - "github.com/robrotheram/gogallery/backend/pipeline" - templateengine "github.com/robrotheram/gogallery/backend/templateEngine" - "golang.org/x/net/html" -) - -type GoGalleryAPI struct { - db *datastore.DataStore - config *config.Configuration - router *mux.Router - monitor *monitor.TasksMonitor -} - -func NewGoGalleryAPI(config *config.Configuration, db *datastore.DataStore) *GoGalleryAPI { - api := &GoGalleryAPI{config: config, db: db, monitor: monitor.NewMonitor()} - api.router = mux.NewRouter() - api.setupDashboardRoutes() - return api -} - -func (api *GoGalleryAPI) setupDashboardRoutes() { - fmt.Println("Setting up API") - api.router.HandleFunc("/img/{id}", api.ImgHandler) - api.router.HandleFunc("/img/{id}/{size}.{ext}", api.ImgHandler) - - api.router.HandleFunc("/api/admin/photos", api.GetPicturesHandler).Methods("GET") - api.router.HandleFunc("/api/admin/photo/{id}", api.GetPictureHandler).Methods("GET") - api.router.HandleFunc("/api/admin/photo/{id}", api.UpdatePictureHandler).Methods("POST") - api.router.HandleFunc("/api/admin/photo/{id}", api.DeletePictureHandler).Methods("DELETE") - - api.router.HandleFunc("/api/admin/collection/move", api.moveCollectionHandler).Methods("POST") - api.router.HandleFunc("/api/admin/collection/uploadFile", api.uploadFileHandler).Methods("POST") - api.router.HandleFunc("/api/admin/collection/upload", api.uploadHandler).Methods("POST") - - api.router.HandleFunc("/api/admin/collections", api.getCollectionsHandler).Methods("GET") - api.router.HandleFunc("/api/admin/collection", api.createCollectionHandler).Methods("POST") - api.router.HandleFunc("/api/admin/collection/{id}/photos", api.getCollectionPhotosHandler).Methods("GET") - api.router.HandleFunc("/api/admin/collection/{id}", api.getCollectionHandler).Methods("GET") - api.router.HandleFunc("/api/admin/collection/{id}", api.updateCollectionHandler).Methods("POST") - - api.router.HandleFunc("/api/admin/settings/stats", api.statsHandler).Methods("GET") - api.router.HandleFunc("/api/admin/settings/gallery", api.getGallerySettings).Methods("GET") - api.router.HandleFunc("/api/admin/settings/gallery", api.setGallerySettings).Methods("POST") - api.router.HandleFunc("/api/admin/settings/profile", api.getProfileInfo).Methods("GET") - api.router.HandleFunc("/api/admin/settings/profile", api.setProfileInfo).Methods("POST") - api.router.HandleFunc("/api/admin/settings/deploy", api.getDeploymentSettings).Methods("GET") - api.router.HandleFunc("/api/admin/settings/deploy", api.setDeploymentSettings).Methods("POST") - - api.router.HandleFunc("/api/admin/tasks", api.getTasks).Methods("GET") - api.router.HandleFunc("/api/admin/tasks/purge", api.purgeTaskHandler).Methods("GET") - api.router.HandleFunc("/api/admin/tasks/rescan", api.rescanTaskHandler).Methods("GET") - api.router.HandleFunc("/api/admin/tasks/backup", api.backupTaskHandler).Methods("GET") - api.router.HandleFunc("/api/admin/tasks/upload", api.uploadTaskHandler).Methods("POST") - - api.router.HandleFunc("/api/admin/tasks/build", api.buildTaskHandler).Methods("POST") - api.router.HandleFunc("/api/admin/tasks/publish", api.deployTaskHandler).Methods("POST") -} - -func (api *GoGalleryAPI) ImgHandler(w http.ResponseWriter, r *http.Request) { - size := r.URL.Query().Get("size") - vars := mux.Vars(r) - id := vars["id"] - if len(size) == 0 { - size = vars["size"] - } - pic := api.db.Pictures.FindByID(id) - //Is image in cache - if file, err := api.db.ImageCache.Get(pic.Id, size); err == nil { - io.Copy(w, file) - return - } - src, err := pic.Load() - if err != nil { - return - } - cache, _ := api.db.ImageCache.Writer(pic.Id, size) - writer := io.MultiWriter(w, cache) - if size, ok := templateengine.ImageSizes[size]; ok { - pipeline.ProcessImage(src, size, writer) - return - } - pipeline.ProcessImage(src, templateengine.ImageSizes["xsmall"], writer) -} - -func (api *GoGalleryAPI) DashboardAPI() { - headers := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}) - methods := handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS"}) - origins := handlers.AllowedOrigins([]string{"*"}) - - api.router.PathPrefix("/preview-build").Handler(&home{ - base: api.config.Gallery.Destpath, - }) - spa := SPAHandler{StaticPath: "frontend/dist", IndexPath: "index.html"} - api.router.PathPrefix("/").Handler(spa) - - log.Println("Starting api server on port: http://" + api.config.Server.GetLocalAddr()) - log.Fatal(http.ListenAndServe(api.config.Server.GetLocalAddr(), handlers.CORS(origins, headers, methods)(api.router))) -} - -func (api *GoGalleryAPI) Serve() { - fs := http.FileServer(http.Dir(api.config.Gallery.Destpath)) - http.Handle("/", fs) - log.Println("Starting server on port: http://" + api.config.Server.GetAddr()) - log.Fatal(http.ListenAndServe(api.config.Server.GetAddr(), nil)) -} - -type home struct { - base string -} - -func getAttribute(n *html.Node, attributeName string) string { - for _, attr := range n.Attr { - if attr.Key == attributeName { - return attr.Val - } - } - return "" -} - -func updateLinks(n *html.Node) { - if n.Type == html.ElementNode { - if n.Data == "a" || n.Data == "img" || (n.Data == "link" && getAttribute(n, "rel") == "stylesheet") { - updateHrefAttribute(n, "href") - updateHrefAttribute(n, "src") - } - } - - for c := n.FirstChild; c != nil; c = c.NextSibling { - updateLinks(c) - } -} - -func updateHrefAttribute(n *html.Node, attributeName string) { - if hrefAttr := findAttribute(n, attributeName); hrefAttr != nil { - href := hrefAttr.Val - if href != "" && !strings.HasPrefix(href, "http") { - // Update the href attribute value by adding the "/dev/" prefix - hrefAttr.Val = "/preview-build" + href - } - } -} - -func findAttribute(n *html.Node, attributeName string) *html.Attribute { - for i := range n.Attr { - if n.Attr[i].Key == attributeName { - return &n.Attr[i] - } - } - return nil -} - -func GetFileContentType(ouput *os.File) (string, error) { - buf := make([]byte, 512) - _, err := ouput.Read(buf) - if err != nil { - return "", err - } - contentType := http.DetectContentType(buf) - if contentType == "text/plain; charset=utf-8" && filepath.Ext(ouput.Name()) == ".svg" { - contentType = "image/svg+xml; charset=utf-8" - } else if contentType == "text/plain; charset=utf-8" && filepath.Ext(ouput.Name()) == ".css" { - contentType = "text/css; charset=utf-8" - } - ouput.Seek(0, 0) - return contentType, nil -} - -func IsHtml(constentType string) bool { - return strings.Contains(constentType, "text/html") -} - -func (h *home) ServeHTTP(w http.ResponseWriter, r *http.Request) { - data := strings.Replace(r.URL.Path, "/preview-build", "", -1) - data = path.Join(h.base, data) - fileInfo, err := os.Stat(data) - if err != nil { - return - } - if fileInfo.IsDir() { - data = path.Join(data, "index.html") - } - file, err := os.Open(data) - if err != nil { - return - } - contentType, _ := GetFileContentType(file) - if IsHtml(contentType) { - doc, err := html.Parse(file) - if err != nil { - fmt.Println(err) - } - updateLinks(doc) - html.Render(w, doc) - } else { - w.Header().Set("Content-Type", contentType) - io.Copy(w, file) - } -} diff --git a/backend/api/settings.go b/backend/api/settings.go deleted file mode 100644 index ae56dba..0000000 --- a/backend/api/settings.go +++ /dev/null @@ -1,74 +0,0 @@ -package api - -import ( - "encoding/json" - "net/http" - "os" - - "github.com/robrotheram/gogallery/backend/config" -) - -type Stats struct { - Photos int - Albums int - Rubish int -} - -func (api *GoGalleryAPI) statsHandler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - stats := Stats{0, 0, 0} - stats.Photos = len(api.db.Pictures.GetAll()) - stats.Albums = len(api.db.Albums.GetAll()) - files, _ := os.ReadDir(config.Config.Gallery.Basepath + "/rubish") - stats.Rubish = len(files) - json.NewEncoder(w).Encode(stats) -} - -func (api *GoGalleryAPI) getProfileInfo(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(api.config.About) -} - -func (api *GoGalleryAPI) setProfileInfo(w http.ResponseWriter, r *http.Request) { - var about = config.AboutConfiguration{} - _ = json.NewDecoder(r.Body).Decode(&about) - about.Save() - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(api.config.About) -} - -func (api *GoGalleryAPI) getGallerySettings(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(api.config.Gallery) -} - -func (api *GoGalleryAPI) getDeploymentSettings(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(api.config.Deploy) -} - -func (api *GoGalleryAPI) getPublicGallerySettings(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - config := map[string]string{ - "name": api.config.Gallery.Name, - } - json.NewEncoder(w).Encode(config) -} - -func (api *GoGalleryAPI) setGallerySettings(w http.ResponseWriter, r *http.Request) { - var gallery = config.GalleryConfiguration{} - _ = json.NewDecoder(r.Body).Decode(&gallery) - gallery.Save() - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(api.config.Gallery) -} - -func (api *GoGalleryAPI) setDeploymentSettings(w http.ResponseWriter, r *http.Request) { - var deploy = config.DeployConfig{} - _ = json.NewDecoder(r.Body).Decode(&deploy) - deploy.Save() - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(api.config.Deploy) -} diff --git a/backend/api/spaHandler.go b/backend/api/spaHandler.go deleted file mode 100644 index e5e78b2..0000000 --- a/backend/api/spaHandler.go +++ /dev/null @@ -1,50 +0,0 @@ -package api - -import ( - "net/http" - "os" - "path/filepath" -) - -// spaHandler implements the http.Handler interface, so we can use it -// to respond to HTTP requests. The path to the static directory and -// path to the index file within that static directory are used to -// serve the SPA in the given static directory. -type SPAHandler struct { - StaticPath string - IndexPath string -} - -// ServeHTTP inspects the URL path to locate a file within the static dir -// on the SPA handler. If a file is found, it will be served. If not, the -// file located at the index path on the SPA handler will be served. This -// is suitable behavior for serving an SPA (single page application). -func (h SPAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // get the absolute path to prevent directory traversal - path, err := filepath.Abs(r.URL.Path) - if err != nil { - // if we failed to get the absolute path respond with a 400 bad request - // and stop - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - // prepend the path with the path to the static directory - path = filepath.Join(h.StaticPath, path) - - // check whether a file exists at the given path - _, err = os.Stat(path) - if os.IsNotExist(err) { - // file does not exist, serve index.html - http.ServeFile(w, r, filepath.Join(h.StaticPath, h.IndexPath)) - return - } else if err != nil { - // if we got an error (that wasn't that the file doesn't exist) stating the - // file, return a 500 internal server error and stop - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - // otherwise, use http.FileServer to serve the static dir - http.FileServer(http.Dir(h.StaticPath)).ServeHTTP(w, r) -} diff --git a/backend/api/tasks.go b/backend/api/tasks.go deleted file mode 100644 index e2db2c3..0000000 --- a/backend/api/tasks.go +++ /dev/null @@ -1,91 +0,0 @@ -package api - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore/models" - "github.com/robrotheram/gogallery/backend/deploy" - "github.com/robrotheram/gogallery/backend/pipeline" -) - -type backup struct { - Albums []models.Album `json:"albums"` - Pictures []models.Picture `json:"pictures"` - Config config.Configuration `json:"config"` -} - -func (api *GoGalleryAPI) purgeTaskHandler(w http.ResponseWriter, r *http.Request) { - stat := api.monitor.NewTask("Delete Site", 0) - go func() { - stat.Start() - pipeline.NewRenderPipeline(&api.config.Gallery, api.db, api.monitor).DeleteSite() - stat.End() - }() - fmt.Fprintf(w, "Deleted Site") -} - -func (api *GoGalleryAPI) getTasks(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(api.monitor.GetTasks()) -} - -func (api *GoGalleryAPI) rescanTaskHandler(w http.ResponseWriter, r *http.Request) { - stat := api.monitor.NewTask("Rescan", 0) - go func() { - stat.Start() - api.db.ScanPath(api.config.Gallery.Basepath) - stat.End() - }() - fmt.Fprintf(w, "rescan task started") -} - -func (api *GoGalleryAPI) buildTaskHandler(w http.ResponseWriter, r *http.Request) { - go pipeline.NewRenderPipeline(&api.config.Gallery, api.db, api.monitor).BuildSite() - fmt.Fprintf(w, "Build task started") -} - -func (api *GoGalleryAPI) deployTaskHandler(w http.ResponseWriter, r *http.Request) { - go deploy.DeploySite(*api.config, api.monitor.NewTask("netify deploy", 0)) - fmt.Fprintf(w, "Deploy task started") -} - -func (api *GoGalleryAPI) uploadTaskHandler(w http.ResponseWriter, r *http.Request) { - bk := backup{} - r.ParseMultipartForm(32 << 20) - file, _, err := r.FormFile("file") - if err != nil { - fmt.Println(err) - return - } - defer file.Close() - buf := bytes.NewBuffer(nil) - if _, err := io.Copy(buf, file); err != nil { - fmt.Println(err) - return - } - json.Unmarshal(buf.Bytes(), &bk) - for _, p := range bk.Pictures { - api.db.Pictures.Save(&p) - } - for _, a := range bk.Albums { - api.db.Albums.Save(&a) - } - bk.Config.About.Save() - bk.Config.Gallery.Save() -} - -func (api *GoGalleryAPI) backupTaskHandler(w http.ResponseWriter, r *http.Request) { - bk := backup{} - bk.Albums = api.db.Albums.GetAll() - bk.Pictures = api.db.Pictures.GetAll() - bk.Config = *api.config - - w.Header().Set("Content-Disposition", "attachment; filename=Gallery-Backup.json") - w.Header().Set("Content-Type", r.Header.Get("Content-Type")) - json.NewEncoder(w).Encode(bk) -} diff --git a/backend/api/upload.go b/backend/api/upload.go deleted file mode 100644 index 35a33ec..0000000 --- a/backend/api/upload.go +++ /dev/null @@ -1,100 +0,0 @@ -package api - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - "strings" - "time" - - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/datastore/models" -) - -type UploadCollection struct { - Album string `json:"album"` - Photos []string `json:"photos"` -} - -func (api *GoGalleryAPI) uploadHandler(w http.ResponseWriter, r *http.Request) { - var uploadCollection UploadCollection - _ = json.NewDecoder(r.Body).Decode(&uploadCollection) - - album := api.db.Albums.FindByID(uploadCollection.Album) - for _, photo := range uploadCollection.Photos { - albumPath := fmt.Sprintf("%s/%s", album.ParenetPath, album.Name) - newPath := fmt.Sprintf("%s/%s", albumPath, photo) - oldPath := fmt.Sprintf("./temp/%s", config.GetMD5Hash(photo)) - err := datastore.MoveFile(oldPath, newPath) - if err == nil { - picName := strings.TrimSuffix(photo, filepath.Ext(photo)) - p := models.Picture{ - Id: config.GetMD5Hash(newPath), - Name: picName, - Path: newPath, - Album: album.Id, - Ext: filepath.Ext(newPath), - Exif: models.Exif{}, - RootPath: api.config.Gallery.Basepath, - Meta: models.PictureMeta{ - PostedToIG: false, - Visibility: "PUBLIC", - DateAdded: time.Now(), - DateModified: time.Now()}} - p.CreateExif() - api.db.Pictures.Save(&p) - } - } -} - -func (api *GoGalleryAPI) uploadFileHandler(w http.ResponseWriter, r *http.Request) { - fmt.Println("File Upload Endpoint Hit") - //photoID := mux.Vars(r)["id"] - - // Parse our multipart form, 10 << 20 specifies a maximum - // upload of 10 MB files. - r.ParseMultipartForm(10 << 20) - // FormFile returns the first file for the given key `myFile` - // it also returns the FileHeader so we can get the Filename, - // the Header and the size of the file - file, handler, err := r.FormFile("file") - if err != nil { - fmt.Println("Error Retrieving the File") - fmt.Println(err) - return - } - defer file.Close() - fmt.Printf("Uploaded File: %+v\n", handler.Filename) - fmt.Printf("File Size: %+v\n", handler.Size) - fmt.Printf("MIME Header: %+v\n", handler.Header) - - // Create a temporary file within our temp-images directory that follows - // a particular naming pattern - - if _, err := os.Stat("temp"); os.IsNotExist(err) { - os.Mkdir("temp", 0755) - } - - tfile, err := os.OpenFile("./temp/"+config.GetMD5Hash(handler.Filename), os.O_WRONLY|os.O_CREATE, 0666) - if err != nil { - fmt.Println(err) - return - } - defer tfile.Close() - - // read all of the contents of our uploaded file into a - // byte array - fileBytes, err := io.ReadAll(file) - if err != nil { - fmt.Println(err) - return - } - // write this byte array to our temporary file - tfile.Write(fileBytes) - // return that we have successfully uploaded our file! - fmt.Fprintf(w, "Successfully Uploaded File\n") -} diff --git a/backend/cmd/dasboard.go b/backend/cmd/dasboard.go deleted file mode 100644 index 670b49e..0000000 --- a/backend/cmd/dasboard.go +++ /dev/null @@ -1,42 +0,0 @@ -package cmd - -import ( - "github.com/robrotheram/gogallery/backend/api" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/embeds" - "github.com/spf13/cobra" - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func init() { - rootCmd.AddCommand(dashboadCMD) -} - -var dashboadCMD = &cobra.Command{ - Use: "dashboard", - Short: "Launch UI", - Long: "Launch UI", - Run: func(cmd *cobra.Command, args []string) { - LaunchDashboard() - }, -} - -func LaunchDashboard() error { - config := config.LoadConfig() - db := datastore.Open(config.Gallery.Basepath) - defer db.Close() - config.Server.Port = "8800" - go api.NewGoGalleryAPI(config, db).DashboardAPI() - - return wails.Run(&options.App{ - Title: "gogallery", - Width: 1024, - Height: 768, - MinWidth: 800, - Assets: &embeds.DashboardFS, - // EnableDefaultContextMenu: true, - BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, - }) -} diff --git a/backend/cmd/docs.go b/backend/cmd/docs.go deleted file mode 100644 index 0a38fe5..0000000 --- a/backend/cmd/docs.go +++ /dev/null @@ -1,26 +0,0 @@ -package cmd - -import ( - "fmt" - "os" - - "github.com/spf13/cobra" - "github.com/spf13/cobra/doc" -) - -func init() { - rootCmd.AddCommand(docCMD) -} - -var docCMD = &cobra.Command{ - Use: "docs", - Short: "Generate CLI documentation", - Long: "Generate CLI documentation", - Run: func(cmd *cobra.Command, args []string) { - os.MkdirAll("./docs/cli", os.ModePerm) - err := doc.GenMarkdownTree(rootCmd, "./docs/cli") - if err != nil { - fmt.Println(err) - } - }, -} diff --git a/backend/cmd/init.go b/backend/cmd/init.go deleted file mode 100644 index 4c96c25..0000000 --- a/backend/cmd/init.go +++ /dev/null @@ -1,33 +0,0 @@ -package cmd - -import ( - "github.com/k0kubun/pp/v3" - "github.com/manifoldco/promptui" - "github.com/robrotheram/gogallery/backend/config" - "github.com/spf13/cobra" -) - -func init() { - rootCmd.AddCommand(initCMD) -} - -var initCMD = &cobra.Command{ - Use: "init", - Short: "Create site", - Long: "Create site", - Run: func(cmd *cobra.Command, args []string) { - config := config.LoadConfig() - config.PromptSiteName() - config.PromptGalleryBasePath() - config.PromptGalleryDest() - config.PromptGalleryTheme() - - pp.Print(config) - prompt := promptui.Prompt{ - Label: "Is info correct", - IsConfirm: true, - } - prompt.Run() - config.Save() - }, -} diff --git a/backend/cmd/serve.go b/backend/cmd/serve.go deleted file mode 100644 index 9a80c62..0000000 --- a/backend/cmd/serve.go +++ /dev/null @@ -1,73 +0,0 @@ -package cmd - -import ( - "fmt" - "log" - "os" - "os/exec" - "runtime" - - "github.com/robrotheram/gogallery/backend/api" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/spf13/cobra" -) - -func init() { - rootCmd.AddCommand(serveCMD) - rootCmd.AddCommand(devCMD) -} - -var serveCMD = &cobra.Command{ - Use: "serve", - Short: "Serve static site", - Long: "Serve static site", - Run: func(cmd *cobra.Command, args []string) { - - config := config.LoadConfig() - db := datastore.Open(config.Gallery.Basepath) - defer db.Close() - - _, err := os.Stat(config.Gallery.Destpath) - if os.IsNotExist(err) { - log.Fatalf("Sorry it does not look like the site has been built, there is nothing at: \"%s\". Please check the config ", config.Gallery.Destpath) - return - } - - if len(args) == 1 { - config.Server.Port = ":" + args[0] - } - openbrowser(fmt.Sprintf("http://%s", config.Server.GetLocalAddr())) - api.NewGoGalleryAPI(config, db).Serve() - }, -} - -var devCMD = &cobra.Command{ - Use: "dev", - Run: func(cmd *cobra.Command, args []string) { - config := config.LoadConfig() - db := datastore.Open(config.Gallery.Basepath) - defer db.Close() - // db.ScanPath(config.Gallery.Basepath) - config.Server.Port = "8800" - api.NewGoGalleryAPI(config, db).DashboardAPI() - }, -} - -func openbrowser(url string) { - var err error - switch runtime.GOOS { - case "linux": - err = exec.Command("xdg-open", url).Start() - case "windows": - err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() - case "darwin": - err = exec.Command("open", url).Start() - default: - err = fmt.Errorf("unsupported platform") - } - if err != nil { - log.Fatal(err) - } - -} diff --git a/backend/config/GereatePassword.go b/backend/config/GereatePassword.go deleted file mode 100644 index d31879f..0000000 --- a/backend/config/GereatePassword.go +++ /dev/null @@ -1,24 +0,0 @@ -package config - -import ( - "math/rand" - "time" -) - -const charset = "abcdefghijklmnopqrstuvwxyz" + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -var seededRand *rand.Rand = rand.New( - rand.NewSource(time.Now().UnixNano())) - -func StringWithCharset(length int, charset string) string { - b := make([]byte, length) - for i := range b { - b[i] = charset[seededRand.Intn(len(charset))] - } - return string(b) -} - -func RandomPassword(length int) string { - return StringWithCharset(length, charset) -} diff --git a/backend/datastore/AlbumStructure.go b/backend/datastore/AlbumStructure.go deleted file mode 100644 index b449bc0..0000000 --- a/backend/datastore/AlbumStructure.go +++ /dev/null @@ -1,97 +0,0 @@ -package datastore - -import ( - "path" - "sort" - "strings" - - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore/models" -) - -type AlbumStrcure = map[string]models.Album - -func Sort(as AlbumStrcure) AlbumStrcure { - keys := make([]string, 0, len(as)) - for k := range as { - keys = append(keys, k) - } - data := make(map[string]models.Album) - sort.Strings(keys) - for _, k := range keys { - data[k] = as[k] - } - return data -} - -func SliceToTree(albms []models.Album, basepath string) AlbumStrcure { - newalbms := make(map[string]models.Album) - sort.Slice(albms, func(i, j int) bool { - return albms[i].ParenetPath < albms[j].ParenetPath - }) - for _, ab := range albms { - if ab.ParenetPath == basepath { - ab.ParenetPath = "" - newalbms[ab.Name] = ab - } - } - for _, ab := range albms { - if (ab.ParenetPath != basepath) && (ab.Id != config.GetMD5Hash(basepath)) { - s := strings.Split(strings.Replace(ab.ParenetPath, basepath, "", 1), "/") - copy(s, s[1:]) - s = s[:len(s)-1] - pth := basepath - var alb models.Album - for i, p := range s { - if i == 0 { - alb = newalbms[p] - } else { - alb = alb.Children[p] - } - pth = path.Join(pth, p) - if i == len(s)-1 { - if alb.Children != nil { - ab.ParenetPath = "" - alb.Children[ab.Name] = ab - } - } - } - } - } - return newalbms -} - -func FindInAlbumStrcureById(ab models.Album, id string) models.Album { - if ab.Id == id { - return ab - } - for _, v := range ab.Children { - a := FindInAlbumStrcureById(v, id) - if a.Id == id { - return a - } - } - return models.Album{} -} - -func GetAlbumFromStructure(as AlbumStrcure, id string) models.Album { - album := models.Album{} - for _, v := range as { - album = FindInAlbumStrcureById(v, id) - if album.Id != "" { - return album - } - } - return album -} - -func (a *AlumnCollectioins) GetAlbumStructure(config config.GalleryConfiguration) AlbumStrcure { - albums := []models.Album{} - for _, alb := range a.GetAll() { - if !IsAlbumInBlacklist(alb.Name) { - albums = append(albums, alb) - } - } - newalbms := SliceToTree(albums, config.Basepath) - return newalbms -} diff --git a/backend/datastore/albumCollection.go b/backend/datastore/albumCollection.go deleted file mode 100644 index fddc38d..0000000 --- a/backend/datastore/albumCollection.go +++ /dev/null @@ -1,83 +0,0 @@ -package datastore - -import ( - "fmt" - "os" - "path/filepath" - "sync" - - "github.com/asdine/storm" - "github.com/robrotheram/gogallery/backend/datastore/models" -) - -type AlumnCollectioins struct { - DB *storm.DB - sync.Mutex -} - -func (a *AlumnCollectioins) Save(pic *models.Album) { - a.DB.Save(pic) -} - -func (a *AlumnCollectioins) Update(alb *models.Album) { - album := a.FindByID(alb.Id) - album.Update(*alb) - a.Save(&album) -} - -func (a *AlumnCollectioins) GetAll() []models.Album { - a.Lock() - defer a.Unlock() - - var albums []models.Album - a.DB.All(&albums) - return albums -} - -func (a *AlumnCollectioins) FindByID(id string) models.Album { - var alb models.Album - a.DB.One("Id", id, &alb) - return alb -} - -func (a *AlumnCollectioins) FindManyFeild(id string) []models.Album { - var alb []models.Album - a.FindByFeild("id", id, alb) - return alb -} - -func (a *AlumnCollectioins) FindByFeild(key string, val any, to any) { - a.Lock() - defer a.Unlock() - a.DB.Find(key, val, &to) -} - -func (a *AlumnCollectioins) UpdateField(id string, key string, val any) { - a.Lock() - defer a.Unlock() - a.DB.UpdateField(&models.Album{Id: id}, key, val) -} - -func (a *AlumnCollectioins) Delete(albums models.Album) error { - a.Lock() - defer a.Unlock() - - err := os.Remove(albums.Path) - if err != nil { - return err - } - a.DB.DeleteStruct(&albums) - return nil -} - -func (a *AlumnCollectioins) MovePictureToAlbum(picture *models.Picture, newAlbum string) error { - album := a.FindByID(newAlbum) - newName := fmt.Sprintf("%s/%s/%s%s", album.ParenetPath, album.Name, picture.Name, filepath.Ext(picture.Path)) - err := os.Rename(picture.Path, newName) - if err != nil { - return err - } - picture.Path = newName - picture.Album = newAlbum - return nil -} diff --git a/backend/datastore/datastore.go b/backend/datastore/datastore.go deleted file mode 100644 index 447f34e..0000000 --- a/backend/datastore/datastore.go +++ /dev/null @@ -1,121 +0,0 @@ -package datastore - -import ( - "fmt" - "log" - "os" - "path/filepath" - "strings" - "time" - - "github.com/asdine/storm" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore/models" -) - -type CRUD interface { - Save(any) - Delete(any) - Update(any) - GetById(string) []any - GetByField(string string) []any - GetAll() []any -} - -type DataStore struct { - db *storm.DB - Pictures *PictureCollection - Albums *AlumnCollectioins - ImageCache *ImageCache -} - -func Open(dbPath string) *DataStore { - os.MkdirAll(dbPath, os.ModePerm) - path := filepath.Join(dbPath, "gogallery.db") - db, err := storm.Open(path) - if err != nil { - log.Fatalf("Unable to open db at: %s \n Error: %v", path, err) - } - return &DataStore{ - db: db, - Pictures: &PictureCollection{DB: db}, - Albums: &AlumnCollectioins{DB: db}, - ImageCache: NewImageCache(), - } -} - -func (d *DataStore) Close() { - d.db.Close() -} - -func (d *DataStore) RestDB() { - d.db.Drop(models.Picture{}) - d.db.Drop(models.Album{}) -} - -func (d *DataStore) ScanPath(path string) error { - rubishPath := fmt.Sprintf("%s/%s", gConfig.Basepath, "rubish") - if _, err := os.Stat(rubishPath); os.IsNotExist(err) { - os.Mkdir(rubishPath, 0755) - } - if !contains(gConfig.AlbumBlacklist, "rubish") { - gConfig.AlbumBlacklist = append(gConfig.AlbumBlacklist, "rubish") - } - - log.Println("Scanning Folders at:" + path) - IsScanning = true - - absRoot, err := filepath.Abs(path) - if err != nil { - return err - } - walkFunc := func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if checkEXT(path) && !info.IsDir() { - albumName := filepath.Base(filepath.Dir(path)) - picName := strings.TrimSuffix(info.Name(), filepath.Ext(info.Name())) - if !IsAlbumInBlacklist(albumName) && !IsPictureInBlacklist(picName) { - p := models.Picture{ - Id: config.GetMD5Hash(path), - Name: picName, - Path: path, - Ext: filepath.Ext(path), - Album: config.GetMD5Hash(filepath.Dir(path)), - AlbumName: albumName, - Exif: models.Exif{}, - RootPath: gConfig.Basepath, - Meta: models.PictureMeta{ - PostedToIG: false, - Visibility: "PUBLIC", - DateAdded: time.Now(), - DateModified: time.Now()}} - p.CreateExif() - if !d.Pictures.Exist(p.Id) { - d.Pictures.Save(&p) - } - d.Albums.UpdateField(config.GetMD5Hash(filepath.Dir(path)), "ProfileID", p.Id) - } - } - - if info.IsDir() { - if !IsAlbumInBlacklist(info.Name()) { - if filepath.Base(filepath.Dir(path)) != gConfig.Basepath { - info := fileInfoFromInterface(info) - d.Albums.Update(&models.Album{ - Id: config.GetMD5Hash(path), - Name: info.Name, - ModTime: info.ModTime, - Parent: filepath.Base(filepath.Dir(path)), - ParenetPath: (filepath.Dir(path))}) - } - } - } - return nil - } - err = filepath.Walk(absRoot, walkFunc) - log.Println("Scanning Complete") - IsScanning = false - return err -} diff --git a/backend/datastore/image_cache.go b/backend/datastore/image_cache.go deleted file mode 100644 index 2d60593..0000000 --- a/backend/datastore/image_cache.go +++ /dev/null @@ -1,26 +0,0 @@ -package datastore - -import ( - "fmt" - "os" - "path" -) - -type ImageCache struct { - base string -} - -func NewImageCache() *ImageCache { - path := path.Join(os.TempDir(), "gogallery") - os.MkdirAll(path, 0755) - return &ImageCache{ - base: path, - } -} - -func (ic *ImageCache) Get(name string, size string) (*os.File, error) { - return os.Open(path.Join(ic.base, fmt.Sprintf("%s-%s.webp", name, size))) -} -func (ic *ImageCache) Writer(name string, size string) (*os.File, error) { - return os.Create(path.Join(ic.base, fmt.Sprintf("%s-%s.webp", name, size))) -} diff --git a/backend/datastore/models/Album.go b/backend/datastore/models/Album.go deleted file mode 100644 index b78ae11..0000000 --- a/backend/datastore/models/Album.go +++ /dev/null @@ -1,40 +0,0 @@ -package models - -import "time" - -type Album struct { - Id string `json:"id" storm:"id"` - Name string `json:"name"` - ModTime time.Time `json:"mod_time"` - Parent string `json:"parent"` - ParenetPath string `json:"parentPath,omitempty"` - Path string `json:"path,omitempty"` - ProfileID string `json:"profile_image"` - Images []Picture `json:"images"` - Children AlbumStrcure `json:"children"` - GPS GPS `json:"gps"` -} - -type AlbumStrcure = map[string]Album - -func (a *Album) Update(alb Album) { - - if a.Name != alb.Name && alb.Name != "" { - a.Name = alb.Name - } - if a.Parent != alb.Parent && alb.Parent != "" { - a.Parent = alb.Parent - } - if a.ParenetPath != alb.ParenetPath && alb.ParenetPath != "" { - a.ParenetPath = alb.ParenetPath - } - if (a.ProfileID != alb.ProfileID) && (alb.ProfileID != "") { - a.ProfileID = alb.ProfileID - } - if a.Children == nil { - a.Children = make(map[string]Album) - } - if a.Id == "" { - a.Id = alb.Id - } -} diff --git a/backend/datastore/models/Exif.go b/backend/datastore/models/Exif.go deleted file mode 100644 index 1bea23a..0000000 --- a/backend/datastore/models/Exif.go +++ /dev/null @@ -1,51 +0,0 @@ -package models - -import ( - "os" - "strings" - "time" - - "github.com/dsoprea/go-exif/v3" -) - -type Exif struct { - FStop string `json:"f_stop"` - FocalLength string `json:"focal_length"` - ShutterSpeed string `json:"shutter_speed"` - ISO string `json:"iso"` - Dimension string `json:"dimension"` - Camera string `json:"camera"` - LensModel string `json:"lens_model"` - DateTaken time.Time `json:"date_taken"` - GPS GPS `json:"gps"` -} - -type GPS struct { - Lat float64 `json:"latitude"` - Lng float64 `json:"longitude"` -} - -func GetRawExif(path string) ([]byte, error) { - source, err := os.Open(path) - if err != nil { - return nil, err - } - defer func() { - _ = source.Close() - }() - return exif.SearchAndExtractExifWithReader(source) -} - -func GetExifTags(rawExif []byte) map[string]string { - - opt := exif.ScanOptions{} - entries, _, _ := exif.GetFlatExifData(rawExif, &opt) - - data := make(map[string]string) - for _, entry := range entries { - if entry.TagName != "" && entry.Formatted != "" { - data[entry.TagName] = strings.Split(entry.FormattedFirst, "\x00")[0] - } - } - return data -} diff --git a/backend/datastore/models/Picture.go b/backend/datastore/models/Picture.go deleted file mode 100644 index c3b7615..0000000 --- a/backend/datastore/models/Picture.go +++ /dev/null @@ -1,83 +0,0 @@ -package models - -import ( - "fmt" - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "os" - "sort" - "time" - - "github.com/evanoberholster/imagemeta" - // Blind import for image.Decode - _ "golang.org/x/image/webp" -) - -type Picture struct { - Id string `json:"id" storm:"id"` - Name string `json:"name"` - Caption string `json:"caption"` - Path string `json:"path,omitempty"` - Ext string `json:"extention,omitempty"` - FormatTime string `json:"format_time"` - Album string `json:"album"` - AlbumName string `json:"album_name"` - Exif Exif `json:"exif"` - Meta PictureMeta `json:"meta,omitempty"` - RootPath string `json:"root_path,omitempty"` -} - -type PictureMeta struct { - PostedToIG bool `json:"posted_to_IG,omitempty"` - Visibility string `json:"visibility,omitempty"` - DateAdded time.Time `json:"date_added,omitempty"` - DateModified time.Time `json:"date_modified,omitempty"` -} - -func (u *Picture) CreateExif() error { - f, _ := os.Open(u.Path) - defer f.Close() - u.Exif = Exif{} - - meta, err := imagemeta.Decode(f) - if err != nil { - return err - } - - u.Exif.FStop = meta.FNumber.String() - u.Exif.FocalLength = meta.FocalLength.String() - u.Exif.ShutterSpeed = meta.ExposureTime.String() - u.Exif.ISO = fmt.Sprintf("%d", meta.ISOSpeed) - u.Exif.Dimension = fmt.Sprintf("%d/%d", meta.ImageWidth, meta.ImageHeight) - u.Exif.Camera = meta.CameraMake.String() - u.Exif.LensModel = meta.LensModel - u.Exif.DateTaken = meta.CreateDate() - u.Exif.GPS = GPS{ - Lat: meta.GPS.Latitude(), - Lng: meta.GPS.Latitude(), - } - - return nil -} - -func SortByTime(p []Picture) []Picture { - sort.Slice(p, func(i, j int) bool { - return p[i].Exif.DateTaken.Sub(p[j].Exif.DateTaken) > 0 - }) - return p -} - -func (p *Picture) Load() (image.Image, error) { - f, err := os.Open(p.Path) - if err != nil { - return nil, err - } - defer f.Close() - img, _, err := image.Decode(f) - if err != nil { - return nil, fmt.Errorf("image %s, decode failed: %v", p.Path, err) - } - return img, nil -} diff --git a/backend/datastore/picturesCollection.go b/backend/datastore/picturesCollection.go deleted file mode 100644 index 99b3fda..0000000 --- a/backend/datastore/picturesCollection.go +++ /dev/null @@ -1,97 +0,0 @@ -package datastore - -import ( - "os" - "sync" - - "github.com/asdine/storm" - "github.com/robrotheram/gogallery/backend/datastore/models" -) - -type PictureCollection struct { - DB *storm.DB - sync.Mutex -} - -func (p *PictureCollection) Save(pic *models.Picture) { - p.DB.Save(pic) -} - -func (p *PictureCollection) GetAll() []models.Picture { - p.Lock() - defer p.Unlock() - - var pics []models.Picture - err := p.DB.All(&pics) - if err != nil { - return []models.Picture{} - } - return pics -} - -func (p *PictureCollection) FindByID(id string) models.Picture { - p.Lock() - defer p.Unlock() - var alb models.Picture - p.DB.One("Id", id, &alb) - return alb -} - -func (p *PictureCollection) FindManyFeild(key string, val string) []models.Picture { - var alb []models.Picture - p.DB.Find(key, val, &alb) - return alb -} - -func (p *PictureCollection) Delete(picture models.Picture) error { - p.Lock() - defer p.Unlock() - os.Remove(picture.Path) - p.DB.DeleteStruct(&picture) - return nil -} - -func (p *PictureCollection) Exist(id string) bool { - pic := p.FindByID(id) - return pic.Id != "" -} - -func (p *PictureCollection) GetByAlbumID(id string) []models.Picture { - return models.SortByTime(p.FindManyFeild("Album", id)) -} - -func (p *PictureCollection) GetFilteredPictures(admin bool) []models.Picture { - var filterPics []models.Picture - for _, pic := range p.GetAll() { - if admin { - filterPics = append(filterPics, pic) - } else if !IsAlbumInBlacklist(pic.Album) && pic.Meta.Visibility == "PUBLIC" { - cleanpic := models.Picture{ - Id: pic.Id, - Name: pic.Name, - Caption: pic.Caption, - Album: pic.Album, - AlbumName: pic.AlbumName, - FormatTime: pic.Exif.DateTaken.Format("01-02-2006 15:04:05"), - Exif: pic.Exif, - Meta: pic.Meta, - Ext: pic.Ext, - } - filterPics = append(filterPics, cleanpic) - } - } - return models.SortByTime(filterPics) -} - -func (p *PictureCollection) GetLatestAlbum() string { - pics := p.GetFilteredPictures(false) - latests := pics[0].Exif.DateTaken - album := pics[0].Album - for _, p := range pics { - if p.Exif.DateTaken.After(latests) { - latests = p.Exif.DateTaken - album = p.Album - } - } - return album -} diff --git a/backend/embeds/embeds.go b/backend/embeds/embeds.go deleted file mode 100644 index e9a7da5..0000000 --- a/backend/embeds/embeds.go +++ /dev/null @@ -1,111 +0,0 @@ -package embeds - -import ( - "archive/tar" - "compress/gzip" - "embed" - "io" - "io/fs" - "os" - "path/filepath" - "strings" -) - -var DashboardFS embed.FS -var ThemeFS embed.FS - -func CopyTheme(templatePath string) { - os.MkdirAll(templatePath, os.ModePerm) - fs.WalkDir(ThemeFS, ".", func(path string, d fs.DirEntry, err error) error { - newPath := filepath.Join(templatePath, path) - if d.IsDir() { - os.MkdirAll(newPath, os.ModePerm) - } else { - file, _ := ThemeFS.ReadFile(path) - os.WriteFile(newPath, file, os.ModePerm) - } - return nil - }) - -} - -func CopyThemeAssets(templatePath string) { - os.MkdirAll(templatePath, os.ModePerm) - root := "themes/eastnor/assets" - fs.WalkDir(ThemeFS, root, func(path string, d fs.DirEntry, err error) error { - newPath := filepath.Join(templatePath, strings.Replace(path, root, "", -1)) - if d.IsDir() { - os.MkdirAll(newPath, os.ModePerm) - } else { - file, _ := ThemeFS.ReadFile(path) - os.WriteFile(newPath, file, os.ModePerm) - } - return nil - }) - -} - -func Untar(dst string, r io.Reader) error { - - gzr, err := gzip.NewReader(r) - if err != nil { - return err - } - defer gzr.Close() - - tr := tar.NewReader(gzr) - - for { - header, err := tr.Next() - - switch { - - // if no more files are found return - case err == io.EOF: - return nil - - // return any other error - case err != nil: - return err - - // if the header is nil, just skip it (not sure how this happens) - case header == nil: - continue - } - - // the target location where the dir/file should be created - target := filepath.Join(dst, header.Name) - - // the following switch could also be done using fi.Mode(), not sure if there - // a benefit of using one vs. the other. - // fi := header.FileInfo() - - // check the file type - switch header.Typeflag { - - // if its a dir and it doesn't exist create it - case tar.TypeDir: - if _, err := os.Stat(target); err != nil { - if err := os.MkdirAll(target, 0755); err != nil { - return err - } - } - - // if it's a file create it - case tar.TypeReg: - f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)) - if err != nil { - return err - } - - // copy over contents - if _, err := io.Copy(f, tr); err != nil { - return err - } - - // manually close here after each file operation; defering would cause each file close - // to wait until all operations have completed. - f.Close() - } - } -} diff --git a/backend/monitor/cmd_monitor .go b/backend/monitor/cmd_monitor .go deleted file mode 100644 index f583def..0000000 --- a/backend/monitor/cmd_monitor .go +++ /dev/null @@ -1,74 +0,0 @@ -package monitor - -import ( - "fmt" - "sort" - "time" - - "github.com/gosuri/uiprogress" - "github.com/gosuri/uiprogress/util/strutil" -) - -type CmdMonitor struct { - Tasks map[string]*ProgressStats - Bars map[string]*uiprogress.Bar - done chan bool - ticker *time.Ticker -} - -func NewCMDMonitor() *CmdMonitor { - return &CmdMonitor{ - Tasks: make(map[string]*ProgressStats), - Bars: make(map[string]*uiprogress.Bar), - done: make(chan bool), - } -} - -func (t *CmdMonitor) NewTask(name string, total int) *ProgressStats { - stat := NewProgressStats(name, total) - t.Tasks[name] = stat - t.Bars[name] = uiprogress.AddBar(total).AppendCompleted() - t.Bars[name].PrependFunc(func(b *uiprogress.Bar) string { - return strutil.Resize(name, 20) - }) - t.Bars[name].AppendFunc(func(b *uiprogress.Bar) string { - return fmt.Sprintf("%d/%d", uint(b.Current()), uint(b.Total)) - }) - return stat -} - -func (t *CmdMonitor) GetTasks() []ProgressStats { - keys := make([]string, 0, len(t.Tasks)) - values := make([]ProgressStats, 0, len(t.Tasks)) - for k := range t.Tasks { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - values = append(values, *t.Tasks[k]) - } - return values -} -func (t *CmdMonitor) StartUpdater() { - t.ticker = time.NewTicker(1 * time.Second) - go func() { - for { - select { - case <-t.done: - t.UpdateProgress() - return - case <-t.ticker.C: - t.UpdateProgress() - } - } - }() -} -func (t *CmdMonitor) StopUpdater() { - t.ticker.Stop() - t.done <- true -} -func (t *CmdMonitor) UpdateProgress() { - for name, stat := range t.Tasks { - t.Bars[name].Set(stat.Proceesed) - } -} diff --git a/backend/monitor/monitor.go b/backend/monitor/monitor.go deleted file mode 100644 index 3a6f167..0000000 --- a/backend/monitor/monitor.go +++ /dev/null @@ -1,6 +0,0 @@ -package monitor - -type Monitor interface { - NewTask(name string, total int) *ProgressStats - GetTasks() []ProgressStats -} diff --git a/backend/pipeline/AlbumPagePipeline.go b/backend/pipeline/AlbumPagePipeline.go deleted file mode 100644 index 51bd496..0000000 --- a/backend/pipeline/AlbumPagePipeline.go +++ /dev/null @@ -1,34 +0,0 @@ -package pipeline - -import ( - "bufio" - "fmt" - "os" - "path/filepath" - - "github.com/gosimple/slug" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/datastore/models" - templateengine "github.com/robrotheram/gogallery/backend/templateEngine" -) - -func renderAlbumTemplate(db *datastore.DataStore) func(alb models.Album) error { - return func(alb models.Album) error { - alb_path := filepath.Join(albumDir, slug.Make(alb.Id)) - os.MkdirAll(alb_path, os.ModePerm) - - page := templateengine.NewPage(nil, db.Pictures.GetLatestAlbum()) - albums := db.Albums.GetAlbumStructure(page.Settings) - album := datastore.GetAlbumFromStructure(albums, alb.Id) - - f, _ := os.Create(filepath.Join(alb_path, "index.html")) - w := bufio.NewWriter(f) - page.Album = album - page.Images = db.Pictures.GetByAlbumID(alb.Id) - page.Picture = templateengine.NewPagePicture(db.Pictures.FindByID(alb.ProfileID)) - page.SEO.Description = fmt.Sprintf("Album: %s", alb.Name) - templateengine.Templates.RenderPage(w, templateengine.CollectionTemplate, page) - f.Close() - return nil - } -} diff --git a/backend/pipeline/ImagePipeline.go b/backend/pipeline/ImagePipeline.go deleted file mode 100644 index 7264b9a..0000000 --- a/backend/pipeline/ImagePipeline.go +++ /dev/null @@ -1,71 +0,0 @@ -package pipeline - -import ( - "image" - "io" - "os" - "path/filepath" - - "github.com/bep/gowebp/libwebp" - "github.com/bep/gowebp/libwebp/webpoptions" - "github.com/disintegration/imaging" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore/models" - templateengine "github.com/robrotheram/gogallery/backend/templateEngine" -) - -func resize(base image.Image, width int, height int) image.Image { - if width == 0 && height == 0 { - return imaging.Resize(base, int(float64(base.Bounds().Dx())), 0, imaging.Lanczos) - } - return imaging.Resize(base, width, height, imaging.Lanczos) -} - -func ProcessImage(src image.Image, size int, w io.Writer) { - resized := resize(src, size, 0) - libwebp.Encode(w, resized, webpoptions.EncodingOptions{ - Quality: 100, - EncodingPreset: webpoptions.EncodingPresetDefault, - UseSharpYuv: true, - }) -} - -func ImageGenV2(pic models.Picture) error { - destPath := filepath.Join(imgDir, pic.Id) - os.MkdirAll(destPath, os.ModePerm) - - toRender := map[string]int{} - for key, size := range templateengine.ImageSizes { - cachePath := filepath.Join(destPath, key+".webp") - if !templateengine.FileExists(cachePath) { - toRender[key] = size - } - } - - if config.Config.Gallery.UseOriginal { - orginalPath := filepath.Join(destPath, "original"+pic.Ext) - if !templateengine.FileExists(orginalPath) { - templateengine.Copy(pic.Path, orginalPath) - } - } - - if len(toRender) == 0 { - return nil - } - - src, err := pic.Load() - if err != nil { - return err - } - - for key, size := range toRender { - cachePath := filepath.Join(destPath, key+".webp") - fo, err := os.Create(cachePath) - if err != nil { - continue - } - defer fo.Close() - ProcessImage(src, size, fo) - } - return nil -} diff --git a/backend/pipeline/IndexPagePipeluine.go b/backend/pipeline/IndexPagePipeluine.go deleted file mode 100644 index 2e2aa3d..0000000 --- a/backend/pipeline/IndexPagePipeluine.go +++ /dev/null @@ -1,106 +0,0 @@ -package pipeline - -import ( - "bufio" - "fmt" - "os" - "path/filepath" - - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/datastore/models" - "github.com/robrotheram/gogallery/backend/embeds" - templateengine "github.com/robrotheram/gogallery/backend/templateEngine" -) - -func renderIndex(db *datastore.DataStore, config *config.GalleryConfiguration) { - imagesPerPage := 16 //defautl - if config.ImagesPerPage > 0 { - imagesPerPage = config.ImagesPerPage - } - latestAlbumID := db.Pictures.GetLatestAlbum() - indexPage := templateengine.NewPage(nil, latestAlbumID) - images := db.Pictures.GetFilteredPictures(false) - pages := paginateImages(images, imagesPerPage) - albums := datastore.Sort(db.Albums.GetAlbumStructure(indexPage.Settings)) - - indexPage.Images = pages[0] - indexPage.Albums = albums - if len(images) > 0 { - indexPage.SEO.SetImage(images[0]) - } - - f, _ := os.Create(filepath.Join(root, "index.html")) - w := bufio.NewWriter(f) - templateengine.Templates.RenderPage(w, templateengine.HomeTemplate, indexPage) - renderPages(pages, latestAlbumID, albums) - w.Flush() - f.Close() - - f, _ = os.Create(filepath.Join(root, "manifest.json")) - w = bufio.NewWriter(f) - templateengine.ManifestWriter(w, config) - w.Flush() - f.Close() - - f, _ = os.Create(filepath.Join(root, "service-worker.js")) - w = bufio.NewWriter(f) - templateengine.ServiceWorkerWriter(w) - w.Flush() - f.Close() -} - -func paginateImages(slice []models.Picture, chunkSize int) [][]models.Picture { - var chunks [][]models.Picture - for i := 0; i < len(slice); i += chunkSize { - end := i + chunkSize - if end > len(slice) { - end = len(slice) - } - chunks = append(chunks, slice[i:end]) - } - return chunks -} - -func renderPages(pages [][]models.Picture, albumID string, albums models.AlbumStrcure) { - pagesPath := filepath.Join(root, "page") - os.MkdirAll(pagesPath, os.ModePerm) - for page, pageImages := range pages { - pagePath := filepath.Join(pagesPath, fmt.Sprint(page)) - os.MkdirAll(pagePath, os.ModePerm) - page := templateengine.NewPage(nil, albumID) - page.Images = pageImages - page.Albums = albums - if len(pageImages) > 0 { - page.SEO.SetImage(pageImages[0]) - } - f, _ := os.Create(filepath.Join(pagePath, "index.html")) - w := bufio.NewWriter(f) - templateengine.Templates.RenderPage(w, templateengine.PaginationTemplate, page) - w.Flush() - f.Close() - } -} - -func renderAlbums(db *datastore.DataStore) { - os.MkdirAll(albumsDir, os.ModePerm) - f, _ := os.Create(filepath.Join(albumsDir, "index.html")) - w := bufio.NewWriter(f) - page := templateengine.NewPage(nil, db.Pictures.GetLatestAlbum()) - page.Albums = datastore.Sort(db.Albums.GetAlbumStructure(page.Settings)) - templateengine.Templates.RenderPage(w, templateengine.AlbumTemplate, page) - w.Flush() - f.Close() -} - -func build() { - err := templateengine.Templates.Load(config.Config.Gallery.Theme) - if err != nil { - fmt.Println(err) - } - if config.Config.Gallery.Theme == "default" { - embeds.CopyThemeAssets(filepath.Join(root, "assets")) - } else { - templateengine.Dir(filepath.Join(config.Config.Gallery.Theme, "assets"), filepath.Join(root, "assets")) - } -} diff --git a/backend/pipeline/PhotoPagePipeline.go b/backend/pipeline/PhotoPagePipeline.go deleted file mode 100644 index 6e9e0c9..0000000 --- a/backend/pipeline/PhotoPagePipeline.go +++ /dev/null @@ -1,26 +0,0 @@ -package pipeline - -import ( - "os" - "path/filepath" - - "github.com/gosimple/slug" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/datastore/models" - templateengine "github.com/robrotheram/gogallery/backend/templateEngine" -) - -func renderPhotoTemplate(db *datastore.DataStore) func(alb models.Picture) error { - return func(pic models.Picture) error { - pic_path := filepath.Join(photoDir, slug.Make(pic.Id)) - os.MkdirAll(pic_path, os.ModePerm) - f, err := os.Create(filepath.Join(pic_path, "index.html")) - if err != nil { - return err - } - latestAlbumId := db.Pictures.GetLatestAlbum() - templateengine.RenderPhoto(f, pic, db.Pictures.GetByAlbumID(pic.Album), templateengine.NewPage(nil, latestAlbumId)) - f.Close() - return nil - } -} diff --git a/backend/pipeline/Render.go b/backend/pipeline/Render.go deleted file mode 100644 index 48e62bc..0000000 --- a/backend/pipeline/Render.go +++ /dev/null @@ -1,69 +0,0 @@ -package pipeline - -import ( - "os" - "path/filepath" - - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/datastore/models" - "github.com/robrotheram/gogallery/backend/monitor" -) - -var root = "" -var imgDir string -var photoDir string -var albumsDir string -var albumDir string - -type RenderPipeline struct { - AlbumRender *BatchProcessing[models.Album] - PageRender *BatchProcessing[models.Picture] - ImageRender *BatchProcessing[models.Picture] - monitor monitor.Monitor - db *datastore.DataStore - config *config.GalleryConfiguration -} - -func NewRenderPipeline(config *config.GalleryConfiguration, db *datastore.DataStore, monitor monitor.Monitor) *RenderPipeline { - root = config.Destpath - imgDir = filepath.Join(root, "img") - photoDir = filepath.Join(root, "photo") - albumsDir = filepath.Join(root, "albums") - albumDir = filepath.Join(root, "album") - - albums := db.Albums.GetAll() - images := db.Pictures.GetAll() - - render := RenderPipeline{ - db: db, - AlbumRender: NewBatchProcessing(renderAlbumTemplate(db), albums, monitor.NewTask("rendering albums", len(albums))), - PageRender: NewBatchProcessing(renderPhotoTemplate(db), images, monitor.NewTask("rendering pages", len(images))), - ImageRender: NewBatchProcessing(ImageGenV2, images, monitor.NewTask("optomizing images", len(images))), - monitor: monitor, - config: config, - } - return &render -} - -func (r *RenderPipeline) CreateDir() { - os.MkdirAll(root, os.ModePerm) - os.MkdirAll(imgDir, os.ModePerm) - os.MkdirAll(photoDir, os.ModePerm) - os.MkdirAll(albumDir, os.ModePerm) -} - -func (r *RenderPipeline) DeleteSite() { - os.RemoveAll(root) -} - -func (r *RenderPipeline) BuildSite() { - db := r.db - r.CreateDir() - build() - renderIndex(db, r.config) - renderAlbums(db) - r.AlbumRender.Run() - r.PageRender.Run() - r.ImageRender.Run() -} diff --git a/backend/pipeline/batch.go b/backend/pipeline/batch.go deleted file mode 100644 index d4fd246..0000000 --- a/backend/pipeline/batch.go +++ /dev/null @@ -1,63 +0,0 @@ -package pipeline - -import ( - "runtime" - "sync" - - "github.com/robrotheram/gogallery/backend/monitor" -) - -type BatchProcessing[T any] struct { - items []T - stat *monitor.ProgressStats - work func(T) error - chunkSize int -} - -func chunkSlice[T any](slice []T, nchunks int) [][]T { - var chunks [][]T - chunkSize := (len(slice) / nchunks) - for i := 0; i < len(slice); i += chunkSize { - end := i + chunkSize - if end > len(slice) { - end = len(slice) - } - chunks = append(chunks, slice[i:end]) - } - return chunks -} - -func (batch *BatchProcessing[T]) Run() { - batch.stat.Start() - var wg sync.WaitGroup - chunks := chunkSlice(batch.items, batch.chunkSize) - for _, chunk := range chunks { - wg.Add(1) - go batch.processing(chunk, &wg) - } - wg.Wait() - batch.stat.End() -} - -func (poc *BatchProcessing[T]) processing(batch []T, wg *sync.WaitGroup) { - for _, pic := range batch { - poc.work(pic) - poc.stat.Update() - } - wg.Done() -} - -func NewBatchProcessing[T any](processing func(T) error, items []T, stat *monitor.ProgressStats) *BatchProcessing[T] { - stat.Total = len(items) - //save 1 core for the system - chunsize := runtime.NumCPU() - 1 - if chunsize < 1 { - chunsize = 1 - } - return &BatchProcessing[T]{ - work: processing, - chunkSize: chunsize, - items: items, - stat: stat, - } -} diff --git a/cmd/benchmark.go b/cmd/benchmark.go new file mode 100644 index 0000000..bdef853 --- /dev/null +++ b/cmd/benchmark.go @@ -0,0 +1,93 @@ +package cmd + +import ( + "gogallery/pkg/config" + "gogallery/pkg/datastore" + "gogallery/pkg/monitor" + "log" + "os" + "runtime/pprof" + "time" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(benchmark) +} + +var benchmark = &cobra.Command{ + Use: "benchmark", + RunE: func(cmd *cobra.Command, args []string) error { + cpuFile, _ := os.Create("cpu.prof") + pprof.StartCPUProfile(cpuFile) + defer pprof.StopCPUProfile() + + memFile, _ := os.Create("mem.prof") + pprof.WriteHeapProfile(memFile) + defer memFile.Close() + + benchmarkScanPath() + return nil + }, +} + +func benchmarkScanPath() { + + start := time.Now() + config := config.LoadConfig() + config.Validate() + db, err := datastore.Open(config.Gallery.Basepath, monitor.NewCMDMonitor()) + if err != nil { + log.Fatalf("Failed to open database: %v", err) + } + + if err := db.ScanPath(config.Gallery.Basepath); err != nil { + log.Fatalf("Error scanning path: %v", err) + } + + elapsed := time.Since(start) + log.Printf("Scan completed in %s", elapsed) +} + +func benchmarkImage() { + var totalTime time.Duration + p := datastore.Picture{ + Id: "benchmark", + Path: "/home/robert/Pictures/gallery/pictures/bergen/20250511_0010.jpg", + } + start := time.Now() + p.CreateExif() + + elapsed := time.Since(start) + totalTime += elapsed + log.Printf("Benchmark completed in %s", elapsed) + + // src, err := p.Load() + // if err != nil { + // log.Fatalf("Error loading benchmark image: %v", err) + // } + // destPath := "benchmark.webp" + // sizes := templateengine.ImageSizes + // for _, size := range sizes { + // if _, err := os.Stat(destPath); err == nil { + // if err := os.Remove(destPath); err != nil { + // log.Fatalf("Error deleting existing file: %v", err) + // } + // } + // fo, err := os.Create(destPath) + // if err != nil { + // log.Fatalf("Error creating file: %v", err) + // } + // defer fo.Close() + + // start := time.Now() + + // pipeline.ProcessImage(src, size.ImgWidth, fo) + + // elapsed := time.Since(start) + // totalTime += elapsed + // log.Printf("Benchmark completed in %s", elapsed) + // } + log.Printf("Total benchmark time for all sizes: %s", totalTime) +} diff --git a/backend/cmd/build.go b/cmd/build.go similarity index 62% rename from backend/cmd/build.go rename to cmd/build.go index 263cd3d..4064124 100644 --- a/backend/cmd/build.go +++ b/cmd/build.go @@ -1,13 +1,13 @@ package cmd import ( + "gogallery/pkg/config" + "gogallery/pkg/datastore" + "gogallery/pkg/monitor" + "gogallery/pkg/pipeline" "log" "github.com/gosuri/uiprogress" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/datastore" - "github.com/robrotheram/gogallery/backend/monitor" - "github.com/robrotheram/gogallery/backend/pipeline" "github.com/spf13/cobra" ) @@ -23,15 +23,17 @@ var buildCMD = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { config := config.LoadConfig() config.Validate() - db := datastore.Open(config.Gallery.Basepath) - defer db.Close() + db, err := datastore.Open(config.Gallery.Basepath, cmdMonitor) + if err != nil { + log.Fatalf("Failed to open database: %v", err) + } + cmdMonitor.StartUpdater() db.ScanPath(config.Gallery.Basepath) log.Println("Building Site at: " + config.Gallery.Destpath) uiprogress.Start() - render := pipeline.NewRenderPipeline(&config.Gallery, db, cmdMonitor) - cmdMonitor.StartUpdater() + render := pipeline.NewRenderPipeline(&config.Gallery, db) + render.BuildSite() - cmdMonitor.StopUpdater() log.Println("Building Complete") return nil }, diff --git a/backend/cmd/deploy.go b/cmd/deploy.go similarity index 74% rename from backend/cmd/deploy.go rename to cmd/deploy.go index 8eba990..a724f8c 100644 --- a/backend/cmd/deploy.go +++ b/cmd/deploy.go @@ -2,10 +2,10 @@ package cmd import ( "fmt" + "gogallery/pkg/config" + "gogallery/pkg/deploy" + "gogallery/pkg/monitor" - "github.com/robrotheram/gogallery/backend/config" - "github.com/robrotheram/gogallery/backend/deploy" - "github.com/robrotheram/gogallery/backend/monitor" "github.com/spf13/cobra" ) diff --git a/backend/cmd/extract.go b/cmd/extract.go similarity index 90% rename from backend/cmd/extract.go rename to cmd/extract.go index 6323d74..b5ca133 100644 --- a/backend/cmd/extract.go +++ b/cmd/extract.go @@ -2,8 +2,8 @@ package cmd import ( "fmt" + "gogallery/pkg/embeds" - "github.com/robrotheram/gogallery/backend/embeds" "github.com/spf13/cobra" ) diff --git a/backend/cmd/root.go b/cmd/root.go similarity index 97% rename from backend/cmd/root.go rename to cmd/root.go index a88ed3e..d387de9 100644 --- a/backend/cmd/root.go +++ b/cmd/root.go @@ -7,6 +7,7 @@ package cmd import ( "fmt" + "gogallery/pkg/ui" "os" homedir "github.com/mitchellh/go-homedir" @@ -24,7 +25,7 @@ var rootCmd = &cobra.Command{ Long: `Generates a full static site that you can host all use the local provided server`, RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { - return LaunchDashboard() + return ui.App() } return cmd.Help() }, diff --git a/cmd/serve.go b/cmd/serve.go new file mode 100644 index 0000000..21b0ce4 --- /dev/null +++ b/cmd/serve.go @@ -0,0 +1,37 @@ +package cmd + +import ( + "gogallery/pkg/config" + "gogallery/pkg/datastore" + "gogallery/pkg/monitor" + "gogallery/pkg/preview" + "log" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(serveCMD) +} + +var serveCMD = &cobra.Command{ + Use: "serve", + Short: "Serve static site", + Long: "Serve static site", + Run: func(cmd *cobra.Command, args []string) { + config := config.LoadConfig() + db, err := datastore.Open(config.Gallery.Basepath, monitor.NewCMDMonitor()) + if err != nil { + log.Fatalf("Failed to open database: %v", err) + } + + server := preview.NewServer(db) + if err := server.Start(); err != nil { + log.Fatalf("Server failed to start: %v", err) + } + // Print the actual address after the server has started and acquired a port + log.Printf("Starting Preview Server http://%s", server.Addr()) + // Wait for the server goroutine to exit (block until server stops) + select {} + }, +} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index ca5a88a..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,21 +0,0 @@ -version: "2" - -networks: - gogallery: - external: false - -services: - server: - image: ghcr.io/robrotheram/gogallery:master - restart: always - networks: - - gogallery - volumes: - - "./config.yml:/app/config.yml" - - "/path/to/gallery:/app/pictures" - ports: - - 8085:80 - environment: - GLLRY_GALLERY_BASEPATH: "/app/pictures" - - diff --git a/docs/album.png b/docs/album.png new file mode 100644 index 0000000..8c70081 Binary files /dev/null and b/docs/album.png differ diff --git a/docs/cli/gogallery.md b/docs/cli/gogallery.md deleted file mode 100644 index df300ad..0000000 --- a/docs/cli/gogallery.md +++ /dev/null @@ -1,31 +0,0 @@ -## gogallery - -Photo Gallery Static Site generator - -### Synopsis - -Generates a full static site that you can host all use the local provided server - -``` -gogallery [flags] -``` - -### Options - -``` - --config string config file (default is $HOME/.gogallery.yaml) - -h, --help help for gogallery -``` - -### SEE ALSO - -* [gogallery build](gogallery_build.md) - Build static site -* [gogallery completion](gogallery_completion.md) - Generate the autocompletion script for the specified shell -* [gogallery dashboard](gogallery_dashboard.md) - Launch UI -* [gogallery deploy](gogallery_deploy.md) - Deploy static site -* [gogallery docs](gogallery_docs.md) - Generate CLI documentation -* [gogallery init](gogallery_init.md) - Create site -* [gogallery serve](gogallery_serve.md) - Serve static site -* [gogallery template](gogallery_template.md) - Extract template to directory - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_build.md b/docs/cli/gogallery_build.md deleted file mode 100644 index d0bf4d2..0000000 --- a/docs/cli/gogallery_build.md +++ /dev/null @@ -1,29 +0,0 @@ -## gogallery build - -Build static site - -### Synopsis - -Build static site - -``` -gogallery build [flags] -``` - -### Options - -``` - -h, --help help for build -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_completion.md b/docs/cli/gogallery_completion.md deleted file mode 100644 index 51fdafc..0000000 --- a/docs/cli/gogallery_completion.md +++ /dev/null @@ -1,31 +0,0 @@ -## gogallery completion - -Generate the autocompletion script for the specified shell - -### Synopsis - -Generate the autocompletion script for gogallery for the specified shell. -See each sub-command's help for details on how to use the generated script. - - -### Options - -``` - -h, --help help for completion -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator -* [gogallery completion bash](gogallery_completion_bash.md) - Generate the autocompletion script for bash -* [gogallery completion fish](gogallery_completion_fish.md) - Generate the autocompletion script for fish -* [gogallery completion powershell](gogallery_completion_powershell.md) - Generate the autocompletion script for powershell -* [gogallery completion zsh](gogallery_completion_zsh.md) - Generate the autocompletion script for zsh - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_completion_bash.md b/docs/cli/gogallery_completion_bash.md deleted file mode 100644 index ebb0297..0000000 --- a/docs/cli/gogallery_completion_bash.md +++ /dev/null @@ -1,50 +0,0 @@ -## gogallery completion bash - -Generate the autocompletion script for bash - -### Synopsis - -Generate the autocompletion script for the bash shell. - -This script depends on the 'bash-completion' package. -If it is not installed already, you can install it via your OS's package manager. - -To load completions in your current shell session: - - source <(gogallery completion bash) - -To load completions for every new session, execute once: - -#### Linux: - - gogallery completion bash > /etc/bash_completion.d/gogallery - -#### macOS: - - gogallery completion bash > $(brew --prefix)/etc/bash_completion.d/gogallery - -You will need to start a new shell for this setup to take effect. - - -``` -gogallery completion bash -``` - -### Options - -``` - -h, --help help for bash - --no-descriptions disable completion descriptions -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery completion](gogallery_completion.md) - Generate the autocompletion script for the specified shell - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_completion_fish.md b/docs/cli/gogallery_completion_fish.md deleted file mode 100644 index 3adcd70..0000000 --- a/docs/cli/gogallery_completion_fish.md +++ /dev/null @@ -1,41 +0,0 @@ -## gogallery completion fish - -Generate the autocompletion script for fish - -### Synopsis - -Generate the autocompletion script for the fish shell. - -To load completions in your current shell session: - - gogallery completion fish | source - -To load completions for every new session, execute once: - - gogallery completion fish > ~/.config/fish/completions/gogallery.fish - -You will need to start a new shell for this setup to take effect. - - -``` -gogallery completion fish [flags] -``` - -### Options - -``` - -h, --help help for fish - --no-descriptions disable completion descriptions -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery completion](gogallery_completion.md) - Generate the autocompletion script for the specified shell - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_completion_powershell.md b/docs/cli/gogallery_completion_powershell.md deleted file mode 100644 index c57de5b..0000000 --- a/docs/cli/gogallery_completion_powershell.md +++ /dev/null @@ -1,38 +0,0 @@ -## gogallery completion powershell - -Generate the autocompletion script for powershell - -### Synopsis - -Generate the autocompletion script for powershell. - -To load completions in your current shell session: - - gogallery completion powershell | Out-String | Invoke-Expression - -To load completions for every new session, add the output of the above command -to your powershell profile. - - -``` -gogallery completion powershell [flags] -``` - -### Options - -``` - -h, --help help for powershell - --no-descriptions disable completion descriptions -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery completion](gogallery_completion.md) - Generate the autocompletion script for the specified shell - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_completion_zsh.md b/docs/cli/gogallery_completion_zsh.md deleted file mode 100644 index 53dfde1..0000000 --- a/docs/cli/gogallery_completion_zsh.md +++ /dev/null @@ -1,52 +0,0 @@ -## gogallery completion zsh - -Generate the autocompletion script for zsh - -### Synopsis - -Generate the autocompletion script for the zsh shell. - -If shell completion is not already enabled in your environment you will need -to enable it. You can execute the following once: - - echo "autoload -U compinit; compinit" >> ~/.zshrc - -To load completions in your current shell session: - - source <(gogallery completion zsh); compdef _gogallery gogallery - -To load completions for every new session, execute once: - -#### Linux: - - gogallery completion zsh > "${fpath[1]}/_gogallery" - -#### macOS: - - gogallery completion zsh > $(brew --prefix)/share/zsh/site-functions/_gogallery - -You will need to start a new shell for this setup to take effect. - - -``` -gogallery completion zsh [flags] -``` - -### Options - -``` - -h, --help help for zsh - --no-descriptions disable completion descriptions -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery completion](gogallery_completion.md) - Generate the autocompletion script for the specified shell - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_dashboard.md b/docs/cli/gogallery_dashboard.md deleted file mode 100644 index de43ea4..0000000 --- a/docs/cli/gogallery_dashboard.md +++ /dev/null @@ -1,29 +0,0 @@ -## gogallery dashboard - -Launch UI - -### Synopsis - -Launch UI - -``` -gogallery dashboard [flags] -``` - -### Options - -``` - -h, --help help for dashboard -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_deploy.md b/docs/cli/gogallery_deploy.md deleted file mode 100644 index f8dc47e..0000000 --- a/docs/cli/gogallery_deploy.md +++ /dev/null @@ -1,29 +0,0 @@ -## gogallery deploy - -Deploy static site - -### Synopsis - -Deploy static site - -``` -gogallery deploy [flags] -``` - -### Options - -``` - -h, --help help for deploy -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_docs.md b/docs/cli/gogallery_docs.md deleted file mode 100644 index 149f702..0000000 --- a/docs/cli/gogallery_docs.md +++ /dev/null @@ -1,29 +0,0 @@ -## gogallery docs - -Generate CLI documentation - -### Synopsis - -Generate CLI documentation - -``` -gogallery docs [flags] -``` - -### Options - -``` - -h, --help help for docs -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_init.md b/docs/cli/gogallery_init.md deleted file mode 100644 index 9ba4772..0000000 --- a/docs/cli/gogallery_init.md +++ /dev/null @@ -1,29 +0,0 @@ -## gogallery init - -Create site - -### Synopsis - -Create site - -``` -gogallery init [flags] -``` - -### Options - -``` - -h, --help help for init -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_serve.md b/docs/cli/gogallery_serve.md deleted file mode 100644 index e2dd0a8..0000000 --- a/docs/cli/gogallery_serve.md +++ /dev/null @@ -1,29 +0,0 @@ -## gogallery serve - -Serve static site - -### Synopsis - -Serve static site - -``` -gogallery serve [flags] -``` - -### Options - -``` - -h, --help help for serve -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/cli/gogallery_template.md b/docs/cli/gogallery_template.md deleted file mode 100644 index 3c152a0..0000000 --- a/docs/cli/gogallery_template.md +++ /dev/null @@ -1,29 +0,0 @@ -## gogallery template - -Extract template to directory - -### Synopsis - -Extract the internal template to any directory - -``` -gogallery template [flags] -``` - -### Options - -``` - -h, --help help for template -``` - -### Options inherited from parent commands - -``` - --config string config file (default is $HOME/.gogallery.yaml) -``` - -### SEE ALSO - -* [gogallery](gogallery.md) - Photo Gallery Static Site generator - -###### Auto generated by spf13/cobra on 11-Sep-2022 diff --git a/docs/dashboard1.jpg b/docs/dashboard1.jpg deleted file mode 100644 index 3ae7b4f..0000000 Binary files a/docs/dashboard1.jpg and /dev/null differ diff --git a/docs/dashboard2.png b/docs/dashboard2.png deleted file mode 100644 index 5d38a62..0000000 Binary files a/docs/dashboard2.png and /dev/null differ diff --git a/docs/dashboard3.png b/docs/dashboard3.png deleted file mode 100644 index 6031cdd..0000000 Binary files a/docs/dashboard3.png and /dev/null differ diff --git a/docs/homepage.png b/docs/homepage.png new file mode 100644 index 0000000..baca826 Binary files /dev/null and b/docs/homepage.png differ diff --git a/docs/img1.jpg b/docs/img1.jpg deleted file mode 100644 index 6897c3f..0000000 Binary files a/docs/img1.jpg and /dev/null differ diff --git a/docs/img2.jpg b/docs/img2.jpg deleted file mode 100644 index e30c51d..0000000 Binary files a/docs/img2.jpg and /dev/null differ diff --git a/docs/settings.png b/docs/settings.png new file mode 100644 index 0000000..dad15cc Binary files /dev/null and b/docs/settings.png differ diff --git a/docs/sidebar.png b/docs/sidebar.png new file mode 100644 index 0000000..e9192ae Binary files /dev/null and b/docs/sidebar.png differ diff --git a/docs/tasks.png b/docs/tasks.png new file mode 100644 index 0000000..22ef7ec Binary files /dev/null and b/docs/tasks.png differ diff --git a/docs/website-collection.png b/docs/website-collection.png new file mode 100644 index 0000000..52eb78a Binary files /dev/null and b/docs/website-collection.png differ diff --git a/docs/website-home.png b/docs/website-home.png new file mode 100644 index 0000000..8171bf7 Binary files /dev/null and b/docs/website-home.png differ diff --git a/docs/website-photo.png b/docs/website-photo.png new file mode 100644 index 0000000..b309907 Binary files /dev/null and b/docs/website-photo.png differ diff --git a/frontend/favicon.ico b/frontend/favicon.ico deleted file mode 100644 index 0c67ce2..0000000 Binary files a/frontend/favicon.ico and /dev/null differ diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index 232e787..0000000 --- a/frontend/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - gogallery - - - - - - -
- - - - diff --git a/frontend/package-lock.json b/frontend/package-lock.json deleted file mode 100644 index cf67551..0000000 --- a/frontend/package-lock.json +++ /dev/null @@ -1,3612 +0,0 @@ -{ - "name": "frontend", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "frontend", - "version": "0.0.0", - "dependencies": { - "antd": "^5.22.1", - "axios": "^1.6.3", - "leaflet": "^1.9.1", - "mapbox-gl": "^2.10.0", - "maplibre-gl": "^2.4.0", - "moment": "^2.29.4", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-lazy-load-image-component": "^1.5.5", - "react-leaflet": "^4.0.2", - "react-map-gl": "^7.0.19", - "react-redux": "^8.0.2", - "react-router-dom": "^6.3.0", - "redux": "^4.2.0", - "redux-logger": "^3.0.6", - "redux-thunk": "^2.4.1" - }, - "devDependencies": { - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@vitejs/plugin-react": "^4.2.1", - "vite": "^5.1.5" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@ant-design/colors": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz", - "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==", - "license": "MIT", - "dependencies": { - "@ctrl/tinycolor": "^3.6.1" - } - }, - "node_modules/@ant-design/cssinjs": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.22.0.tgz", - "integrity": "sha512-W9XSFeRPR0mAN3OuxfuS/xhENCYKf+8s+QyNNER0FSWoK9OpISTag6CCweg6lq0hASQ/2Vcza0Z8/kGivCP0Ng==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.1", - "@emotion/hash": "^0.8.0", - "@emotion/unitless": "^0.7.5", - "classnames": "^2.3.1", - "csstype": "^3.1.3", - "rc-util": "^5.35.0", - "stylis": "^4.3.4" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/@ant-design/cssinjs-utils": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.1.tgz", - "integrity": "sha512-2HAiyGGGnM0es40SxdszeQAU5iWp41wBIInq+ONTCKjlSKOrzQfnw4JDtB8IBmqE6tQaEKwmzTP2LGdt5DSwYQ==", - "license": "MIT", - "dependencies": { - "@ant-design/cssinjs": "^1.21.0", - "@babel/runtime": "^7.23.2", - "rc-util": "^5.38.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@ant-design/fast-color": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", - "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.24.7" - }, - "engines": { - "node": ">=8.x" - } - }, - "node_modules/@ant-design/icons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.1.tgz", - "integrity": "sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==", - "license": "MIT", - "dependencies": { - "@ant-design/colors": "^7.0.0", - "@ant-design/icons-svg": "^4.4.0", - "@babel/runtime": "^7.24.8", - "classnames": "^2.2.6", - "rc-util": "^5.31.1" - }, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/@ant-design/icons-svg": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", - "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==", - "license": "MIT" - }, - "node_modules/@ant-design/react-slick": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", - "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.4", - "classnames": "^2.2.5", - "json2mq": "^0.2.0", - "resize-observer-polyfill": "^1.5.1", - "throttle-debounce": "^5.0.0" - }, - "peerDependencies": { - "react": ">=16.9.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", - "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", - "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", - "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", - "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", - "license": "MIT" - }, - "node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", - "license": "MIT" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@mapbox/geojson-rewind": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", - "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "license": "ISC", - "dependencies": { - "get-stream": "^6.0.1", - "minimist": "^1.2.6" - }, - "bin": { - "geojson-rewind": "geojson-rewind" - } - }, - "node_modules/@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@mapbox/mapbox-gl-supported": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz", - "integrity": "sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@mapbox/point-geometry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", - "license": "ISC" - }, - "node_modules/@mapbox/tiny-sdf": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", - "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==", - "license": "BSD-2-Clause" - }, - "node_modules/@mapbox/unitbezier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", - "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", - "license": "BSD-2-Clause" - }, - "node_modules/@mapbox/vector-tile": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", - "license": "BSD-3-Clause", - "dependencies": { - "@mapbox/point-geometry": "~0.1.0" - } - }, - "node_modules/@mapbox/whoots-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", - "license": "ISC", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "19.3.3", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.3.tgz", - "integrity": "sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==", - "license": "ISC", - "dependencies": { - "@mapbox/jsonlint-lines-primitives": "~2.0.2", - "@mapbox/unitbezier": "^0.0.1", - "json-stringify-pretty-compact": "^3.0.0", - "minimist": "^1.2.8", - "rw": "^1.3.3", - "sort-object": "^3.0.3" - }, - "bin": { - "gl-style-format": "dist/gl-style-format.mjs", - "gl-style-migrate": "dist/gl-style-migrate.mjs", - "gl-style-validate": "dist/gl-style-validate.mjs" - } - }, - "node_modules/@rc-component/async-validator": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", - "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.24.4" - }, - "engines": { - "node": ">=14.x" - } - }, - "node_modules/@rc-component/color-picker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz", - "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==", - "license": "MIT", - "dependencies": { - "@ant-design/fast-color": "^2.0.6", - "@babel/runtime": "^7.23.6", - "classnames": "^2.2.6", - "rc-util": "^5.38.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/context": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", - "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/mini-decimal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", - "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.0" - }, - "engines": { - "node": ">=8.x" - } - }, - "node_modules/@rc-component/mutate-observer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", - "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.0", - "classnames": "^2.3.2", - "rc-util": "^5.24.4" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/portal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", - "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.0", - "classnames": "^2.3.2", - "rc-util": "^5.24.4" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/qrcode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz", - "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.24.7", - "classnames": "^2.3.2", - "rc-util": "^5.38.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/tour": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz", - "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.0", - "@rc-component/portal": "^1.0.0-9", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.3.2", - "rc-util": "^5.24.4" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/trigger": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.5.tgz", - "integrity": "sha512-F1EJ4KjFpGAHAjuKvOyZB/6IZDkVx0bHl0M4fQM5wXcmm7lgTgVSSnR3bXwdmS6jOJGHOqfDxIJW3WUvwMIXhQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@rc-component/portal": "^1.1.0", - "classnames": "^2.3.2", - "rc-motion": "^2.0.0", - "rc-resize-observer": "^1.3.1", - "rc-util": "^5.38.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@react-leaflet/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", - "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", - "license": "Hippocratic-2.1", - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@remix-run/router": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", - "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", - "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", - "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", - "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", - "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", - "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", - "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", - "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", - "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", - "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", - "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", - "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", - "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", - "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", - "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", - "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", - "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", - "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", - "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", - "license": "MIT" - }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", - "license": "MIT", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "node_modules/@types/mapbox__point-geometry": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", - "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", - "license": "MIT" - }, - "node_modules/@types/mapbox__vector-tile": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", - "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", - "license": "MIT", - "dependencies": { - "@types/geojson": "*", - "@types/mapbox__point-geometry": "*", - "@types/pbf": "*" - } - }, - "node_modules/@types/mapbox-gl": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.4.1.tgz", - "integrity": "sha512-NsGKKtgW93B+UaLPti6B7NwlxYlES5DpV5Gzj9F75rK5ALKsqSk15CiEHbOnTr09RGbr6ZYiCdI+59NNNcAImg==", - "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/pbf": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", - "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", - "license": "MIT" - }, - "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", - "license": "MIT" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", - "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.26.0", - "@babel/plugin-transform-react-jsx-self": "^7.25.9", - "@babel/plugin-transform-react-jsx-source": "^7.25.9", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" - } - }, - "node_modules/antd": { - "version": "5.22.2", - "resolved": "https://registry.npmjs.org/antd/-/antd-5.22.2.tgz", - "integrity": "sha512-vihhiJbm9VG3d6boUeD1q2MXMax+qBrXhgqCEC+45v8iGUF6m4Ct+lFiCW4oWaN3EABOsbVA6Svy3Rj/QkQFKw==", - "license": "MIT", - "dependencies": { - "@ant-design/colors": "^7.1.0", - "@ant-design/cssinjs": "^1.21.1", - "@ant-design/cssinjs-utils": "^1.1.1", - "@ant-design/icons": "^5.5.1", - "@ant-design/react-slick": "~1.1.2", - "@babel/runtime": "^7.25.7", - "@ctrl/tinycolor": "^3.6.1", - "@rc-component/color-picker": "~2.0.1", - "@rc-component/mutate-observer": "^1.1.0", - "@rc-component/qrcode": "~1.0.0", - "@rc-component/tour": "~1.15.1", - "@rc-component/trigger": "^2.2.5", - "classnames": "^2.5.1", - "copy-to-clipboard": "^3.3.3", - "dayjs": "^1.11.11", - "rc-cascader": "~3.30.0", - "rc-checkbox": "~3.3.0", - "rc-collapse": "~3.9.0", - "rc-dialog": "~9.6.0", - "rc-drawer": "~7.2.0", - "rc-dropdown": "~4.2.0", - "rc-field-form": "~2.5.1", - "rc-image": "~7.11.0", - "rc-input": "~1.6.3", - "rc-input-number": "~9.3.0", - "rc-mentions": "~2.17.0", - "rc-menu": "~9.16.0", - "rc-motion": "^2.9.3", - "rc-notification": "~5.6.2", - "rc-pagination": "~4.3.0", - "rc-picker": "~4.8.1", - "rc-progress": "~4.0.0", - "rc-rate": "~2.13.0", - "rc-resize-observer": "^1.4.0", - "rc-segmented": "~2.5.0", - "rc-select": "~14.16.3", - "rc-slider": "~11.1.7", - "rc-steps": "~6.0.1", - "rc-switch": "~4.1.0", - "rc-table": "~7.48.1", - "rc-tabs": "~15.4.0", - "rc-textarea": "~1.8.2", - "rc-tooltip": "~6.2.1", - "rc-tree": "~5.10.1", - "rc-tree-select": "~5.24.4", - "rc-upload": "~4.8.1", - "rc-util": "^5.43.0", - "scroll-into-view-if-needed": "^3.1.0", - "throttle-debounce": "^5.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ant-design" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", - "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bytewise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", - "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==", - "license": "MIT", - "dependencies": { - "bytewise-core": "^1.2.2", - "typewise": "^1.0.3" - } - }, - "node_modules/bytewise-core": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", - "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", - "license": "MIT", - "dependencies": { - "typewise-core": "^1.2" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001684", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", - "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/compute-scroll-into-view": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", - "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==", - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/copy-to-clipboard": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", - "license": "MIT", - "dependencies": { - "toggle-selection": "^1.0.6" - } - }, - "node_modules/csscolorparser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", - "license": "MIT" - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" - }, - "node_modules/dayjs": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", - "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-diff": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", - "integrity": "sha512-yVn6RZmHiGnxRKR9sJb3iVV2XTF1Ghh2DiWRZ3dMnGc43yUdWWF/kX6lQyk3+P84iprfWKU/8zFTrlkvtFm1ug==", - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", - "license": "ISC" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.66", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.66.tgz", - "integrity": "sha512-pI2QF6+i+zjPbqRzJwkMvtvkdI7MjVbSh2g8dlMguDJIXEPw+kwasS1Jl+YGPEBfGVxsVgGUratAKymPdPo2vQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/geojson-vt": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", - "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==", - "license": "ISC" - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gl-matrix": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==", - "license": "MIT" - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "license": "MIT", - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/grid-index": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", - "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", - "license": "ISC" - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-stringify-pretty-compact": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", - "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==", - "license": "MIT" - }, - "node_modules/json2mq": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", - "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", - "license": "MIT", - "dependencies": { - "string-convert": "^0.2.0" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kdbush": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", - "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", - "license": "ISC" - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/leaflet": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", - "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "license": "MIT" - }, - "node_modules/lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/mapbox-gl": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-2.15.0.tgz", - "integrity": "sha512-fjv+aYrd5TIHiL7wRa+W7KjtUqKWziJMZUkK5hm8TvJ3OLeNPx4NmW/DgfYhd/jHej8wWL+QJBDbdMMAKvNC0A==", - "license": "SEE LICENSE IN LICENSE.txt", - "dependencies": { - "@mapbox/geojson-rewind": "^0.5.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^2.0.1", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^2.0.6", - "@mapbox/unitbezier": "^0.0.1", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "csscolorparser": "~1.0.3", - "earcut": "^2.2.4", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.4.3", - "grid-index": "^1.1.0", - "kdbush": "^4.0.1", - "murmurhash-js": "^1.0.0", - "pbf": "^3.2.1", - "potpack": "^2.0.0", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "supercluster": "^8.0.0", - "tinyqueue": "^2.0.3", - "vt-pbf": "^3.1.3" - } - }, - "node_modules/maplibre-gl": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-2.4.0.tgz", - "integrity": "sha512-csNFylzntPmHWidczfgCZpvbTSmhaWvLRj9e1ezUDBEPizGgshgm3ea1T5TCNEEBq0roauu7BPuRZjA3wO4KqA==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@mapbox/geojson-rewind": "^0.5.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^2.0.1", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^2.0.5", - "@mapbox/unitbezier": "^0.0.1", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "@types/geojson": "^7946.0.10", - "@types/mapbox__point-geometry": "^0.1.2", - "@types/mapbox__vector-tile": "^1.3.0", - "@types/pbf": "^3.0.2", - "csscolorparser": "~1.0.3", - "earcut": "^2.2.4", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.4.3", - "global-prefix": "^3.0.0", - "murmurhash-js": "^1.0.0", - "pbf": "^3.2.1", - "potpack": "^1.0.2", - "quickselect": "^2.0.0", - "supercluster": "^7.1.5", - "tinyqueue": "^2.0.3", - "vt-pbf": "^3.1.3" - } - }, - "node_modules/maplibre-gl/node_modules/kdbush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", - "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==", - "license": "ISC" - }, - "node_modules/maplibre-gl/node_modules/potpack": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "license": "ISC" - }, - "node_modules/maplibre-gl/node_modules/supercluster": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", - "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", - "license": "ISC", - "dependencies": { - "kdbush": "^3.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/murmurhash-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", - "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, - "license": "MIT" - }, - "node_modules/pbf": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", - "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", - "license": "BSD-3-Clause", - "dependencies": { - "ieee754": "^1.1.12", - "resolve-protobuf-schema": "^2.1.0" - }, - "bin": { - "pbf": "bin/pbf" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/potpack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", - "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==", - "license": "ISC" - }, - "node_modules/protocol-buffers-schema": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", - "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", - "license": "ISC" - }, - "node_modules/rc-cascader": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.30.0.tgz", - "integrity": "sha512-rrzSbk1Bdqbu+pDwiLCLHu72+lwX9BZ28+JKzoi0DWZ4N29QYFeip8Gctl33QVd2Xg3Rf14D3yAOG76ElJw16w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.25.7", - "classnames": "^2.3.1", - "rc-select": "~14.16.2", - "rc-tree": "~5.10.1", - "rc-util": "^5.43.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-checkbox": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", - "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.3.2", - "rc-util": "^5.25.2" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-collapse": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.9.0.tgz", - "integrity": "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.3.4", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-dialog": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz", - "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/portal": "^1.0.0-8", - "classnames": "^2.2.6", - "rc-motion": "^2.3.0", - "rc-util": "^5.21.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-drawer": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", - "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@rc-component/portal": "^1.1.1", - "classnames": "^2.2.6", - "rc-motion": "^2.6.1", - "rc-util": "^5.38.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-dropdown": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz", - "integrity": "sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.2.6", - "rc-util": "^5.17.0" - }, - "peerDependencies": { - "react": ">=16.11.0", - "react-dom": ">=16.11.0" - } - }, - "node_modules/rc-field-form": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.5.1.tgz", - "integrity": "sha512-33hunXwynQJyeae7LS3hMGTXNeRBjiPyPYgB0824EbmLHiXC1EBGyUwRh6xjLRy9c+en5WARYN0gJz5+JAqwig==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.0", - "@rc-component/async-validator": "^5.0.3", - "rc-util": "^5.32.2" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-image": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz", - "integrity": "sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.2", - "@rc-component/portal": "^1.0.2", - "classnames": "^2.2.6", - "rc-dialog": "~9.6.0", - "rc-motion": "^2.6.2", - "rc-util": "^5.34.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-input": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.3.tgz", - "integrity": "sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-util": "^5.18.1" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/rc-input-number": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.3.0.tgz", - "integrity": "sha512-JQ363ywqRyxwgVxpg2z2kja3CehTpYdqR7emJ/6yJjRdbvo+RvfE83fcpBCIJRq3zLp8SakmEXq60qzWyZ7Usw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/mini-decimal": "^1.0.1", - "classnames": "^2.2.5", - "rc-input": "~1.6.0", - "rc-util": "^5.40.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-mentions": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.17.0.tgz", - "integrity": "sha512-sfHy+qLvc+p8jx8GUsujZWXDOIlIimp6YQz7N5ONQ6bHsa2kyG+BLa5k2wuxgebBbH97is33wxiyq5UkiXRpHA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.22.5", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.2.6", - "rc-input": "~1.6.0", - "rc-menu": "~9.16.0", - "rc-textarea": "~1.8.0", - "rc-util": "^5.34.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-menu": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.16.0.tgz", - "integrity": "sha512-vAL0yqPkmXWk3+YKRkmIR8TYj3RVdEt3ptG2jCJXWNAvQbT0VJJdRyHZ7kG/l1JsZlB+VJq/VcYOo69VR4oD+w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/trigger": "^2.0.0", - "classnames": "2.x", - "rc-motion": "^2.4.3", - "rc-overflow": "^1.3.1", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-motion": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.3.tgz", - "integrity": "sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-util": "^5.43.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-notification": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz", - "integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.9.0", - "rc-util": "^5.20.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-overflow": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", - "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.37.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-pagination": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.3.0.tgz", - "integrity": "sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.3.2", - "rc-util": "^5.38.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-picker": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.8.2.tgz", - "integrity": "sha512-I6Nn4ngkRskSD//rsXDvjlEQ8CzX9kPQrUIb7+qTY49erJaa3/oKJWmi6JIxo/A7gy59phNmPTdhKosAa/NrQQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.24.7", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.2.1", - "rc-overflow": "^1.3.2", - "rc-resize-observer": "^1.4.0", - "rc-util": "^5.43.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "date-fns": ">= 2.x", - "dayjs": ">= 1.x", - "luxon": ">= 3.x", - "moment": ">= 2.x", - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - }, - "peerDependenciesMeta": { - "date-fns": { - "optional": true - }, - "dayjs": { - "optional": true - }, - "luxon": { - "optional": true - }, - "moment": { - "optional": true - } - } - }, - "node_modules/rc-progress": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", - "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.6", - "rc-util": "^5.16.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-rate": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", - "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-util": "^5.0.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-resize-observer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", - "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.20.7", - "classnames": "^2.2.1", - "rc-util": "^5.38.0", - "resize-observer-polyfill": "^1.5.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-segmented": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz", - "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-motion": "^2.4.4", - "rc-util": "^5.17.0" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/rc-select": { - "version": "14.16.3", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.16.3.tgz", - "integrity": "sha512-51+j6s3fJJJXB7E+B6W1hM4Tjzv1B/Decooz9ilgegDBt3ZAth1b/xMwYCTrT5BbG2e53XACQsyDib2+3Ro1fg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/trigger": "^2.1.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-overflow": "^1.3.1", - "rc-util": "^5.16.1", - "rc-virtual-list": "^3.5.2" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-slider": { - "version": "11.1.7", - "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.7.tgz", - "integrity": "sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-util": "^5.36.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-steps": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", - "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.16.7", - "classnames": "^2.2.3", - "rc-util": "^5.16.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-switch": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", - "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.21.0", - "classnames": "^2.2.1", - "rc-util": "^5.30.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-table": { - "version": "7.48.1", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.48.1.tgz", - "integrity": "sha512-Z4mDKjWg+xz/Ezdw6ivWcbqRpaJ0QfCORRoRrlrw65KSGZLK8OcTdacH22/fyGb8L4It/0/9qcMm8VrVAk/WBw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/context": "^1.4.0", - "classnames": "^2.2.5", - "rc-resize-observer": "^1.1.0", - "rc-util": "^5.41.0", - "rc-virtual-list": "^3.14.2" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-tabs": { - "version": "15.4.0", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.4.0.tgz", - "integrity": "sha512-llKuyiAVqmXm2z7OrmhX5cNb2ueZaL8ZyA2P4R+6/72NYYcbEgOXibwHiQCFY2RiN3swXl53SIABi2CumUS02g==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.2", - "classnames": "2.x", - "rc-dropdown": "~4.2.0", - "rc-menu": "~9.16.0", - "rc-motion": "^2.6.2", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.34.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-textarea": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz", - "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.1", - "rc-input": "~1.6.0", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-tooltip": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz", - "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.11.2", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.3.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-tree": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.10.1.tgz", - "integrity": "sha512-FPXb3tT/u39mgjr6JNlHaUTYfHkVGW56XaGDahDpEFLGsnPxGcVLNTjcqoQb/GNbSCycl7tD7EvIymwOTP0+Yw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-util": "^5.16.1", - "rc-virtual-list": "^3.5.1" - }, - "engines": { - "node": ">=10.x" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-tree-select": { - "version": "5.24.5", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.24.5.tgz", - "integrity": "sha512-PnyR8LZJWaiEFw0SHRqo4MNQWyyZsyMs8eNmo68uXZWjxc7QqeWcjPPoONN0rc90c3HZqGF9z+Roz+GLzY5GXA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.25.7", - "classnames": "2.x", - "rc-select": "~14.16.2", - "rc-tree": "~5.10.1", - "rc-util": "^5.43.0" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-upload": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz", - "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.3", - "classnames": "^2.2.5", - "rc-util": "^5.2.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-util": { - "version": "5.43.0", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.43.0.tgz", - "integrity": "sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.3", - "react-is": "^18.2.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-virtual-list": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.15.0.tgz", - "integrity": "sha512-dF2YQztqrU3ijAeWOqscTshCEr7vpimzSqAVjO1AyAmaqcHulaXpnGR0ptK5PXfxTUy48VkJOiglMIxlkYGs0w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.20.0", - "classnames": "^2.2.6", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.36.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, - "node_modules/react-lazy-load-image-component": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/react-lazy-load-image-component/-/react-lazy-load-image-component-1.6.2.tgz", - "integrity": "sha512-dAdH5PsRgvDMlHC7QpZRA9oRzEZl1kPFwowmR9Mt0IUUhxk2wwq43PB6Ffwv84HFYuPmsxDUCka0E9KVXi8roQ==", - "license": "MIT", - "dependencies": { - "lodash.debounce": "^4.0.8", - "lodash.throttle": "^4.1.1" - }, - "peerDependencies": { - "react": "^15.x.x || ^16.x.x || ^17.x.x || ^18.x.x" - } - }, - "node_modules/react-leaflet": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", - "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", - "license": "Hippocratic-2.1", - "dependencies": { - "@react-leaflet/core": "^2.1.0" - }, - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/react-map-gl": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.7.tgz", - "integrity": "sha512-mwjc0obkBJOXCcoXQr3VoLqmqwo9vS4bXfbGsdxXzEgVCv/PM0v+1QggL7W0d/ccIy+VCjbXNlGij+PENz6VNg==", - "license": "MIT", - "dependencies": { - "@maplibre/maplibre-gl-style-spec": "^19.2.1", - "@types/mapbox-gl": ">=1.0.0" - }, - "peerDependencies": { - "mapbox-gl": ">=1.13.0", - "maplibre-gl": ">=1.13.0", - "react": ">=16.3.0", - "react-dom": ">=16.3.0" - }, - "peerDependenciesMeta": { - "mapbox-gl": { - "optional": true - }, - "maplibre-gl": { - "optional": true - } - } - }, - "node_modules/react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-router": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.0.tgz", - "integrity": "sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==", - "license": "MIT", - "dependencies": { - "@remix-run/router": "1.21.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.0.tgz", - "integrity": "sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==", - "license": "MIT", - "dependencies": { - "@remix-run/router": "1.21.0", - "react-router": "6.28.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/redux-logger": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz", - "integrity": "sha512-JoCIok7bg/XpqA1JqCqXFypuqBbQzGQySrhFzewB7ThcnysTO30l4VCst86AuB9T9tuT03MAA56Jw2PNhRSNCg==", - "license": "MIT", - "dependencies": { - "deep-diff": "^0.3.5" - } - }, - "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", - "license": "MIT", - "peerDependencies": { - "redux": "^4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, - "node_modules/resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", - "license": "MIT" - }, - "node_modules/resolve-protobuf-schema": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", - "license": "MIT", - "dependencies": { - "protocol-buffers-schema": "^3.3.1" - } - }, - "node_modules/rollup": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", - "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.6" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.27.4", - "@rollup/rollup-android-arm64": "4.27.4", - "@rollup/rollup-darwin-arm64": "4.27.4", - "@rollup/rollup-darwin-x64": "4.27.4", - "@rollup/rollup-freebsd-arm64": "4.27.4", - "@rollup/rollup-freebsd-x64": "4.27.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", - "@rollup/rollup-linux-arm-musleabihf": "4.27.4", - "@rollup/rollup-linux-arm64-gnu": "4.27.4", - "@rollup/rollup-linux-arm64-musl": "4.27.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", - "@rollup/rollup-linux-riscv64-gnu": "4.27.4", - "@rollup/rollup-linux-s390x-gnu": "4.27.4", - "@rollup/rollup-linux-x64-gnu": "4.27.4", - "@rollup/rollup-linux-x64-musl": "4.27.4", - "@rollup/rollup-win32-arm64-msvc": "4.27.4", - "@rollup/rollup-win32-ia32-msvc": "4.27.4", - "@rollup/rollup-win32-x64-msvc": "4.27.4", - "fsevents": "~2.3.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/scroll-into-view-if-needed": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", - "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", - "license": "MIT", - "dependencies": { - "compute-scroll-into-view": "^3.0.2" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-asc": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz", - "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-desc": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.2.0.tgz", - "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-object": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-3.0.3.tgz", - "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==", - "license": "MIT", - "dependencies": { - "bytewise": "^1.1.0", - "get-value": "^2.0.2", - "is-extendable": "^0.1.1", - "sort-asc": "^0.2.0", - "sort-desc": "^0.2.0", - "union-value": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-convert": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", - "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==", - "license": "MIT" - }, - "node_modules/stylis": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", - "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", - "license": "MIT" - }, - "node_modules/supercluster": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", - "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", - "license": "ISC", - "dependencies": { - "kdbush": "^4.0.2" - } - }, - "node_modules/throttle-debounce": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", - "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", - "license": "MIT", - "engines": { - "node": ">=12.22" - } - }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", - "license": "ISC" - }, - "node_modules/toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", - "license": "MIT" - }, - "node_modules/typewise": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", - "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==", - "license": "MIT", - "dependencies": { - "typewise-core": "^1.2.0" - } - }, - "node_modules/typewise-core": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", - "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==", - "license": "MIT" - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", - "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/vite": { - "version": "5.4.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", - "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vt-pbf": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", - "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", - "license": "MIT", - "dependencies": { - "@mapbox/point-geometry": "0.1.0", - "@mapbox/vector-tile": "^1.3.1", - "pbf": "^3.2.1" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - } - } -} diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index c28c545..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "dependencies": { - "antd": "^5.22.1", - "axios": "^1.6.3", - "leaflet": "^1.9.1", - "mapbox-gl": "^2.10.0", - "maplibre-gl": "^2.4.0", - "moment": "^2.29.4", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-lazy-load-image-component": "^1.5.5", - "react-leaflet": "^4.0.2", - "react-map-gl": "^7.0.19", - "react-redux": "^8.0.2", - "react-router-dom": "^6.3.0", - "redux": "^4.2.0", - "redux-logger": "^3.0.6", - "redux-thunk": "^2.4.1" - }, - "devDependencies": { - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@vitejs/plugin-react": "^4.2.1", - "vite": "^5.1.5" - } -} diff --git a/frontend/package.json.md5 b/frontend/package.json.md5 deleted file mode 100755 index 52d3822..0000000 --- a/frontend/package.json.md5 +++ /dev/null @@ -1 +0,0 @@ -85c9b773b391c3dc08c46bfe300878af \ No newline at end of file diff --git a/frontend/src/components/Gallery.jsx b/frontend/src/components/Gallery.jsx deleted file mode 100644 index 0ee9adf..0000000 --- a/frontend/src/components/Gallery.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import { LazyLoadImage, trackWindowScroll } - from 'react-lazy-load-image-component'; -import { Row, Col } from 'antd'; -import "./loading/loading.css" -import Loading from './loading/loading.svg'; -import { config } from '../store'; -const Gallery = ({ images, imageSize, addElementRef, selectPhoto, getStyle, scrollPosition }) => { - - const spanWidth = (size) => { - console.log("CHANGE_SIZE", size) - switch (size) { - case "xsmall": - return 2; - case "small": - return 4; - case "medium": - return 6; - case "large": - return 12; - case "xlarge": - return 24; - default: return 2; - } - } - return ( - - {images.map((image, index) => - -
-
selectPhoto(e, image)}> - -
-
- - )} -
- ); -} -// Wrap Gallery with trackWindowScroll HOC so it receives -// a scrollPosition prop to pass down to the images -export default trackWindowScroll(Gallery); - diff --git a/frontend/src/components/Map/Map.css b/frontend/src/components/Map/Map.css deleted file mode 100644 index 53ab9ad..0000000 --- a/frontend/src/components/Map/Map.css +++ /dev/null @@ -1,30 +0,0 @@ -.map-container { - width: 100%; - height: 100%; -} - -.sidebarStyle { - display: inline-block; - position: absolute; - top: 0; - left: 0; - margin: 12px; - background-color: #404040; - color: #ffffff; - z-index: 1 !important; - padding: 6px; - font-weight: bold; -} - -.map-model > * >.ant-modal-body { - padding: 0px; - margin: 6px; -} -.map-model > * > .ant-modal-header { - padding: 0px; - margin-bottom: 10px; - -} -.map-model > * > .ant-modal-close { - padding: 2px; -} \ No newline at end of file diff --git a/frontend/src/components/Map/Map.jsx b/frontend/src/components/Map/Map.jsx deleted file mode 100644 index e994ef9..0000000 --- a/frontend/src/components/Map/Map.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { useRef } from 'react'; -import { MapContainer, Marker, Popup, TileLayer, useMap, useMapEvents } from 'react-leaflet' - -const LocationMarker = ({onLocation, center}) => { - const [position, setPosition] = useState(center) - const map = useMapEvents({ - click(e) { - console.log("Map click evebt", e.latlng) - setPosition(e.latlng) - onLocation(e.latlng) - } - }) - - return position === null || (position.lat === 0 && position.lng === 0) ? null : ( - - You are here - - ) -} - -const ComponentResize = () => { - const map = useMap() - - setTimeout(() => { - console.log("MAP CALLED") - map.invalidateSize() - }, 0) - - return null -} - -const MapView = (props) => { - let center = [props.lat, props.lng] - if (props.lng === 0 && props.lat === 0) { - center = [51.505, -0.09] - } - return ( - - - - - - ) -}; - -export default MapView; diff --git a/frontend/src/components/Map/index.jsx b/frontend/src/components/Map/index.jsx deleted file mode 100644 index 164b422..0000000 --- a/frontend/src/components/Map/index.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, {useState} from 'react'; -import { Modal, Input, Button} from 'antd'; -import Map from './Map' -import "./Map.css" - -const defaultLat = 52.56815737826566 -const defaultLng =-1.4654394633258416 - -const InputGroup = Input.Group; -export const LocationModal = (props) =>{ - const [visable, setVisable] = useState(false); - - const [lng, setLng] = useState(defaultLng); - const [lat, setLat] = useState(defaultLat); - - React.useEffect(() => { - if (props.lat !== undefined){ - setLat(props.lat); - } - }, [props.lat]); - - React.useEffect(() => { - if (props.lng !== undefined){ - setLng(props.lng); - } - }, [props.lng]); - - - const onUpdate = () => { - props.onUpdate(lat,lng); - setVisable(false) - } - const onCancel = () => {setVisable(false)} - - const onLocationChange = ({lat, lng}) => { - setLng(lng) - setLat(lat) - } - - return ( -
- setVisable(true)}> - setVisable(true)}/> - setVisable(true)} /> - - - -
- - - - - -
-
- ) -} -export {default as Map} from "./Map" \ No newline at end of file diff --git a/frontend/src/components/addCollection.jsx b/frontend/src/components/addCollection.jsx deleted file mode 100644 index bef582a..0000000 --- a/frontend/src/components/addCollection.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import { Modal, Input, TreeSelect, Form } from 'antd'; -import {galleryActions, collectionActions} from '../store/actions' -import { useDispatch, useSelector } from 'react-redux'; - -const AddCollection = () => { - const {addCollectionModalVisable} = useSelector(state => state.GalleryReducer); - const {collections} = useSelector(state => state.CollectionsReducer) - - const [form] = Form.useForm(); - const dispatch = useDispatch() - - const handleCancel = () => { - dispatch(galleryActions.hideAdd()) - }; - - const handleCreate = () => { - form.validateFields().then(values => { - console.log('Received values of form: ', values); - form.resetFields(); - dispatch(collectionActions.create(values)) - dispatch(galleryActions.hideAdd()) - }) - .catch(err => { - console.log("error:",err) - }) - }; - - return ( - -
- - - - - - -
-
- ); -} -export default (AddCollection) diff --git a/frontend/src/components/header.jsx b/frontend/src/components/header.jsx deleted file mode 100644 index 8c3b764..0000000 --- a/frontend/src/components/header.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import { DesktopOutlined, SearchOutlined, SettingOutlined } from '@ant-design/icons'; -// as an array -import { Layout, Menu, Input, Avatar } from 'antd'; -import { userActions } from '../store/actions'; -import { Link } from "react-router-dom"; -import { useDispatch, useSelector } from 'react-redux'; -import { useLocation } from "react-router-dom"; - -const { Header } = Layout; -const { SubMenu } = Menu; - -const HeaderComponent = ({ search }) => { - const dispatch = useDispatch() - const location = useLocation(); - const { email } = useSelector(state => state.UserReducer) - const logout = () => { dispatch(userActions.logout()) } - const handleSearch = (e) => { search({ key: e.target.value }) } - - const get_gravatar = (size) => { - var MD5 = function (s) { function L(k, d) { return (k << d) | (k >>> (32 - d)) } function K(G, k) { var I, d, F, H, x; F = (G & 2147483648); H = (k & 2147483648); I = (G & 1073741824); d = (k & 1073741824); x = (G & 1073741823) + (k & 1073741823); if (I & d) { return (x ^ 2147483648 ^ F ^ H) } if (I | d) { if (x & 1073741824) { return (x ^ 3221225472 ^ F ^ H) } else { return (x ^ 1073741824 ^ F ^ H) } } else { return (x ^ F ^ H) } } function r(d, F, k) { return (d & F) | ((~d) & k) } function q(d, F, k) { return (d & k) | (F & (~k)) } function p(d, F, k) { return (d ^ F ^ k) } function n(d, F, k) { return (F ^ (d | (~k))) } function u(G, F, aa, Z, k, H, I) { G = K(G, K(K(r(F, aa, Z), k), I)); return K(L(G, H), F) } function f(G, F, aa, Z, k, H, I) { G = K(G, K(K(q(F, aa, Z), k), I)); return K(L(G, H), F) } function D(G, F, aa, Z, k, H, I) { G = K(G, K(K(p(F, aa, Z), k), I)); return K(L(G, H), F) } function t(G, F, aa, Z, k, H, I) { G = K(G, K(K(n(F, aa, Z), k), I)); return K(L(G, H), F) } function e(G) { var Z; var F = G.length; var x = F + 8; var k = (x - (x % 64)) / 64; var I = (k + 1) * 16; var aa = Array(I - 1); var d = 0; var H = 0; while (H < F) { Z = (H - (H % 4)) / 4; d = (H % 4) * 8; aa[Z] = (aa[Z] | (G.charCodeAt(H) << d)); H++ } Z = (H - (H % 4)) / 4; d = (H % 4) * 8; aa[Z] = aa[Z] | (128 << d); aa[I - 2] = F << 3; aa[I - 1] = F >>> 29; return aa } function B(x) { var k = "", F = "", G, d; for (d = 0; d <= 3; d++) { G = (x >>> (d * 8)) & 255; F = "0" + G.toString(16); k = k + F.substr(F.length - 2, 2) } return k } function J(k) { k = k.replace(/rn/g, "n"); var d = ""; for (var F = 0; F < k.length; F++) { var x = k.charCodeAt(F); if (x < 128) { d += String.fromCharCode(x) } else { if ((x > 127) && (x < 2048)) { d += String.fromCharCode((x >> 6) | 192); d += String.fromCharCode((x & 63) | 128) } else { d += String.fromCharCode((x >> 12) | 224); d += String.fromCharCode(((x >> 6) & 63) | 128); d += String.fromCharCode((x & 63) | 128) } } } return d } var C = []; var P, h, E, v, g, Y, X, W, V; var S = 7, Q = 12, N = 17, M = 22; var A = 5, z = 9, y = 14, w = 20; var o = 4, m = 11, l = 16, j = 23; var U = 6, T = 10, R = 15, O = 21; s = J(s); C = e(s); Y = 1732584193; X = 4023233417; W = 2562383102; V = 271733878; for (P = 0; P < C.length; P += 16) { h = Y; E = X; v = W; g = V; Y = u(Y, X, W, V, C[P + 0], S, 3614090360); V = u(V, Y, X, W, C[P + 1], Q, 3905402710); W = u(W, V, Y, X, C[P + 2], N, 606105819); X = u(X, W, V, Y, C[P + 3], M, 3250441966); Y = u(Y, X, W, V, C[P + 4], S, 4118548399); V = u(V, Y, X, W, C[P + 5], Q, 1200080426); W = u(W, V, Y, X, C[P + 6], N, 2821735955); X = u(X, W, V, Y, C[P + 7], M, 4249261313); Y = u(Y, X, W, V, C[P + 8], S, 1770035416); V = u(V, Y, X, W, C[P + 9], Q, 2336552879); W = u(W, V, Y, X, C[P + 10], N, 4294925233); X = u(X, W, V, Y, C[P + 11], M, 2304563134); Y = u(Y, X, W, V, C[P + 12], S, 1804603682); V = u(V, Y, X, W, C[P + 13], Q, 4254626195); W = u(W, V, Y, X, C[P + 14], N, 2792965006); X = u(X, W, V, Y, C[P + 15], M, 1236535329); Y = f(Y, X, W, V, C[P + 1], A, 4129170786); V = f(V, Y, X, W, C[P + 6], z, 3225465664); W = f(W, V, Y, X, C[P + 11], y, 643717713); X = f(X, W, V, Y, C[P + 0], w, 3921069994); Y = f(Y, X, W, V, C[P + 5], A, 3593408605); V = f(V, Y, X, W, C[P + 10], z, 38016083); W = f(W, V, Y, X, C[P + 15], y, 3634488961); X = f(X, W, V, Y, C[P + 4], w, 3889429448); Y = f(Y, X, W, V, C[P + 9], A, 568446438); V = f(V, Y, X, W, C[P + 14], z, 3275163606); W = f(W, V, Y, X, C[P + 3], y, 4107603335); X = f(X, W, V, Y, C[P + 8], w, 1163531501); Y = f(Y, X, W, V, C[P + 13], A, 2850285829); V = f(V, Y, X, W, C[P + 2], z, 4243563512); W = f(W, V, Y, X, C[P + 7], y, 1735328473); X = f(X, W, V, Y, C[P + 12], w, 2368359562); Y = D(Y, X, W, V, C[P + 5], o, 4294588738); V = D(V, Y, X, W, C[P + 8], m, 2272392833); W = D(W, V, Y, X, C[P + 11], l, 1839030562); X = D(X, W, V, Y, C[P + 14], j, 4259657740); Y = D(Y, X, W, V, C[P + 1], o, 2763975236); V = D(V, Y, X, W, C[P + 4], m, 1272893353); W = D(W, V, Y, X, C[P + 7], l, 4139469664); X = D(X, W, V, Y, C[P + 10], j, 3200236656); Y = D(Y, X, W, V, C[P + 13], o, 681279174); V = D(V, Y, X, W, C[P + 0], m, 3936430074); W = D(W, V, Y, X, C[P + 3], l, 3572445317); X = D(X, W, V, Y, C[P + 6], j, 76029189); Y = D(Y, X, W, V, C[P + 9], o, 3654602809); V = D(V, Y, X, W, C[P + 12], m, 3873151461); W = D(W, V, Y, X, C[P + 15], l, 530742520); X = D(X, W, V, Y, C[P + 2], j, 3299628645); Y = t(Y, X, W, V, C[P + 0], U, 4096336452); V = t(V, Y, X, W, C[P + 7], T, 1126891415); W = t(W, V, Y, X, C[P + 14], R, 2878612391); X = t(X, W, V, Y, C[P + 5], O, 4237533241); Y = t(Y, X, W, V, C[P + 12], U, 1700485571); V = t(V, Y, X, W, C[P + 3], T, 2399980690); W = t(W, V, Y, X, C[P + 10], R, 4293915773); X = t(X, W, V, Y, C[P + 1], O, 2240044497); Y = t(Y, X, W, V, C[P + 8], U, 1873313359); V = t(V, Y, X, W, C[P + 15], T, 4264355552); W = t(W, V, Y, X, C[P + 6], R, 2734768916); X = t(X, W, V, Y, C[P + 13], O, 1309151649); Y = t(Y, X, W, V, C[P + 4], U, 4149444226); V = t(V, Y, X, W, C[P + 11], T, 3174756917); W = t(W, V, Y, X, C[P + 2], R, 718787259); X = t(X, W, V, Y, C[P + 9], O, 3951481745); Y = K(Y, h); X = K(X, E); W = K(W, v); V = K(V, g) } var i = B(Y) + B(X) + B(W) + B(V); return i.toLowerCase() }; - size = size || 80; - return 'https://www.gravatar.com/avatar/' + MD5(email || "") + '.jpg?s=' + size; - } - return ( -
-
GoGallery
- {location.pathname === "/" && - } placeholder="Filter Photos" onChange={handleSearch} style={{ width: "400px" }} /> - } - ), - key: 'settings' - } - ]} /> - ), - key: 'preview' - } - ]} /> - -
- ); -} - -export default HeaderComponent - diff --git a/frontend/src/components/loading/loading.css b/frontend/src/components/loading/loading.css deleted file mode 100644 index 715c1f9..0000000 --- a/frontend/src/components/loading/loading.css +++ /dev/null @@ -1,39 +0,0 @@ - .container { - --uib-size: 35px; - --uib-color: black; - --uib-speed: 1.2s; - --uib-bg-opacity: .1; - height: var(--uib-size); - width: var(--uib-size); - transform-origin: center; - will-change: transform; - overflow: visible; - } - - .car { - fill: none; - stroke: var(--uib-color); - stroke-dasharray: 25, 75; - stroke-dashoffset: 0; - animation: travel var(--uib-speed) linear infinite; - will-change: stroke-dasharray, stroke-dashoffset; - transition: stroke 0.5s ease; - } - - .track { - fill: none; - stroke: var(--uib-color); - opacity: var(--uib-bg-opacity); - transition: stroke 0.5s ease; - } - - @keyframes travel { - 0% { - stroke-dashoffset: 0; - } - - 100% { - stroke-dashoffset: -100; - } - } - diff --git a/frontend/src/components/loading/loading.jsx b/frontend/src/components/loading/loading.jsx deleted file mode 100644 index 37cbaf8..0000000 --- a/frontend/src/components/loading/loading.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import "./loading.css" - -export const Loading = () => ( - - - - -) \ No newline at end of file diff --git a/frontend/src/components/loading/loading.svg b/frontend/src/components/loading/loading.svg deleted file mode 100644 index 94a3172..0000000 --- a/frontend/src/components/loading/loading.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/frontend/src/components/modal.jsx b/frontend/src/components/modal.jsx deleted file mode 100644 index cfda359..0000000 --- a/frontend/src/components/modal.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { useState } from 'react'; -import { ContainerOutlined, DeleteOutlined } from '@ant-design/icons'; -import { Modal, Button, TreeSelect,Form } from 'antd'; - -import { useDispatch, useSelector } from 'react-redux'; -import { collectionActions } from '../store/actions'; - -const { confirm } = Modal; -const ButtonGroup = Button.Group; - -const MoveModal = ({selectedPhotos}) => { - const [visible, setVisable] = useState(false) - const [form] = Form.useForm(); - const dispatch = useDispatch() - - const { photos } = useSelector(state => state.PhotoReducer) - const {collections} = useSelector(state => state.CollectionsReducer); - - const showModal = () => { - setVisable(true) - }; - - const handleCancel = () => { - setVisable(false) - }; - - const showDeleteConfirm = () =>{ - confirm({ - title: 'Are you sure delete these photos?', - content: '', - okText: 'Yes', - okType: 'danger', - cancelText: 'No', - onOk() { - selectedPhotos.forEach(pos => { - let photo = photos[pos] - dispatch(collectionActions.remove(photo.id)) - }) - - console.log('OK'); - }, - onCancel() { - console.log('Cancel'); - }, - }); - } - - const handleCreate = () => { - form.validateFields().then(values => { - values["photos"] = selectedPhotos.map(pos => photos[pos]) - console.log('Received values of Move form: ', values); - dispatch(collectionActions.move(values)) - setVisable(false) - }) - .catch(err => {}) - }; - - return ( -
- - - - - -
- - - -
-
-
- ); -} - - -export default MoveModal diff --git a/frontend/src/components/settings/AlbumSettings.jsx b/frontend/src/components/settings/AlbumSettings.jsx deleted file mode 100644 index 917032b..0000000 --- a/frontend/src/components/settings/AlbumSettings.jsx +++ /dev/null @@ -1,168 +0,0 @@ -import React, {useState, useEffect} from 'react'; -import { Form } from "antd" -import { Input, Divider, Button, Tree, Row, Col, Select } from 'antd'; -import { useDispatch, useSelector } from 'react-redux'; -import { collectionActions } from '../../store/actions'; -import {notify} from '../../store/actions'; -import {LocationModal} from '../Map' - -const { Option } = Select; -const formItemLayout = { - labelCol: { - xs: { span: 24 }, - sm: { span: 5 }, - }, - wrapperCol: { - xs: { span: 24 }, - sm: { span: 19 }, - }, -}; -const tailFormItemLayout = { - wrapperCol: { - xs: { - span: 24, - offset: 0, - }, - sm: { - span: 8, - offset: 8, - }, - }, -}; - -const AlbumSettings = () => { - - const photos = useSelector(state =>state.PhotoReducer.photos); - const collections = useSelector(state =>state.CollectionsReducer.collections); - const dispatch = useDispatch(); - - const [albumName, setAlbumName] = useState("") - const [albumPic, setAlbumPic] = useState("") - const [albumID, setAlbumID] = useState("") - - const [GPS, setGPS] = useState({ - latitude:0, - longitude:0 - }) - - const [form] = Form.useForm(); - useEffect(() => { - form.setFieldsValue({ - albumName: albumName, - albumPic: albumPic, - albumID: albumID, - }); - }, [form, albumName, albumPic,albumID]); - - - - - - const handleSubmit = () => { - if(albumID === ""){ - notify("warning", "Please Select album") - return; - } - dispatch(collectionActions.update({ - id: albumID, - name: albumName, - profile_image: albumPic, - GPS: GPS - })) - }; - - const onTreeSelect = (selectedKeys, info) => { - let alb = findInTree(collections, selectedKeys[0]) - console.log("TREE_SELECT", alb, selectedKeys) - if(alb === undefined){ - return - } - setAlbumID(alb.id) - setAlbumPic(alb.profile_image) - setAlbumName(alb.name) - setGPS(alb.gps) - - }; - - const onChange = (value) => { - setAlbumPic(value) - } - - const updateAlbumName = (evt) => { - setAlbumName(evt.target.value) - } - - const updateGPS = (lat, lng) => { - setGPS( - { - latitude:lat, - longitude:lng - } - ) - } - - - const findInTree = (tree, id) => { - let el - const proceesNode = (node) => { - if (node.id === id) { - el = node - return - } - return node.children.map(n => proceesNode(n)) - } - tree = Object.values(tree) - tree.map(node => proceesNode(node)) - return el - } - - - console.log("COLLECTIONS:", collections) - return ( - - - - - -
- < Divider/> - - - - - - - - - - - - - - - - - -
- ); - } - -export default AlbumSettings; diff --git a/frontend/src/components/settings/DeploymentForm.jsx b/frontend/src/components/settings/DeploymentForm.jsx deleted file mode 100644 index 527fd61..0000000 --- a/frontend/src/components/settings/DeploymentForm.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React, { useEffect } from 'react'; -import { Form, Switch } from 'antd'; -import { Input, Select, InputNumber, Divider, Button } from 'antd'; -import EditableTagGroup from './EditableTagGroup'; - -import { useDispatch, useSelector } from 'react-redux'; -import { settingsActions } from '../../store/actions'; - -const { Option } = Select; -const formItemLayout = { - labelCol: { - xs: { span: 24 }, - sm: { span: 5 }, - }, - wrapperCol: { - xs: { span: 24 }, - sm: { span: 19 }, - }, -}; -const tailFormItemLayout = { - wrapperCol: { - xs: { - span: 24, - offset: 0, - }, - sm: { - span: 8, - offset: 8, - }, - }, -}; - - -const DeploymentForm = () => { - const [form] = Form.useForm(); - const deploy = useSelector(state => state.SettingsReducer.deploy); - const dispatch = useDispatch(); - - useEffect(() => { - console.log("DEPLOY:",deploy); - form.setFieldsValue({ - SiteId: deploy.SiteId, - AuthToken: deploy.AuthToken, - Draft: deploy.Draft - }); - }, [form,deploy]); - - const handleSubmit = () => { - - form.validateFields().then(values => { - console.log('Received values of form: ', values); - dispatch(settingsActions.setDeploy(values)) - }); - }; - - return ( -
- - - - - - - - - - ) -} - -export default DeploymentForm \ No newline at end of file diff --git a/frontend/src/components/settings/EditableTagGroup.jsx b/frontend/src/components/settings/EditableTagGroup.jsx deleted file mode 100644 index 62740e6..0000000 --- a/frontend/src/components/settings/EditableTagGroup.jsx +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react'; -import { PlusOutlined } from '@ant-design/icons'; -import { Tag, Input, Tooltip } from 'antd'; - -export default class EditableTagGroup extends React.Component { - constructor(props){ - super(props) - this.state = { - tags: [], - removedTags: [], - inputVisible: false, - inputValue: '', - }; - } - - static getDerivedStateFromProps(nextProps, prevState){ - if(nextProps.value === undefined || nextProps.value === null){return null} - let intersection = nextProps.value.filter(x => !prevState.removedTags.includes(x)); - console.log("NEW PROPS", nextProps.value, prevState.removedTags, intersection) - - return { tags: intersection } - - } - - handleClose = removedTag => { - const tags = this.state.tags.filter(tag => tag !== removedTag); - console.log("CLOS TAG", tags); - this.setState({ tags, - removedTags: this.state.removedTags.concat(removedTag) - }); - this.props.onChange(tags) - }; - - showInput = () => { - this.setState({ inputVisible: true }, () => this.input.focus()); - }; - - handleInputChange = e => { - this.setState({ inputValue: e.target.value }); - - }; - - handleInputConfirm = () => { - const { inputValue } = this.state; - let { tags } = this.state; - if (inputValue && tags.indexOf(inputValue) === -1) { - tags = [...tags, inputValue]; - } - this.setState({ - tags, - inputVisible: false, - inputValue: '', - }); - console.log("Received values of form",tags, this.state) - this.props.onChange(tags) - }; - - saveInputRef = input => (this.input = input); - - render() { - const { tags, inputVisible, inputValue } = this.state; - return ( -
- {tags.map((tag, index) => { - const isLongTag = tag.length > 20; - const tagElem = ( - this.handleClose(tag)}> - {isLongTag ? `${tag.slice(0, 20)}...` : tag} - - ); - return isLongTag ? ( - - {tagElem} - - ) : ( - tagElem - ); - })} - {inputVisible && ( - - )} - {!inputVisible && ( - - New Tag - - )} -
- ); - } -} \ No newline at end of file diff --git a/frontend/src/components/settings/ProfileForm.jsx b/frontend/src/components/settings/ProfileForm.jsx deleted file mode 100644 index 8ac47eb..0000000 --- a/frontend/src/components/settings/ProfileForm.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import React, {useEffect} from 'react'; -import { Form } from "antd"; -import { Input, Divider, Button } from 'antd'; -import { useDispatch, useSelector } from 'react-redux'; -import { settingsActions } from '../../store/actions'; - -const formItemLayout = { - labelCol: { - xs: { span: 24 }, - sm: { span: 5 }, - }, - wrapperCol: { - xs: { span: 24 }, - sm: { span: 19 }, - }, -}; -const tailFormItemLayout = { - wrapperCol: { - xs: { - span: 24, - offset: 0, - }, - sm: { - span: 8, - offset: 8, - }, - }, -}; - -const ProfileForm = () => { - - const settings = useSelector(state => state.SettingsReducer.profile); - const dispatch = useDispatch(); - - const [form] = Form.useForm(); - useEffect(() => { - console.log("SETTINGS:", settings); - form.setFieldsValue({ - ProfilePhoto: settings.ProfilePhoto, - BackgroundPhoto: settings.BackgroundPhoto, - Description: settings.Description, - Footer: settings.Footer, - Twitter: settings.Twitter, - Instagram: settings.Instagram, - Website: settings.Website, - }); - }, [form, settings]); - - - - - const handleSubmit = e => { - form.validateFields().then(values => { - console.log('Received values of form: ', values); - dispatch(settingsActions.setProfile(values)) - }); - }; - - - - return ( -
-
- About - - - - - Social -

Leave black to disable

- - - - - - - - -
- - ); - } -export default ProfileForm; diff --git a/frontend/src/components/settings/RegistrationForm.jsx b/frontend/src/components/settings/RegistrationForm.jsx deleted file mode 100644 index aab0821..0000000 --- a/frontend/src/components/settings/RegistrationForm.jsx +++ /dev/null @@ -1,132 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Form } from 'antd'; -import { Input, Divider, Button } from 'antd'; -import { useDispatch, useSelector } from 'react-redux'; -import { userActions } from '../../store/actions'; - -const formItemLayout = { - labelCol: { - xs: { span: 24 }, - sm: { span: 5 }, - }, - wrapperCol: { - xs: { span: 24 }, - sm: { span: 19 }, - }, -}; -const tailFormItemLayout = { - wrapperCol: { - xs: { - span: 24, - offset: 0, - }, - sm: { - span: 8, - offset: 8, - }, - }, -}; - - -const RegistrationForm = (props) => { - const auth = useSelector(state => state.UserReducer); - const dispatch = useDispatch(); - - const [confirmDirty, setConfirmDirty] = useState(false) - const [form] = Form.useForm(); - - useEffect(() => { - console.log("SETTINGS:", auth); - form.setFieldsValue({ - username: auth.username, - email: auth.email, - }); - }, [form, auth]); - - const handleSubmit = () => { - form.validateFields().then(values => { - console.log('Received values of form: ', values); - if (values.password !== undefined) { - dispatch(userActions.update({ - username: values.username, - email: values.email, - password: values.password - })) - } else { - dispatch(userActions.update({ - username: values.username, - email: values.email - })) - } - }); - }; - - const handleConfirmBlur = e => { - const { value } = e.target; - setConfirmDirty(confirmDirty || !!value) - }; - - - - - return ( -
- - - - - - - ({ - validator(_, value) { - if (!value || getFieldValue('password') === value) { - return Promise.resolve(); - } - return Promise.reject(new Error('The two passwords that you entered do not match!')); - }, - }), - ] - }> - - - - - - - ) -} -export default RegistrationForm diff --git a/frontend/src/components/settings/SettingsForm.jsx b/frontend/src/components/settings/SettingsForm.jsx deleted file mode 100644 index 0181373..0000000 --- a/frontend/src/components/settings/SettingsForm.jsx +++ /dev/null @@ -1,92 +0,0 @@ -import React, { useEffect } from 'react'; -import { Form, Switch } from 'antd'; -import { Input, Select, InputNumber, Divider, Button } from 'antd'; -import EditableTagGroup from './EditableTagGroup'; - -import { useDispatch, useSelector } from 'react-redux'; -import { settingsActions } from '../../store/actions'; - -const { Option } = Select; -const formItemLayout = { - labelCol: { - xs: { span: 24 }, - sm: { span: 5 }, - }, - wrapperCol: { - xs: { span: 24 }, - sm: { span: 19 }, - }, -}; -const tailFormItemLayout = { - wrapperCol: { - xs: { - span: 24, - offset: 0, - }, - sm: { - span: 8, - offset: 8, - }, - }, -}; - - -const SettingsForm = () => { - const [form] = Form.useForm(); - const settings = useSelector(state => state.SettingsReducer.gallery); - const dispatch = useDispatch(); - - useEffect(() => { - console.log("SETTINGS:",settings); - form.setFieldsValue({ - Name: settings.Name, - Basepath: settings.Basepath, - Url: settings.Url, - Theme: settings.Theme, - Destpath: settings.Destpath, - ImagesPerPage: settings.ImagesPerPage, - PictureBlacklist: settings.PictureBlacklist || [], - AlbumBlacklist: settings.AlbumBlacklist || [], - Renderer: settings.Renderer, - }); - }, [form,settings]); - - const handleSubmit = () => { - - form.validateFields().then(values => { - console.log('Received values of form: ', values); - dispatch(settingsActions.setGallery(values)) - }); - }; - - return ( -
- - - - - - - - - - - - - - - - - - - - - - - - ) -} - -export default SettingsForm \ No newline at end of file diff --git a/frontend/src/components/settings/TaskViewer.jsx b/frontend/src/components/settings/TaskViewer.jsx deleted file mode 100644 index 3839f0d..0000000 --- a/frontend/src/components/settings/TaskViewer.jsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Badge, Space, Table, Tag } from "antd" -import axios from "axios"; -import React, { useEffect, useState } from 'react'; -import { config } from "../../store"; -import { notify } from "../../store/actions"; -const { Column, ColumnGroup } = Table; -const test = [ - { - "name": "albums", - "done": true, - "start": "2022-09-10T19:47:53.842094663+01:00", - "end": "2022-09-10T19:47:54.092477954+01:00", - "duration": 250383285 - }, - { - "name": "images", - "done": false, - "start": "2022-09-10T19:47:58.417235735+01:00", - "end": "2022-09-10T19:47:58.423342357+01:00", - "duration": 6106621 - }, - { - "name": "photos", - "done": true, - "start": "2022-09-10T19:47:54.106178396+01:00", - "end": "2022-09-10T19:47:58.391295965+01:00", - "duration": 4285117574 - } - ]; - -const formatDuration = ms => { - if (ms < 0) ms = -ms; - const time = { - day: Math.floor(ms / 86400000), - hour: Math.floor(ms / 3600000) % 24, - minute: Math.floor(ms / 60000) % 60, - second: Math.floor(ms / 1000) % 60, - // millisecond: Math.floor(ms) % 1000 - }; - let msg = Object.entries(time) - .filter(val => val[1] !== 0) - .map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`) - .join(', '); - - if (msg === "") return "-" - return msg - }; - -export const TaskViewer = () => { - const [data, setData] = useState([]) - - const getTasks = () => { - axios.get(config.baseUrl+"/tasks").then((resp)=>{ - setData(resp.data) - }).catch((err)=>{ - notify("warning", "Error from server: "+err) - }) - } - - - useEffect(() => { - let interval = setInterval(() => { - getTasks() - }, 1000); - return () => { - clearInterval(interval); - }; - }, []); - - const sortTasks = (tasks) => { - tasks = tasks.filter(a => a.state!=="inactive") - return tasks.sort((a,b) => {return new Date(Date.parse(b.start)) - new Date(Date.parse(a.start));}); - } - - return ( - - - { - return state==="complete" ? <> Complete : <> In progress - }}/> - { - let date = new Date(Date.parse(timeStr)); - return date.toLocaleString(); - } - } /> - { - return formatDuration(timeStr/1000000); - } - } /> - - -
- ) -} \ No newline at end of file diff --git a/frontend/src/components/settings/maintenance.jsx b/frontend/src/components/settings/maintenance.jsx deleted file mode 100644 index 5864cb3..0000000 --- a/frontend/src/components/settings/maintenance.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useState } from 'react'; -import { DeleteOutlined, DownloadOutlined, SyncOutlined, UploadOutlined, BuildOutlined } from '@ant-design/icons'; -import { message, Row, Col, Divider, Upload, Button, Modal } from 'antd'; -import { useDispatch } from 'react-redux'; -import { taskActions } from '../../store/actions'; -import { config } from "../../store"; -import { TaskViewer } from './TaskViewer'; - - -const Maintenance = () => { - const dispatch = useDispatch(); - const [fileList, setFileList] = useState([]) - - const props = { - name: 'file', - action: config.baseUrl + "/tasks/upload", - headers: { Authorization: localStorage.getItem('token') }, - className: "maintenance", - - onChange(info) { - if (info.file.status !== 'uploading') { - console.log(info.file, info.fileList); - } - if (info.file.status === 'done') { - message.success(`${info.file.name} file uploaded successfully`); - info.fileList = [] - } else if (info.file.status === 'error') { - message.error(`${info.file.name} file upload failed.`); - } - let fileList = [...info.fileList]; - fileList = fileList.slice(-2); - fileList = fileList.map(file => { - if (file.response) { - file.url = file.response.url; - } - return file; - }); - setFileList(fileList); - }, - }; - - return ( - <> - - - - - -
- - -
- - - - - - - - - - - - -
- Tasks - - - - ); -} - - -export default Maintenance; \ No newline at end of file diff --git a/frontend/src/components/sidebar.jsx b/frontend/src/components/sidebar.jsx deleted file mode 100644 index af8ba6f..0000000 --- a/frontend/src/components/sidebar.jsx +++ /dev/null @@ -1,146 +0,0 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import { AutoComplete, Form } from 'antd'; -// as an array -import { Layout, Input, Select, TreeSelect, Typography } from 'antd'; -import { Collapse } from 'antd'; - -import { useDispatch, useSelector } from 'react-redux'; -import { config } from '../store'; -import { getOptions, photoActions } from '../store/actions'; -import { LocationModal } from './Map' -import axios from 'axios'; - -const { Paragraph } = Typography; -const { Panel } = Collapse; -const { Sider } = Layout; -const { Option } = Select; - -const SideBar = ({ photo }) => { - - const { collections } = useSelector(state => state.CollectionsReducer); - const dispatch = useDispatch() - const [form] = Form.useForm(); - const [data, setData] = useState({}) - const [captionOptions, setCaptionOptions] = useState([]) - - const editPhoto = () => { - let formData = form.getFieldValue() - let newPhoto = { ...data, ...formData } - if (JSON.stringify(newPhoto) !== JSON.stringify(data)) { - dispatch(photoActions.edit(newPhoto)) - } - - } - - const getCaptionList = useCallback(() => { - axios.get(`${config.baseUrl}/photo/${photo.id}/caption`, getOptions()).then(res => { - console.log("CAPTIONS", res) - if (res.data.status === "ok") { - let options = res.data.predictions.map( prediction => { return {value: prediction.caption}}) - setCaptionOptions(options) - } - }).catch(err => console.log(err)) - }, [photo]); - - useEffect(() => { - if (photo) { - console.log("Photo Update") - setData(photo) - //getCaptionList() - form.setFieldsValue(photo) - } else { - setData({}) - } - }, [photo, form, getCaptionList]) - - const updateGPS = (lat, lng) => { - data.exif.GPS = { - latitude: lat, - longitude: lng - } - console.log("UPDATE GPS", data) - dispatch(photoActions.edit(data)) - } - - const formItemLayout = { - labelCol: { - xs: { span: 24 }, - sm: { span: 8 }, - }, - wrapperCol: { - xs: { span: 24 }, - sm: { span: 16 }, - }, - }; - - const formatDate = (datestr) => { - console.log("DATE:",datestr) - const date = new Date(Date.parse(datestr)); - return date.toLocaleString(); - } - - return ( - - thumbnail -
- - - - - - {data.id} - - - - - - - - - - - - - - - - - - - - - - - - - {data.name} - - - - - {data.exif ? formatDate(data.exif.date_taken) : ""} - - - {data.meta ? formatDate(data.meta.date_added) : ""} - - - {data.meta ? formatDate(data.meta.date_modified) : ""} - - - -
-
- ); -} -export default SideBar; diff --git a/frontend/src/components/upload.jsx b/frontend/src/components/upload.jsx deleted file mode 100644 index 5610980..0000000 --- a/frontend/src/components/upload.jsx +++ /dev/null @@ -1,108 +0,0 @@ -import React from 'react'; -import { InboxOutlined } from '@ant-design/icons'; -import { Form } from 'antd'; -import { Modal, TreeSelect } from 'antd'; -import {config} from "../store"; -import axios from "axios" -import {notify} from '../store/actions'; -import { useDispatch, useSelector } from 'react-redux'; -import {galleryActions, collectionActions, getOptions} from '../store/actions' -import { useState } from 'react'; - -import { Upload, message } from 'antd'; -const { Dragger } = Upload; - -const UploadCollection = () => { - const {uploadModalVisable} = useSelector(state => state.GalleryReducer); - const {collections} = useSelector(state => state.CollectionsReducer) - - const [upload, setEnableUpload] = useState(false) - const [files, setFiles] = useState([]) - - const [form] = Form.useForm(); - const dispatch = useDispatch() - - const enableUpload = () =>{ - setEnableUpload(true); - } - - const customRequest = (options ) => { - const data= new FormData() - console.log("FILE UPLOAD", options); - data.append('file', options.file) - let config = getOptions(); - config.headers["content-type"] = 'multipart/form-data; boundary=----WebKitFormBoundaryqTqJIxvkWFYqvP5s'; - - axios.post(options.action, data, config).then((res) => { - options.onSuccess(res.data, options.file) - message.success(`${options.file.name} file uploaded successfully.`); - setFiles(files => [...files, options.file.name]); - }).catch(() => { - message.error(`${options.file.name} file upload failed.`); - }) - } - const onCancel = () => { - dispatch(galleryActions.hideUpload()) - } - - const onCreate = () => { - form.validateFields().then(values => { - console.log('Received values of form: ', values, files); - form.resetFields(); - dispatch(collectionActions.upload({ - album: values.select, - photos: files - })) - dispatch(galleryActions.hideUpload()) - - }).catch(() => { - notify("warning", "Invaild data, could not upload") - return; - }) - } - - return ( - -
- - - - -

- -

-

Click or drag file to this area to upload

-

- Support for a single or bulk upload. Strictly prohibit from uploading company data or other - band files -

-
- -
-
- ); -} -export default UploadCollection - diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx deleted file mode 100644 index 45d8f67..0000000 --- a/frontend/src/main.jsx +++ /dev/null @@ -1,62 +0,0 @@ -// import 'antd/dist/antd.compact.min.css'; -// import 'antd/dist/antd.dark.min.css'; -// import 'antd/dist/reset.css'; -import React from 'react'; -import {createRoot} from 'react-dom/client'; - -import { Provider } from 'react-redux'; -import { BrowserRouter } from 'react-router-dom'; -import store from './store' -import { - Routes, - Route, - Navigate -} from 'react-router-dom' - -import Main from './pages/Main'; -import Settings from './pages/Settings' -import { Button, ConfigProvider, Layout, theme } from 'antd'; -import Preview from './pages/Preview'; - -const NoMatch = ({ location }) => ( - -) - -const AppComponent = () => { - return( - - - )} /> - )} /> - )} /> - - - - ) -} -const container = document.getElementById('app_root'); -const root = createRoot(container); -const { Header, Footer, Sider, Content } = Layout; -root.render( - - - - - -); \ No newline at end of file diff --git a/frontend/src/pages/Main.css b/frontend/src/pages/Main.css deleted file mode 100644 index 40ccc38..0000000 --- a/frontend/src/pages/Main.css +++ /dev/null @@ -1,245 +0,0 @@ -html, body { - height: 100%; - color: white; - overflow: hidden; -} -.App { - text-align: center; - height: 100%; -} -#root{ - height: 100%; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -* { - animation-duration: 0s !important; -} - -.App-header { - - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -.item-container { - cursor:crosshair; -} -.App { - text-align: center; -} - -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 40vmin; - pointer-events: none; -} - -.App-header { - /* background-color: #282c34; */ - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -.ant-modal-body { - padding: 5px 24px 16px 24px; -} - -.ant-modal-header { - padding: 16px 24px 5px 24px; -} - -.brand { - float: left; - font-size: 24px; - color: white; - border-right: 1px solid #282828; - border-color: rgba(253, 253, 253, 0.12); - width: 200px; - text-align: center; -} - - -.brand:hover { - color: rgba(255, 255, 255, 0.65); -} - -.galleryImg { - position: absolute; - top:0; - left:0; - width:100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; -} - -.ant-row.ant-form-item{ - margin-bottom: 10px; -} - -.disable-select { - user-select: none; /* supported by Chrome and Opera */ - -webkit-user-select: none; /* Safari */ - -khtml-user-select: none; /* Konqueror HTML */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* Internet Explorer/Edge */ -} - -.item { - cursor: pointer; - user-select: none; /* supported by Chrome and Opera */ - -webkit-user-select: none; /* Safari */ - -khtml-user-select: none; /* Konqueror HTML */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* Internet Explorer/Edge */ - - width:100%; - height:0; - padding-bottom: calc(100%*4/6); - position: relative; -} -/* Blur + Gray Scale */ -.item figure img { - -webkit-filter: grayscale(0); - filter: grayscale(0); - -webkit-transition: .3s ease-in-out; - transition: .3s ease-in-out; - cursor: pointer; -} -.item figure:hover img { - -webkit-filter: grayscale(100%); - filter: grayscale(100%); - cursor: pointer; - -} -.item figure { - border: 3px solid #000; - margin: 0; - text-align: center; -} - - - -.ant-input-search .ant-input { - border: 0px; - height: 42px; - -} -.ant-input-search .ant-input:focus { - outline-color: transparent; - outline-style: none; - box-shadow: none; -} - -.ant-input-search { - font-size: larger; - margin-top: 10px; -} -.ant-input-search .ant-input-suffix { - left: 10px; - right: auto; -} - - - -/* .tick { - -webkit-filter: grayscale(100%); - filter: grayscale(100%); - -} */ - -.maintenance .ant-upload { - width: 100%; -} - -.ant-menu-submenu ul { - max-height: 500px; - overflow-y: auto; - overflow-x: hidden; - margin-top: -5px; - margin-right: -20px; -} - -/* .ant-menu-submenu-popup::-webkit-scrollbar { - display: none; -} -.ant-menu-submenu-popup{ - max-height: 500px; - overflow-y: auto; - padding-right: 10px; - - scrollbar-width: none; -} */ - - -.menu-tree > .ant-tree { - font-family: "Roboto", sans-serif; - font-size: 14px; - font-weight: 300; - min-width:300px -} - -.menu-tree .ant-tree-treenode { - padding: 5px 10px; -} - - -.main { - width: 100%; -} - -::-webkit-scrollbar { width: 8px; height: 0px;} -::-webkit-scrollbar-track { background-color: #646464;} -::-webkit-scrollbar-track-piece { background-color: #000;} -::-webkit-scrollbar-thumb { height: 0px; background-color: #666; border-radius: 0px;} -::-webkit-scrollbar-corner { background-color: #646464;} -::-webkit-resizer { background-color: #666;} - diff --git a/frontend/src/pages/Main.jsx b/frontend/src/pages/Main.jsx deleted file mode 100644 index cf70978..0000000 --- a/frontend/src/pages/Main.jsx +++ /dev/null @@ -1,294 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import './Main.css'; - -import { - CalendarOutlined, - CameraOutlined, - ClockCircleOutlined, - PictureOutlined, - PlusOutlined, - UploadOutlined, -} from '@ant-design/icons'; - -import { Layout, Menu, Pagination, Radio, Tree } from 'antd'; -import moment from 'moment'; -import { useDispatch, useSelector } from 'react-redux'; -import { collectionActions, photoActions } from '../store/actions'; - -/*****************************/ -//import actions from "../store/actions"; -import SideBar from '../components/sidebar' -import MoveModal from '../components/modal' -import Header from '../components/header' -import AddCollection from '../components/addCollection.jsx' -import UploadPhotos from '../components/upload' -import { galleryActions } from '../store/actions/gallery'; -import { IDFromTree } from '../store'; -import Gallery from '../components/Gallery'; - -const { Content, Sider, Footer } = Layout; -const { SubMenu } = Menu; -const { DirectoryTree } = Tree; - - -const Main = () => { - - const dispatch = useDispatch() - - const { photos } = useSelector(state => state.PhotoReducer) - const { dates, collections } = useSelector(state => state.CollectionsReducer) - const { imageSize } = useSelector(state => state.GalleryReducer) - - const [selectedElements, setSelectedElements] = useState([]) - const [collapsed, setCollapsed] = useState(true) - const [selectedPhoto, setSelectedPhoto] = useState({}) - const [filter, setFilter] = useState("") - const [uploaded_filter, setUploadedFilter] = useState("") - - const [page, setPage] = useState(1); - const [pageSize, setPageSize] = useState(36); - - - useEffect(() => { - dispatch(photoActions.getAll()); - dispatch(collectionActions.getAll()); - }, [dispatch]) - - const selectPhoto = (e, photo) => { - e.stopPropagation(); - setSelectedPhoto(photos.findIndex(x => x.id === photo.id)) - setSelectedElements([photos.findIndex(x => x.id === photo.id)]) - - console.log("Set Selected", selectedPhoto) - } - - const clearSelection = () => { - setSelectedPhoto({}) - console.log("Clear Selected", selectedPhoto) - } - - const onCollapse = collapsed => { - setCollapsed(collapsed) - }; - - const paginate = (items, page = 1, perPage = 10) => { - const offset = perPage * (page - 1); - const totalPages = Math.ceil(items.length / perPage); - const paginatedItems = items.slice(offset, perPage * page); - - return { - previousPage: page - 1 ? page - 1 : null, - nextPage: (totalPages > page) ? page + 1 : null, - total: items.length, - totalPages: totalPages, - items: paginatedItems - }; - }; - - const getStyle = (index) => { - let elements = selectedElements.map(s => photos[s]); - if (elements.find(e => e.id === index) !== undefined) { - // Selected state - return { - border: '3px solid #2185d0', - margin: 0, - textAlign: "center" - }; - } - return { - textAlign: "center" - }; - }; - - const handleSizeChange = (e) => { - switch (e.target.value) { - case "xsmall": - setPageSize(120); - break; - case "small": - setPageSize(36); - break; - case "medium": - setPageSize(16); - break; - case "large": - setPageSize(4); - break; - case "xlarge": - setPageSize(1); - break; - } - dispatch(galleryActions.changeImageSize(e.target.value)) - } - - const onTreeSelect = (selectedKeys, info) => { - console.log('selected', selectedKeys, info); //.node.props.id); - filterPhotos({ - key: selectedKeys[0] - }) - }; - - const filterPhotos = (item, datesList) => { - setPage(1); - switch (item.key) { - case "all": - setFilter("") - setUploadedFilter("") - break; - case "add": - setFilter("") - setUploadedFilter("") - break; - case "upload": - setFilter("") - setUploadedFilter("") - break; - case "uploaded": - setFilter(datesList[0]) - setUploadedFilter("") - break; - default: - if (item.key !== undefined) { - setFilter(item.key) - setUploadedFilter("") - } else { - let name = IDFromTree(collections, item["0"]) - setFilter(name.id) - setUploadedFilter("") - } - break; - } - } - const lowercasedFilter = filter.toLowerCase(); - - const filteredData = photos.filter(item => { - return search(item, uploaded_filter, lowercasedFilter) - }); - - function formatDate(date) { - let formattedDate = moment(date, "YYYY-MM-DD").format("DD-MM-YYYY"); - return formattedDate; - } - - function search(item, uploaded_filter, lowercasedFilter) { - if (uploaded_filter !== "") { - return moment(item.meta["DateAdded"], "YYYY-MM-DD'T'HH:mm:SSZ").format("YYYY-MM-DD HH:mm") === uploaded_filter - } else { - if (item["name"].toLowerCase().includes(lowercasedFilter)) { return true } - if (item["album"].toLowerCase() === (lowercasedFilter)) { return true } - if (item.exif.date_taken.toLowerCase().includes(lowercasedFilter)) { return true } - } - return false - } - - let selectMessage = filteredData.length + " photos" - if (selectedElements.length > 0) { - selectMessage = selectedElements.length + " out of " + filteredData.length + " selected" - } - - let datesList = dates.sort((a, b) => { - var dateA = new Date(a), dateB = new Date(b); - return dateA - dateB; - }).reverse(); - - - let results = paginate(filteredData, page, pageSize) - return ( - - -
- - - filterPhotos(item, datesList)}> - All Content - Last Uploaded - - - Date Captured - - } - > - {datesList.map((el, index) => ({formatDate(el)}))} - - - - Collections - - } - > -
  • - -
  • -
    -
    - - - - - dispatch(galleryActions.showAdd())} key="add" style={{ backgroundColor: "@popover-background", position: "absolute", bottom: 50 }}> Add Collection - dispatch(galleryActions.showUpload())} key="upload" style={{ backgroundColor: "@popover-background", position: "absolute", bottom: 100 }}> Upload - -
    - - - - - - -
    - {selectedElements.length > 0 && } - - { - setPage(page); - }} /> - - - Tiny - Small - Medium - Large - -
    -
    - -
    - - ); - -} - -export default Main; \ No newline at end of file diff --git a/frontend/src/pages/Preview.jsx b/frontend/src/pages/Preview.jsx deleted file mode 100644 index c853695..0000000 --- a/frontend/src/pages/Preview.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import './Main.css'; - -import { Layout } from 'antd'; -import { useDispatch } from 'react-redux'; -import Header from '../components/header' -const { Content } = Layout; - -const Preview = () => { - return ( - -
    - - -