check for duplicate tag names
authorPhiTux <redacted>
Fri, 3 Oct 2025 10:27:38 +0000 (12:27 +0200)
committerPhiTux <redacted>
Fri, 3 Oct 2025 10:27:38 +0000 (12:27 +0200)
backend/handlers/additional.go
frontend/src/lib/Sidenav.svelte
frontend/src/lib/Tag.svelte
frontend/src/routes/(authed)/write/+page.svelte

index 3ff9e5aeb2b8b3ed0888a509c278a2052fcb1999..d2d9d4d650ec9d93c31eb0a2a01f8769fe3cd599 100644 (file)
@@ -1200,6 +1200,29 @@ func SaveTags(w http.ResponseWriter, r *http.Request) {
                return
        }
 
+       // Check for duplicate tag names
+       tags, ok := content["tags"].([]any)
+       if ok {
+               for _, tagInterface := range tags {
+                       tag, ok := tagInterface.(map[string]any)
+                       if !ok {
+                               continue
+                       }
+
+                       if encName, ok := tag["name"].(string); ok {
+                               decryptedName, err := utils.DecryptText(encName, encKey)
+                               if err != nil {
+                                       http.Error(w, fmt.Sprintf("Error decrypting tag name: %v", err), http.StatusInternalServerError)
+                                       return
+                               }
+                               if decryptedName == req.Name {
+                                       http.Error(w, "Tag name already exists", http.StatusBadRequest)
+                                       return
+                               }
+                       }
+               }
+       }
+
        // Encrypt tag data
        encIcon, err := utils.EncryptText(req.Icon, encKey)
        if err != nil {
@@ -1233,7 +1256,7 @@ func SaveTags(w http.ResponseWriter, r *http.Request) {
        }
 
        // Add tag to tags array
-       tags, ok := content["tags"].([]any)
+       tags, ok = content["tags"].([]any)
        if !ok {
                tags = []any{}
        }
index 0601147049016a4f5e37a9f7dd0e66c8edfdb57d..2561b88145c7d95c9d1badedc409bcac1846b67c 100644 (file)
                flex-wrap: wrap;
        }
 
-       .touch-tag-item:active {
-               transform: scale(0.96);
-       }
-
        @media (max-width: 1599px) {
                .searchTagDropdown {
                        left: 58px;
index ea25599a9e203d382151a332cb451e7672615ba1..1730cde7ca19cdf973a8e773b882cc12dd751573 100644 (file)
@@ -18,7 +18,7 @@
        });
 </script>
 
-<span class="badge rounded-pill" style="background-color: {tag.color}; color: {fontColor}">
+<span class="shadow badge rounded-pill" style="background-color: {tag.color}; color: {fontColor}">
        <div class="d-flex flex-row">
                <div>{tag.icon} #{tag.name}</div>
                {#if isEditable}
index 1fa73ff77e1cc3666c4684cdbc2300e9dac53976..65e2cf918b3891be71643e0a9d50b3c40f143482 100644 (file)
                                        toast.show();
                                }
                        })
+                       .catch((error) => {
+                               console.error(error.response);
+                               if (error.response.status == 400) {
+                                       // name already exists
+                                       // toast
+                                       const toast = new bootstrap.Toast(
+                                               document.getElementById('toastErrorSavingNewTagExists')
+                                       );
+                                       toast.show();
+                               } else {
+                                       // toast
+                                       const toast = new bootstrap.Toast(document.getElementById('toastErrorSavingNewTag'));
+                                       toast.show();
+                               }
+                       })
                        .finally(() => {
                                // close modal
                                isSavingNewTag = false;
                        </div>
                </div>
 
+               <div
+                       id="toastErrorSavingNewTagExists"
+                       class="toast align-items-center text-bg-danger"
+                       role="alert"
+                       aria-live="assertive"
+                       aria-atomic="true"
+               >
+                       <div class="d-flex">
+                               <div class="toast-body">
+                                       {$t('tags.toast.error_saving_exists')}
+                               </div>
+                               <button
+                                       type="button"
+                                       class="btn-close me-2 m-auto"
+                                       data-bs-dismiss="toast"
+                                       aria-label="Close"
+                               ></button>
+                       </div>
+               </div>
+
                <div
                        id="toastErrorSavingLog"
                        class="toast align-items-center text-bg-danger"
git clone https://git.99rst.org/PROJECT