Explorar o código

Merge remote-tracking branch 'origin/dev' into dev

Vanessa hai 1 ano
pai
achega
2710c7c2eb

+ 4 - 1
app/appearance/langs/en_US.json

@@ -1,4 +1,6 @@
 {
+  "containerBlockTip1": "Enabling container blocks will result in duplicate search results",
+  "containerBlockTip2": "Enabling document blocks currently only supports searching for document titles",
   "copyAsPNG": "Copy as PNG",
   "unbindBlock": "Unbind block",
   "showTitle": "Show database title",
@@ -1477,6 +1479,7 @@
     "242": "The binding block already exists in the current database",
     "243": "Only list the first [%d] tags (including subtags), if you need to adjust, please modify [Settings - Doc Tree - Maximum number to list]",
     "244": "It did not exit normally after the last use. It is recommended to execute [Doc Tree - Rebuild Index]",
-    "245": "It did not exit normally after the last use. It is recommended to execute [Doc Tree - Rebuild Index]. To exit normally, you need to use [Exit Application] in the right panel"
+    "245": "It did not exit normally after the last use. It is recommended to execute [Doc Tree - Rebuild Index]. To exit normally, you need to use [Exit Application] in the right panel",
+    "246": "The document title cannot contain / and has been replaced with _"
   }
 }

+ 4 - 1
app/appearance/langs/es_ES.json

@@ -1,4 +1,6 @@
 {
+  "containerBlockTip1": "Habilitar bloques de contenedores generará resultados de búsqueda duplicados",
+  "containerBlockTip2": "Habilitar bloques de documentos actualmente solo admite la búsqueda de títulos de documentos",
   "copyAsPNG": "Copiar como PNG",
   "unbindBlock": "Desvincular bloque",
   "showTitle": "Mostrar título de la base de datos",
@@ -1477,6 +1479,7 @@
     "242": "El bloque de enlace ya existe en la base de datos actual",
     "243": "Enumere solo las primeras [%d] etiquetas (incluidas las subetiquetas), modifique [Configuración - Árbol de documentos - Número máximo a listar]",
     "244": "No salió normalmente después del último uso. Se recomienda ejecutar [Árbol de documentos - Reconstruir índice]",
-    "245": "No salió normalmente después del último uso. Se recomienda ejecutar [Árbol de documentos - Reconstruir índice]. Para salir normalmente, necesita usar [Salir de la aplicación] en el panel derecho"
+    "245": "No salió normalmente después del último uso. Se recomienda ejecutar [Árbol de documentos - Reconstruir índice]. Para salir normalmente, necesita usar [Salir de la aplicación] en el panel derecho",
+    "246": "El título del documento no puede contener / y ha sido reemplazado por _"
   }
 }

+ 4 - 1
app/appearance/langs/fr_FR.json

@@ -1,4 +1,6 @@
 {
+  "containerBlockTip1": "L'activation des blocs de conteneurs entraînera des résultats de recherche en double",
+  "containerBlockTip2": "L'activation des blocs de documents ne prend actuellement en charge que la recherche de titres de documents",
   "copyAsPNG": "Copier en tant PNG",
   "unbindBlock": "Dissocier le bloc",
   "showTitle": "Afficher le titre de la base de données",
@@ -1477,6 +1479,7 @@
     "242": "Le bloc de liaison existe déjà dans la base de données actuelle",
     "243": "Répertorier uniquement les [%d] premières balises (y compris les sous-balises). veuillez modifier [Paramètres - Arbre des documents - Nombre maximum de documents à lister].",
     "244": "Il ne s'est pas terminé normalement après la dernière utilisation. Il est recommandé d'exécuter [Doc Tree - Rebuild Index]",
-    "245": "Il ne s'est pas terminé normalement après la dernière utilisation. Il est recommandé d'exécuter [Doc Tree - Rebuild Index]. Pour quitter normalement, vous devez utiliser [Quitter l'application] dans le panneau de droite"
+    "245": "Il ne s'est pas terminé normalement après la dernière utilisation. Il est recommandé d'exécuter [Doc Tree - Rebuild Index]. Pour quitter normalement, vous devez utiliser [Quitter l'application] dans le panneau de droite",
+    "246": "Le titre du document ne peut pas contenir / et a été remplacé par _"
   }
 }

+ 4 - 1
app/appearance/langs/zh_CHT.json

@@ -1,4 +1,6 @@
 {
+  "containerBlockTip1": "啟用容器區塊後會導致搜尋結果重複",
+  "containerBlockTip2": "啟用文件區塊目前僅支援搜尋文件名稱",
   "copyAsPNG": "複製為 PNG",
   "unbindBlock": "取消綁定區塊",
   "showTitle": "顯示資料庫標題",
@@ -1477,6 +1479,7 @@
     "242": "目前資料庫中已經存在該綁定區塊",
     "243": "僅列出前 [%d] 個標籤(含子標籤),如需調整請修改 [設置 - 文檔樹 - 最大列出數量]",
     "244": "上次使用後未正常退出,建議執行一次 [文檔樹 - 重建索引]",
-    "245": "上次使用後未正常退出,建議執行一次 [文件樹 - 重建索引],正常退出需使用右側欄面板中的 [退出應用]"
+    "245": "上次使用後未正常退出,建議執行一次 [文件樹 - 重建索引],正常退出需使用右側欄面板中的 [退出應用]",
+    "246": "文件標題不能包含 /,已經使用 _ 替換"
   }
 }

+ 4 - 1
app/appearance/langs/zh_CN.json

@@ -1,4 +1,6 @@
 {
+  "containerBlockTip1": "启用容器块后会导致搜索结果重复",
+  "containerBlockTip2": "启用文档块目前仅支持搜索文档名",
   "copyAsPNG": "复制为 PNG",
   "unbindBlock": "取消绑定块",
   "showTitle": "显示数据库标题",
@@ -1477,6 +1479,7 @@
     "242": "当前数据库中已经存在该绑定块",
     "243": "仅列出前 [%d] 个标签(含子标签),如需调整请修改 [设置 - 文档树 - 最大列出数量]",
     "244": "上次使用后未正常退出,建议执行一次 [文档树 - 重建索引]",
-    "245": "上次使用后未正常退出,建议执行一次 [文档树 - 重建索引],正常退出需使用右侧栏面板中的 [退出应用]"
+    "245": "上次使用后未正常退出,建议执行一次 [文档树 - 重建索引],正常退出需使用右侧栏面板中的 [退出应用]",
+    "246": "文档标题不能包含 /,已经使用 _ 替换"
   }
 }

+ 51 - 46
app/src/config/query.ts

@@ -25,141 +25,146 @@ export const query = {
             <input class="b3-switch" id="table" type="checkbox"${window.siyuan.config.search.table ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconQuote"></use></svg>
+            <svg class="svg"><use xlink:href="#iconParagraph"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.quote}
+                ${window.siyuan.languages.paragraph}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="blockquote" type="checkbox"${window.siyuan.config.search.blockquote ? " checked" : ""}/>
+            <input class="b3-switch" id="paragraph" type="checkbox"${window.siyuan.config.search.paragraph ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconSuper"></use></svg>
+            <svg class="svg"><use xlink:href="#iconHeadings"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.superBlock}
+                ${window.siyuan.languages.headings}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="superBlock" type="checkbox"${window.siyuan.config.search.superBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="heading" type="checkbox"${window.siyuan.config.search.heading ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconParagraph"></use></svg>
+            <svg class="svg"><use xlink:href="#iconCode"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.paragraph}
+                ${window.siyuan.languages.code}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="paragraph" type="checkbox"${window.siyuan.config.search.paragraph ? " checked" : ""}/>
+            <input class="b3-switch" id="codeBlock" type="checkbox"${window.siyuan.config.search.codeBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconFile"></use></svg>
+            <svg class="svg"><use xlink:href="#iconHTML5"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.doc}
+                HTML
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="document" type="checkbox"${window.siyuan.config.search.document ? " checked" : ""}/>
+            <input class="b3-switch" id="htmlBlock" type="checkbox"${window.siyuan.config.search.htmlBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconHeadings"></use></svg>
+            <svg class="svg"><use xlink:href="#iconDatabase"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.headings}
+                ${window.siyuan.languages.database}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="heading" type="checkbox"${window.siyuan.config.search.heading ? " checked" : ""}/>
-        </label>
+            <input class="b3-switch" id="databaseBlock" type="checkbox"${window.siyuan.config.search.databaseBlock ? " checked" : ""}/>
+        </label>        
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconList"></use></svg>
+            <svg class="svg"><use xlink:href="#iconSQL"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.list1}
+                ${window.siyuan.languages.embedBlock}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="list" type="checkbox"${window.siyuan.config.search.list ? " checked" : ""}/>
+            <input class="b3-switch" id="embedBlock" type="checkbox"${window.siyuan.config.search.embedBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconListItem"></use></svg>
+            <svg class="svg"><use xlink:href="#iconVideo"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.listItem}
+                ${window.siyuan.languages.video}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="listItem" type="checkbox"${window.siyuan.config.search.listItem ? " checked" : ""}/>
+            <input class="b3-switch" id="videoBlock" type="checkbox"${window.siyuan.config.search.videoBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconCode"></use></svg>
+            <svg class="svg"><use xlink:href="#iconRecord"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.code}
+                ${window.siyuan.languages.audio}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="codeBlock" type="checkbox"${window.siyuan.config.search.codeBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="audioBlock" type="checkbox"${window.siyuan.config.search.audioBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconHTML5"></use></svg>
+            <svg class="svg"><use xlink:href="#iconLanguage"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                HTML
+                IFrame
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="htmlBlock" type="checkbox"${window.siyuan.config.search.htmlBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="iframeBlock" type="checkbox"${window.siyuan.config.search.iframeBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconSQL"></use></svg>
+            <svg class="svg"><use xlink:href="#iconBoth"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.embedBlock}
+                ${window.siyuan.languages.widget}
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="embedBlock" type="checkbox"${window.siyuan.config.search.embedBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="widgetBlock" type="checkbox"${window.siyuan.config.search.widgetBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconDatabase"></use></svg>
+            <svg class="svg"><use xlink:href="#iconQuote"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.database}
+                ${window.siyuan.languages.quote} <sup>[1]</sup>
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="databaseBlock" type="checkbox"${window.siyuan.config.search.databaseBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="blockquote" type="checkbox"${window.siyuan.config.search.blockquote ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconVideo"></use></svg>
+            <svg class="svg"><use xlink:href="#iconSuper"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.video}
+                ${window.siyuan.languages.superBlock} <sup>[1]</sup>
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="videoBlock" type="checkbox"${window.siyuan.config.search.videoBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="superBlock" type="checkbox"${window.siyuan.config.search.superBlock ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconRecord"></use></svg>
+            <svg class="svg"><use xlink:href="#iconList"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.audio}
+                ${window.siyuan.languages.list1} <sup>[1]</sup>
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="audioBlock" type="checkbox"${window.siyuan.config.search.audioBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="list" type="checkbox"${window.siyuan.config.search.list ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconLanguage"></use></svg>
+            <svg class="svg"><use xlink:href="#iconListItem"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                IFrame
+                ${window.siyuan.languages.listItem} <sup>[1]</sup>
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="iframeBlock" type="checkbox"${window.siyuan.config.search.iframeBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="listItem" type="checkbox"${window.siyuan.config.search.listItem ? " checked" : ""}/>
         </label>
         <label class="fn__flex">
-            <svg class="svg"><use xlink:href="#iconBoth"></use></svg>
+            <svg class="svg"><use xlink:href="#iconFile"></use></svg>
             <span class="fn__space"></span>
             <div class="fn__flex-1">
-                ${window.siyuan.languages.widget}
+                ${window.siyuan.languages.doc} <sup>[1] [2]</sup>
             </div>
             <span class="fn__space"></span>
-            <input class="b3-switch" id="widgetBlock" type="checkbox"${window.siyuan.config.search.widgetBlock ? " checked" : ""}/>
+            <input class="b3-switch" id="document" type="checkbox"${window.siyuan.config.search.document ? " checked" : ""}/>
         </label>
     </div>
+    <span class="fn__space"></span>
+    <div class="fn__flex-1">
+        <div class="b3-label__text">[1] ${window.siyuan.languages.containerBlockTip1}</div>
+        <div class="b3-label__text">[2] ${window.siyuan.languages.containerBlockTip2}</div>
+    </div>
 </div>
 <div class="b3-label">
  ${window.siyuan.languages.searchBlockAttr}

+ 51 - 46
app/src/search/menu.ts

@@ -32,140 +32,145 @@ export const filterMenu = (config: Config.IUILayoutTabSearchConfig, cb: () => vo
         <input class="b3-switch fn__flex-center" data-type="table" type="checkbox"${config.types.table ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconQuote"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconParagraph"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.quote}
+            ${window.siyuan.languages.paragraph}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="blockquote" type="checkbox"${config.types.blockquote ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="paragraph" type="checkbox"${config.types.paragraph ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconSuper"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconHeadings"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.superBlock}
+            ${window.siyuan.languages.headings}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="superBlock" type="checkbox"${config.types.superBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="heading" type="checkbox"${config.types.heading ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconParagraph"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconCode"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.paragraph}
+            ${window.siyuan.languages.code}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="paragraph" type="checkbox"${config.types.paragraph ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="codeBlock" type="checkbox"${config.types.codeBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconFile"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconHTML5"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.doc}
+            HTML
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="document" type="checkbox"${config.types.document ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="htmlBlock" type="checkbox"${config.types.htmlBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconHeadings"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconDatabase"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.headings}
+            ${window.siyuan.languages.database}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="heading" type="checkbox"${config.types.heading ? " checked" : ""}>
-    </label>
+        <input class="b3-switch fn__flex-center" data-type="databaseBlock" type="checkbox"${config.types.databaseBlock ? " checked" : ""}>
+    </label>    
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconList"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconSQL"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.list1}
+            ${window.siyuan.languages.embedBlock}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="list" type="checkbox"${config.types.list ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="embedBlock" type="checkbox"${config.types.embedBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconListItem"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconVideo"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.listItem}
+            ${window.siyuan.languages.video}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="listItem" type="checkbox"${config.types.listItem ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="videoBlock" type="checkbox"${config.types.videoBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconCode"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconRecord"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.code}
+            ${window.siyuan.languages.audio}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="codeBlock" type="checkbox"${config.types.codeBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="audioBlock" type="checkbox"${config.types.audioBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconHTML5"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconLanguage"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            HTML
+            IFrame
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="htmlBlock" type="checkbox"${config.types.htmlBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="iframeBlock" type="checkbox"${config.types.iframeBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconSQL"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconBoth"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.embedBlock}
+            ${window.siyuan.languages.widget}
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="embedBlock" type="checkbox"${config.types.embedBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="widgetBlock" type="checkbox"${config.types.widgetBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconDatabase"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconQuote"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.database}
+            ${window.siyuan.languages.quote} <sup>[1]</sup>
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="databaseBlock" type="checkbox"${config.types.databaseBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="blockquote" type="checkbox"${config.types.blockquote ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconVideo"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconSuper"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.video}
+            ${window.siyuan.languages.superBlock} <sup>[1]</sup>
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="videoBlock" type="checkbox"${config.types.videoBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="superBlock" type="checkbox"${config.types.superBlock ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconRecord"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconList"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.audio}
+            ${window.siyuan.languages.list1} <sup>[1]</sup>
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="audioBlock" type="checkbox"${config.types.audioBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="list" type="checkbox"${config.types.list ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconLanguage"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconListItem"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            IFrame
+            ${window.siyuan.languages.listItem} <sup>[1]</sup>
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="iframeBlock" type="checkbox"${config.types.iframeBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="listItem" type="checkbox"${config.types.listItem ? " checked" : ""}>
     </label>
     <label class="fn__flex b3-label">
-        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconBoth"></use></svg>
+        <svg class="ft__on-surface svg fn__flex-center"><use xlink:href="#iconFile"></use></svg>
         <span class="fn__space"></span>
         <div class="fn__flex-1 fn__flex-center">
-            ${window.siyuan.languages.widget}
+            ${window.siyuan.languages.doc} <sup>[1] [2]</sup>
         </div>
         <span class="fn__space"></span>
-        <input class="b3-switch fn__flex-center" data-type="widgetBlock" type="checkbox"${config.types.widgetBlock ? " checked" : ""}>
+        <input class="b3-switch fn__flex-center" data-type="document" type="checkbox"${config.types.document ? " checked" : ""}>
     </label>
+    <span class="fn__space"></span>
+    <div class="fn__flex-1">
+        <div class="b3-label__text">[1] ${window.siyuan.languages.containerBlockTip1}</div>
+        <div class="b3-label__text">[2] ${window.siyuan.languages.containerBlockTip2}</div>
+    </div>    
 </div>
 <div class="b3-dialog__action">
     <button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div>

+ 1 - 1
kernel/api/asset.go

@@ -82,7 +82,7 @@ func statAsset(c *gin.Context) {
 
 	ret.Data = map[string]interface{}{
 		"size":     info.Size(),
-		"hSize":    humanize.Bytes(uint64(info.Size())),
+		"hSize":    humanize.BytesCustomCeil(uint64(info.Size()), 2),
 		"created":  created,
 		"hCreated": hCreated,
 		"updated":  updated,

+ 2 - 2
kernel/bazaar/icon.go

@@ -88,7 +88,7 @@ func Icons() (icons []*Icon) {
 		icon.Stars = repo.Stars
 		icon.OpenIssues = repo.OpenIssues
 		icon.Size = repo.Size
-		icon.HSize = humanize.Bytes(uint64(icon.Size))
+		icon.HSize = humanize.BytesCustomCeil(uint64(icon.Size), 2)
 		icon.HUpdated = formatUpdated(icon.Updated)
 		pkg := bazaarIndex[strings.Split(repoURL, "@")[0]]
 		if nil != pkg {
@@ -158,7 +158,7 @@ func InstalledIcons() (ret []*Icon) {
 		icon.HInstallDate = info.ModTime().Format("2006-01-02")
 		installSize, _ := util.SizeOfDirectory(installPath)
 		icon.InstallSize = installSize
-		icon.HInstallSize = humanize.Bytes(uint64(installSize))
+		icon.HInstallSize = humanize.BytesCustomCeil(uint64(installSize), 2)
 		readmeFilename := getPreferredReadme(icon.Readme)
 		readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
 		if nil != readErr {

+ 2 - 2
kernel/bazaar/plugin.go

@@ -93,7 +93,7 @@ func Plugins(frontend string) (plugins []*Plugin) {
 		plugin.Stars = repo.Stars
 		plugin.OpenIssues = repo.OpenIssues
 		plugin.Size = repo.Size
-		plugin.HSize = humanize.Bytes(uint64(plugin.Size))
+		plugin.HSize = humanize.BytesCustomCeil(uint64(plugin.Size), 2)
 		plugin.HUpdated = formatUpdated(plugin.Updated)
 		pkg := bazaarIndex[strings.Split(repoURL, "@")[0]]
 		if nil != pkg {
@@ -196,7 +196,7 @@ func InstalledPlugins(frontend string, checkUpdate bool) (ret []*Plugin) {
 		plugin.HInstallDate = info.ModTime().Format("2006-01-02")
 		installSize, _ := util.SizeOfDirectory(installPath)
 		plugin.InstallSize = installSize
-		plugin.HInstallSize = humanize.Bytes(uint64(installSize))
+		plugin.HInstallSize = humanize.BytesCustomCeil(uint64(installSize), 2)
 		readmeFilename := getPreferredReadme(plugin.Readme)
 		readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
 		if nil != readErr {

+ 2 - 2
kernel/bazaar/template.go

@@ -89,7 +89,7 @@ func Templates() (templates []*Template) {
 		template.Stars = repo.Stars
 		template.OpenIssues = repo.OpenIssues
 		template.Size = repo.Size
-		template.HSize = humanize.Bytes(uint64(template.Size))
+		template.HSize = humanize.BytesCustomCeil(uint64(template.Size), 2)
 		template.HUpdated = formatUpdated(template.Updated)
 		pkg := bazaarIndex[strings.Split(repoURL, "@")[0]]
 		if nil != pkg {
@@ -159,7 +159,7 @@ func InstalledTemplates() (ret []*Template) {
 		template.HInstallDate = info.ModTime().Format("2006-01-02")
 		installSize, _ := util.SizeOfDirectory(installPath)
 		template.InstallSize = installSize
-		template.HInstallSize = humanize.Bytes(uint64(installSize))
+		template.HInstallSize = humanize.BytesCustomCeil(uint64(installSize), 2)
 		readmeFilename := getPreferredReadme(template.Readme)
 		readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
 		if nil != readErr {

+ 2 - 2
kernel/bazaar/theme.go

@@ -90,7 +90,7 @@ func Themes() (ret []*Theme) {
 		theme.Stars = repo.Stars
 		theme.OpenIssues = repo.OpenIssues
 		theme.Size = repo.Size
-		theme.HSize = humanize.Bytes(uint64(theme.Size))
+		theme.HSize = humanize.BytesCustomCeil(uint64(theme.Size), 2)
 		theme.HUpdated = formatUpdated(theme.Updated)
 		pkg := bazaarIndex[strings.Split(repoURL, "@")[0]]
 		if nil != pkg {
@@ -160,7 +160,7 @@ func InstalledThemes() (ret []*Theme) {
 		theme.HInstallDate = info.ModTime().Format("2006-01-02")
 		installSize, _ := util.SizeOfDirectory(installPath)
 		theme.InstallSize = installSize
-		theme.HInstallSize = humanize.Bytes(uint64(installSize))
+		theme.HInstallSize = humanize.BytesCustomCeil(uint64(installSize), 2)
 		readmeFilename := getPreferredReadme(theme.Readme)
 		readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
 		if nil != readErr {

+ 2 - 2
kernel/bazaar/widget.go

@@ -89,7 +89,7 @@ func Widgets() (widgets []*Widget) {
 		widget.Stars = repo.Stars
 		widget.OpenIssues = repo.OpenIssues
 		widget.Size = repo.Size
-		widget.HSize = humanize.Bytes(uint64(widget.Size))
+		widget.HSize = humanize.BytesCustomCeil(uint64(widget.Size), 2)
 		widget.HUpdated = formatUpdated(widget.Updated)
 		pkg := bazaarIndex[strings.Split(repoURL, "@")[0]]
 		if nil != pkg {
@@ -157,7 +157,7 @@ func InstalledWidgets() (ret []*Widget) {
 		widget.HInstallDate = info.ModTime().Format("2006-01-02")
 		installSize, _ := util.SizeOfDirectory(installPath)
 		widget.InstallSize = installSize
-		widget.HInstallSize = humanize.Bytes(uint64(installSize))
+		widget.HInstallSize = humanize.BytesCustomCeil(uint64(installSize), 2)
 		readmeFilename := getPreferredReadme(widget.Readme)
 		readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
 		if nil != readErr {

+ 3 - 2
kernel/go.mod

@@ -83,10 +83,11 @@ require (
 	github.com/andybalholm/cascadia v1.3.2 // indirect
 	github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef // indirect
 	github.com/aws/aws-sdk-go v1.51.27 // indirect
-	github.com/bytedance/sonic v1.11.5-alpha3 // indirect
+	github.com/bytedance/sonic v1.11.6 // indirect
+	github.com/bytedance/sonic/loader v0.1.1 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/cloudflare/circl v1.3.7 // indirect
-	github.com/cloudwego/base64x v0.1.2 // indirect
+	github.com/cloudwego/base64x v0.1.4 // indirect
 	github.com/cloudwego/iasm v0.2.0 // indirect
 	github.com/dlclark/regexp2 v1.11.0 // indirect
 	github.com/dsnet/compress v0.0.1 // indirect

+ 6 - 5
kernel/go.sum

@@ -52,16 +52,17 @@ github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef h1:2JGTg6JapxP
 github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII=
 github.com/aws/aws-sdk-go v1.51.27 h1:ZprksHovT4rFfNBHB+Bc/0p4PTntAnTlZP39DMA/Qp8=
 github.com/aws/aws-sdk-go v1.51.27/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
-github.com/bytedance/sonic v1.11.5-alpha3 h1:sxepBMt+5mb0YQZOAzXYOiUQ5D4+EWqOfnklxyZRofQ=
-github.com/bytedance/sonic v1.11.5-alpha3/go.mod h1:NYwWBqBszgmWi7sDnT+p6Yj1Jwf2gzpN0UY7R3VYH+c=
+github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
+github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
+github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
 github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
-github.com/cloudwego/base64x v0.1.2-alpha3/go.mod h1:jSIw/Ru6lyma8wP6MbQJ+7ZAgXkHthTuuClUTUxcYwY=
-github.com/cloudwego/base64x v0.1.2 h1:+/5aoq3u+nG+oaQRlnFg/oWu788X6KzDpquxoNJ6Vt0=
-github.com/cloudwego/base64x v0.1.2/go.mod h1:jSIw/Ru6lyma8wP6MbQJ+7ZAgXkHthTuuClUTUxcYwY=
+github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
+github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
 github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
 github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
 github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=

+ 5 - 5
kernel/model/asset_content.go

@@ -236,7 +236,7 @@ func fromSQLAssetContent(assetContent *sql.AssetContent, beforeLen int) *AssetCo
 		Ext:     assetContent.Ext,
 		Path:    assetContent.Path,
 		Size:    assetContent.Size,
-		HSize:   humanize.Bytes(uint64(assetContent.Size)),
+		HSize:   humanize.BytesCustomCeil(uint64(assetContent.Size), 2),
 		Updated: assetContent.Updated,
 		Content: content,
 	}
@@ -508,7 +508,7 @@ func (parser *TxtAssetParser) Parse(absPath string) (ret *AssetParseResult) {
 	}
 
 	if TxtAssetContentMaxSize < info.Size() {
-		logging.LogWarnf("text asset [%s] is too large [%s]", absPath, humanize.Bytes(uint64(info.Size())))
+		logging.LogWarnf("text asset [%s] is too large [%s]", absPath, humanize.BytesCustomCeil(uint64(info.Size()), 2))
 		return
 	}
 
@@ -836,16 +836,16 @@ func (parser *PdfAssetParser) Parse(absPath string) (ret *AssetParseResult) {
 		if maxSize, parseErr := strconv.ParseUint(maxSizeVal, 10, 64); nil == parseErr {
 			if maxSize != PDFAssetContentMaxSize {
 				PDFAssetContentMaxSize = maxSize
-				logging.LogInfof("set PDF asset content index max size to [%s]", humanize.Bytes(maxSize))
+				logging.LogInfof("set PDF asset content index max size to [%s]", humanize.BytesCustomCeil(maxSize, 2))
 			}
 		} else {
-			logging.LogWarnf("invalid env [SIYUAN_PDF_ASSET_CONTENT_INDEX_MAX_SIZE]: [%s], parsing failed: ", maxSizeVal, parseErr)
+			logging.LogWarnf("invalid env [SIYUAN_PDF_ASSET_CONTENT_INDEX_MAX_SIZE]: [%s], parsing failed: %s", maxSizeVal, parseErr)
 		}
 	}
 
 	if PDFAssetContentMaxSize < uint64(len(pdfData)) {
 		// PDF files larger than 128MB are not included in asset file content searching https://github.com/siyuan-note/siyuan/issues/9500
-		logging.LogWarnf("ignore large PDF asset [%s] with [%s]", absPath, humanize.Bytes(uint64(len(pdfData))))
+		logging.LogWarnf("ignore large PDF asset [%s] with [%s]", absPath, humanize.BytesCustomCeil(uint64(len(pdfData)), 2))
 		return
 	}
 

+ 1 - 1
kernel/model/box.go

@@ -73,7 +73,7 @@ func StatJob() {
 	Conf.m.Unlock()
 	Conf.Save()
 
-	logging.LogInfof("auto stat [trees=%d, blocks=%d, dataSize=%s, assetsSize=%s]", Conf.Stat.TreeCount, Conf.Stat.BlockCount, humanize.Bytes(uint64(Conf.Stat.DataSize)), humanize.Bytes(uint64(Conf.Stat.AssetsSize)))
+	logging.LogInfof("auto stat [trees=%d, blocks=%d, dataSize=%s, assetsSize=%s]", Conf.Stat.TreeCount, Conf.Stat.BlockCount, humanize.BytesCustomCeil(uint64(Conf.Stat.DataSize), 2), humanize.BytesCustomCeil(uint64(Conf.Stat.AssetsSize), 2))
 
 	// 桌面端检查磁盘可用空间 https://github.com/siyuan-note/siyuan/issues/6873
 	if util.ContainerStd != util.Container {

+ 1 - 1
kernel/model/conf.go

@@ -851,7 +851,7 @@ func InitBoxes() {
 
 	var dbSize string
 	if dbFile, err := os.Stat(util.DBPath); nil == err {
-		dbSize = humanize.Bytes(uint64(dbFile.Size()))
+		dbSize = humanize.BytesCustomCeil(uint64(dbFile.Size()), 2)
 	}
 	logging.LogInfof("database size [%s], tree/block count [%d/%d]", dbSize, treenode.CountTrees(), treenode.CountBlocks())
 }

+ 1 - 1
kernel/model/file.go

@@ -90,7 +90,7 @@ func (box *Box) docFromFileInfo(fileInfo *FileInfo, ial map[string]string) (ret
 	t, _ := time.ParseInLocation("20060102150405", ret.ID[:14], time.Local)
 	ret.CTime = t.Unix()
 	ret.HCtime = t.Format("2006-01-02 15:04:05")
-	ret.HSize = humanize.Bytes(ret.Size)
+	ret.HSize = humanize.BytesCustomCeil(ret.Size, 2)
 
 	mTime := t
 	if updated := ial["updated"]; "" != updated {

+ 4 - 1
kernel/model/heading.go

@@ -287,7 +287,10 @@ func Heading2Doc(srcHeadingID, targetBoxID, targetPath string) (srcRootBlockID,
 
 	box := Conf.Box(targetBoxID)
 	headingText := getNodeRefText0(headingNode)
-	headingText = util.FilterFileName(headingText)
+	if strings.Contains(headingText, "/") {
+		headingText = strings.ReplaceAll(headingText, "/", "_")
+		util.PushMsg(Conf.language(246), 7000)
+	}
 
 	moveToRoot := "/" == targetPath
 	toHP := path.Join("/", headingText)

+ 1 - 1
kernel/model/index.go

@@ -203,7 +203,7 @@ func index(boxID string) {
 	box.UpdateHistoryGenerated() // 初始化历史生成时间为当前时间
 	end := time.Now()
 	elapsed := end.Sub(start).Seconds()
-	logging.LogInfof("rebuilt database for notebook [%s] in [%.2fs], tree [count=%d, size=%s]", box.ID, elapsed, treeCount, humanize.Bytes(uint64(treeSize)))
+	logging.LogInfof("rebuilt database for notebook [%s] in [%.2fs], tree [count=%d, size=%s]", box.ID, elapsed, treeCount, humanize.BytesCustomCeil(uint64(treeSize), 2))
 	debug.FreeOSMemory()
 	return
 }

+ 2 - 2
kernel/model/ocr.go

@@ -136,7 +136,7 @@ func LoadAssetsTexts() {
 	debug.FreeOSMemory()
 
 	if elapsed := time.Since(start).Seconds(); 2 < elapsed {
-		logging.LogWarnf("read assets texts [%s] to [%s], elapsed [%.2fs]", humanize.Bytes(uint64(len(data))), assetsTextsPath, elapsed)
+		logging.LogWarnf("read assets texts [%s] to [%s], elapsed [%.2fs]", humanize.BytesCustomCeil(uint64(len(data)), 2), assetsTextsPath, elapsed)
 	}
 	return
 }
@@ -165,7 +165,7 @@ func SaveAssetsTexts() {
 	debug.FreeOSMemory()
 
 	if elapsed := time.Since(start).Seconds(); 2 < elapsed {
-		logging.LogWarnf("save assets texts [size=%s] to [%s], elapsed [%.2fs]", humanize.Bytes(uint64(len(data))), assetsTextsPath, elapsed)
+		logging.LogWarnf("save assets texts [size=%s] to [%s], elapsed [%.2fs]", humanize.BytesCustomCeil(uint64(len(data)), 2), assetsTextsPath, elapsed)
 	}
 
 	util.AssetsTextsChanged.Store(false)

+ 20 - 20
kernel/model/repository.go

@@ -233,7 +233,7 @@ func DiffRepoSnapshots(left, right string) (ret *LeftRightDiff, err error) {
 			FileID:  removeRight.ID,
 			Title:   title,
 			Path:    removeRight.Path,
-			HSize:   humanize.Bytes(uint64(removeRight.Size)),
+			HSize:   humanize.BytesCustomCeil(uint64(removeRight.Size), 2),
 			Updated: removeRight.Updated,
 		})
 	}
@@ -251,7 +251,7 @@ func DiffRepoSnapshots(left, right string) (ret *LeftRightDiff, err error) {
 			FileID:  addLeft.ID,
 			Title:   title,
 			Path:    addLeft.Path,
-			HSize:   humanize.Bytes(uint64(addLeft.Size)),
+			HSize:   humanize.BytesCustomCeil(uint64(addLeft.Size), 2),
 			Updated: addLeft.Updated,
 		})
 	}
@@ -269,7 +269,7 @@ func DiffRepoSnapshots(left, right string) (ret *LeftRightDiff, err error) {
 			FileID:  updateLeft.ID,
 			Title:   title,
 			Path:    updateLeft.Path,
-			HSize:   humanize.Bytes(uint64(updateLeft.Size)),
+			HSize:   humanize.BytesCustomCeil(uint64(updateLeft.Size), 2),
 			Updated: updateLeft.Updated,
 		})
 	}
@@ -287,7 +287,7 @@ func DiffRepoSnapshots(left, right string) (ret *LeftRightDiff, err error) {
 			FileID:  updateRight.ID,
 			Title:   title,
 			Path:    updateRight.Path,
-			HSize:   humanize.Bytes(uint64(updateRight.Size)),
+			HSize:   humanize.BytesCustomCeil(uint64(updateRight.Size), 2),
 			Updated: updateRight.Updated,
 		})
 	}
@@ -500,7 +500,7 @@ func PurgeCloud() (err error) {
 
 	deletedIndexes := stat.Indexes
 	deletedObjects := stat.Objects
-	deletedSize := humanize.Bytes(uint64(stat.Size))
+	deletedSize := humanize.BytesCustomCeil(uint64(stat.Size), 2)
 	msg = fmt.Sprintf(Conf.Language(232), deletedIndexes, deletedObjects, deletedSize)
 	util.PushMsg(msg, 5000)
 	return
@@ -523,7 +523,7 @@ func PurgeRepo() (err error) {
 
 	deletedIndexes := stat.Indexes
 	deletedObjects := stat.Objects
-	deletedSize := humanize.Bytes(uint64(stat.Size))
+	deletedSize := humanize.BytesCustomCeil(uint64(stat.Size), 2)
 	msg = fmt.Sprintf(Conf.Language(203), deletedIndexes, deletedObjects, deletedSize)
 	util.PushMsg(msg, 5000)
 	return
@@ -696,7 +696,7 @@ func DownloadCloudSnapshot(tag, id string) (err error) {
 	if nil != err {
 		return
 	}
-	msg := fmt.Sprintf(Conf.Language(153), downloadFileCount, downloadChunkCount, humanize.Bytes(uint64(downloadBytes)))
+	msg := fmt.Sprintf(Conf.Language(153), downloadFileCount, downloadChunkCount, humanize.BytesCustomCeil(uint64(downloadBytes), 2))
 	util.PushMsg(msg, 5000)
 	util.PushStatusBar(msg)
 	return
@@ -737,7 +737,7 @@ func UploadCloudSnapshot(tag, id string) (err error) {
 		err = errors.New(fmt.Sprintf(Conf.Language(84), formatRepoErrorMsg(err)))
 		return
 	}
-	msg := fmt.Sprintf(Conf.Language(152), uploadFileCount, uploadChunkCount, humanize.Bytes(uint64(uploadBytes)))
+	msg := fmt.Sprintf(Conf.Language(152), uploadFileCount, uploadChunkCount, humanize.BytesCustomCeil(uint64(uploadBytes), 2))
 	util.PushMsg(msg, 5000)
 	util.PushStatusBar(msg)
 	return
@@ -1039,9 +1039,9 @@ func syncRepoDownload() (err error) {
 		msg := fmt.Sprintf(Conf.Language(80), formatRepoErrorMsg(err))
 		if errors.Is(err, dejavu.ErrCloudStorageSizeExceeded) {
 			u := Conf.GetUser()
-			msg = fmt.Sprintf(Conf.Language(43), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+			msg = fmt.Sprintf(Conf.Language(43), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			if 2 == u.UserSiYuanSubscriptionPlan {
-				msg = fmt.Sprintf(Conf.Language(68), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+				msg = fmt.Sprintf(Conf.Language(68), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			}
 		}
 		Conf.Sync.Stat = msg
@@ -1053,7 +1053,7 @@ func syncRepoDownload() (err error) {
 
 	util.PushStatusBar(fmt.Sprintf(Conf.Language(149), elapsed.Seconds()))
 	Conf.Sync.Synced = util.CurrentTimeMillis()
-	msg := fmt.Sprintf(Conf.Language(150), trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.Bytes(uint64(trafficStat.UploadBytes)), humanize.Bytes(uint64(trafficStat.DownloadBytes)))
+	msg := fmt.Sprintf(Conf.Language(150), trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.BytesCustomCeil(uint64(trafficStat.UploadBytes), 2), humanize.BytesCustomFloor(uint64(trafficStat.DownloadBytes), 2))
 	Conf.Sync.Stat = msg
 	Conf.Save()
 	autoSyncErrCount = 0
@@ -1110,9 +1110,9 @@ func syncRepoUpload() (err error) {
 		msg := fmt.Sprintf(Conf.Language(80), formatRepoErrorMsg(err))
 		if errors.Is(err, dejavu.ErrCloudStorageSizeExceeded) {
 			u := Conf.GetUser()
-			msg = fmt.Sprintf(Conf.Language(43), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+			msg = fmt.Sprintf(Conf.Language(43), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			if 2 == u.UserSiYuanSubscriptionPlan {
-				msg = fmt.Sprintf(Conf.Language(68), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+				msg = fmt.Sprintf(Conf.Language(68), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			}
 		}
 		Conf.Sync.Stat = msg
@@ -1124,7 +1124,7 @@ func syncRepoUpload() (err error) {
 
 	util.PushStatusBar(fmt.Sprintf(Conf.Language(149), elapsed.Seconds()))
 	Conf.Sync.Synced = util.CurrentTimeMillis()
-	msg := fmt.Sprintf(Conf.Language(150), trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.Bytes(uint64(trafficStat.UploadBytes)), humanize.Bytes(uint64(trafficStat.DownloadBytes)))
+	msg := fmt.Sprintf(Conf.Language(150), trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.BytesCustomCeil(uint64(trafficStat.UploadBytes), 2), humanize.BytesCustomCeil(uint64(trafficStat.DownloadBytes), 2))
 	Conf.Sync.Stat = msg
 	Conf.Save()
 	autoSyncErrCount = 0
@@ -1218,9 +1218,9 @@ func bootSyncRepo() (err error) {
 		msg := fmt.Sprintf(Conf.Language(80), formatRepoErrorMsg(err))
 		if errors.Is(err, dejavu.ErrCloudStorageSizeExceeded) {
 			u := Conf.GetUser()
-			msg = fmt.Sprintf(Conf.Language(43), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+			msg = fmt.Sprintf(Conf.Language(43), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			if 2 == u.UserSiYuanSubscriptionPlan {
-				msg = fmt.Sprintf(Conf.Language(68), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+				msg = fmt.Sprintf(Conf.Language(68), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			}
 		}
 		Conf.Sync.Stat = msg
@@ -1303,9 +1303,9 @@ func syncRepo(exit, byHand bool) (dataChanged bool, err error) {
 		msg := fmt.Sprintf(Conf.Language(80), formatRepoErrorMsg(err))
 		if errors.Is(err, dejavu.ErrCloudStorageSizeExceeded) {
 			u := Conf.GetUser()
-			msg = fmt.Sprintf(Conf.Language(43), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+			msg = fmt.Sprintf(Conf.Language(43), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			if 2 == u.UserSiYuanSubscriptionPlan {
-				msg = fmt.Sprintf(Conf.Language(68), humanize.Bytes(uint64(u.UserSiYuanRepoSize)))
+				msg = fmt.Sprintf(Conf.Language(68), humanize.BytesCustomCeil(uint64(u.UserSiYuanRepoSize), 2))
 			}
 		}
 		Conf.Sync.Stat = msg
@@ -1324,7 +1324,7 @@ func syncRepo(exit, byHand bool) (dataChanged bool, err error) {
 
 	util.PushStatusBar(fmt.Sprintf(Conf.Language(149), elapsed.Seconds()))
 	Conf.Sync.Synced = util.CurrentTimeMillis()
-	msg := fmt.Sprintf(Conf.Language(150), trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.Bytes(uint64(trafficStat.UploadBytes)), humanize.Bytes(uint64(trafficStat.DownloadBytes)))
+	msg := fmt.Sprintf(Conf.Language(150), trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.BytesCustomCeil(uint64(trafficStat.UploadBytes), 2), humanize.BytesCustomCeil(uint64(trafficStat.DownloadBytes), 2))
 	Conf.Sync.Stat = msg
 	Conf.Save()
 	autoSyncErrCount = 0
@@ -1341,7 +1341,7 @@ func syncRepo(exit, byHand bool) (dataChanged bool, err error) {
 func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult, trafficStat *dejavu.TrafficStat, mode string, elapsed time.Duration) {
 	logging.LogInfof("synced data repo [device=%s, kernel=%s, provider=%d, mode=%s/%t, ufc=%d, dfc=%d, ucc=%d, dcc=%d, ub=%s, db=%s] in [%.2fs], merge result [conflicts=%d, upserts=%d, removes=%d]\n\n",
 		Conf.System.ID, KernelID, Conf.Sync.Provider, mode, byHand,
-		trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.Bytes(uint64(trafficStat.UploadBytes)), humanize.Bytes(uint64(trafficStat.DownloadBytes)),
+		trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.BytesCustomCeil(uint64(trafficStat.UploadBytes), 2), humanize.BytesCustomCeil(uint64(trafficStat.DownloadBytes), 2),
 		elapsed.Seconds(),
 		len(mergeResult.Conflicts), len(mergeResult.Upserts), len(mergeResult.Removes))
 

+ 2 - 2
kernel/model/sync.go

@@ -543,13 +543,13 @@ func ListCloudSyncDir() (syncDirs []*Sync, hSize string, err error) {
 			CloudName: d.Name,
 		}
 		if conf.ProviderSiYuan == Conf.Sync.Provider {
-			sync.HSize = humanize.Bytes(uint64(dirSize))
+			sync.HSize = humanize.BytesCustomCeil(uint64(dirSize), 2)
 		}
 		syncDirs = append(syncDirs, sync)
 	}
 	hSize = "-"
 	if conf.ProviderSiYuan == Conf.Sync.Provider {
-		hSize = humanize.Bytes(uint64(size))
+		hSize = humanize.BytesCustomCeil(uint64(size), 2)
 	}
 	return
 }

+ 2 - 2
kernel/treenode/blocktree.go

@@ -506,7 +506,7 @@ func InitBlockTree(force bool) {
 	p.Release()
 
 	elapsed := time.Since(start).Seconds()
-	logging.LogInfof("read block tree [%s] to [%s], elapsed [%.2fs]", humanize.Bytes(uint64(size.Load())), util.BlockTreePath, elapsed)
+	logging.LogInfof("read block tree [%s] to [%s], elapsed [%.2fs]", humanize.BytesCustomCeil(uint64(size.Load()), 2), util.BlockTreePath, elapsed)
 	return
 }
 
@@ -569,7 +569,7 @@ func SaveBlockTree(force bool) {
 
 	elapsed := time.Since(start).Seconds()
 	if 2 < elapsed {
-		logging.LogWarnf("save block tree [size=%s] to [%s], elapsed [%.2fs]", humanize.Bytes(size), util.BlockTreePath, elapsed)
+		logging.LogWarnf("save block tree [size=%s] to [%s], elapsed [%.2fs]", humanize.BytesCustomCeil(size, 2), util.BlockTreePath, elapsed)
 	}
 }
 

+ 1 - 1
kernel/util/disk.go

@@ -30,6 +30,6 @@ func NeedWarnDiskUsage(dataSize int64) bool {
 		logging.LogErrorf("get disk usage failed: %s", err)
 		return false
 	}
-	logging.LogInfof("disk usage [total=%s, used=%s, free=%s]", humanize.Bytes(usage.Total), humanize.Bytes(usage.Used), humanize.Bytes(usage.Free))
+	logging.LogInfof("disk usage [total=%s, used=%s, free=%s]", humanize.BytesCustomCeil(usage.Total, 2), humanize.BytesCustomCeil(usage.Used, 2), humanize.BytesCustomCeil(usage.Free, 2))
 	return usage.Free < uint64(dataSize*2)
 }

+ 1 - 1
kernel/util/tesseract.go

@@ -184,7 +184,7 @@ func InitTesseract() {
 	}
 
 	TesseractLangs = filterTesseractLangs(langs)
-	logging.LogInfof("tesseract-ocr enabled [ver=%s, maxSize=%s, langs=%s]", ver, humanize.Bytes(TesseractMaxSize), strings.Join(TesseractLangs, "+"))
+	logging.LogInfof("tesseract-ocr enabled [ver=%s, maxSize=%s, langs=%s]", ver, humanize.BytesCustomCeil(TesseractMaxSize, 2), strings.Join(TesseractLangs, "+"))
 	tesseractInited.Store(true)
 }