├── .github └── workflows │ └── main.yml ├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_zh_CN.md ├── doc ├── asri-config-menu_en_US_v2.png ├── asri-config-menu_zh_CN_v2.png ├── asri-palettes.png ├── banner_v12.png ├── banner_v18.png ├── banner_v19.png ├── banner_v20.png ├── banner_v21.png ├── banner_v22.png ├── custom-attributes-preview_v7.gif ├── tfp.png ├── theme-config_en_US.gif └── theme-config_zh_CN.gif ├── i18n ├── ar_SA.json ├── en_US.json ├── zh_CHT.json └── zh_CN.json ├── icon.png ├── icons ├── icon-assets.svg ├── icon-chroma.svg ├── icon-outerLink.svg ├── icon-syLink.svg └── iframeResizer.svg ├── package-lock.json ├── package.json ├── postcss.config.js ├── preview.png ├── src ├── main.ts ├── modules │ ├── afwd.ts │ ├── asriPalettes.ts │ ├── dialog.ts │ ├── docks.ts │ ├── editor.ts │ ├── env.ts │ ├── focusedBlock.ts │ ├── index.ts │ ├── modeTransition.ts │ ├── protyleStatus.ts │ ├── scrollbar.ts │ ├── sidepanels.ts │ ├── status.ts │ ├── topbarFusion.ts │ └── trafficLights.ts ├── types │ ├── asri.d.ts │ ├── html.d.ts │ └── siyuan.d.ts └── util │ ├── api.ts │ ├── electron.ts │ ├── eventListeners.ts │ ├── interfaceState.ts │ ├── misc.ts │ ├── observers.ts │ ├── rsc.ts │ └── syAPI.ts ├── styles ├── _main.scss ├── _theme.scss ├── base │ ├── colors.scss │ ├── common.scss │ ├── index.scss │ ├── modes.scss │ └── utils.scss ├── components │ ├── _utils.scss │ ├── breadcrumb.scss │ ├── dialogs │ │ ├── av.scss │ │ ├── dialog.scss │ │ ├── emoji.scss │ │ ├── export.scss │ │ ├── flashcard.scss │ │ ├── functional.scss │ │ ├── history.scss │ │ ├── index.scss │ │ ├── marketplace.scss │ │ ├── mini-window.scss │ │ ├── preview.scss │ │ ├── search.scss │ │ └── settings.scss │ ├── index.scss │ ├── menu.scss │ └── misc.scss ├── features │ ├── _utils.scss │ ├── blur.scss │ ├── colorful-asri.scss │ ├── cover-image-fading.scss │ ├── cover-image-parallax-scrolling.scss │ ├── custom-attributes.scss │ ├── doc-attr-reposition.scss │ ├── filetree-indents-indicator.scss │ ├── floating-docks.scss │ ├── gradient-headings.scss │ ├── heading-indicators.scss │ ├── hide-side-panel-block-icons.scss │ ├── hide-toolbar.scss │ ├── high-readability-variants.scss │ ├── index.scss │ ├── layout-bento.scss │ ├── layout-paper.scss │ ├── list-counter-style.scss │ ├── mode-transition.scss │ ├── overflow-indicator.scss │ ├── panda-scheme.scss │ ├── performance-improvements.scss │ ├── reading-mode.scss │ ├── rtl.scss │ ├── selected-block-indicator.scss │ ├── topbar-fusion-plus.scss │ └── topbar-fusion.scss ├── layout │ ├── dock.scss │ ├── index.scss │ ├── side-panels.scss │ ├── status.scss │ ├── tab-bar.scss │ └── topbar.scss ├── palettes │ ├── index.scss │ ├── prst-palette-aerisland.scss │ ├── prst-palette-auriflow.scss │ ├── prst-palette-everbliss.scss │ ├── prst-palette-polarity.scss │ ├── prst-palette-stellula.scss │ └── prst-palette-zerith.scss ├── platforms │ ├── index.scss │ ├── linux.scss │ ├── mobile.scss │ └── windows.scss ├── plugins │ ├── backlink-panel.scss │ ├── bookmark-plus.scss │ ├── custom-block.scss │ ├── database-properties.scss │ ├── fake-breadcrumb.scss │ ├── fold-list-preview.css │ ├── index.scss │ ├── media-player.scss │ ├── siyuan-plugin-enhance.scss │ ├── typewriter.scss │ └── webview.scss └── protyle │ ├── _utils.scss │ ├── database.scss │ ├── editor.scss │ ├── elements │ ├── block-elements.scss │ ├── doc-header.scss │ ├── gutters.scss │ ├── index.scss │ ├── inline-elements.scss │ └── tools.scss │ ├── index.scss │ └── pdf-reader.scss ├── theme.css ├── theme.js ├── theme.json ├── theme.scss ├── tsconfig.json └── webpack.config.cjs /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | 14 | - name: Zip Release 15 | uses: thedoctor0/zip-release@0.7.6 16 | with: 17 | type: 'zip' 18 | filename: 'package.zip' 19 | exclusions: '*.git* *.scss *.txt /*styles/* /*doc/* /*src/* *config* *package* *CHANGELOG*' 20 | 21 | - name: Create Release 22 | uses: ncipollo/release-action@v1.13.0 23 | with: 24 | allowUpdates: true 25 | artifactErrorsFailBuild: true 26 | artifacts: "package.zip" 27 | token: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | .DS_Store 4 | .eslintcache 5 | dist 6 | package.zip 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 W.Kai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README_zh_CN.md: -------------------------------------------------------------------------------- 1 | 简体中文 | [English](https://github.com/mustakshif/Asri-for-SiYuan/blob/main/README.md) 2 | 3 | 5 | 6 |
7 | 8 | ![banner](https://cdn.jsdelivr.net/gh/mustakshif/Asri-for-SiYuan@main/doc/banner_v22.png) 9 | 10 | # Asri · 让界面隐退,让思维登场 11 | 12 | Asri 是一款极富现代感的[思源笔记](https://github.com/siyuan-note/siyuan)主题,以隐形设计构筑沉浸空间,为你带来专注、优雅、直觉驱动的笔记体验。 13 | 14 | ## 最近更新 15 | 16 | ### v3.4.3 17 | 18 | - 新增预设主题配色「星漪」 19 | - 优化滚动条颜色 20 | - 修复移动端部分子菜单无法滚动的问题 21 | - 修复部分面板上下间距问题 22 | - 修复打开搜索窗口时内容向上移位的问题 23 | 24 | ### … 25 | 26 | ### v3.4.0:视界无界 27 | 28 | ![tfp](https://cdn.jsdelivr.net/gh/mustakshif/Asri-for-SiYuan@main/doc/tfp.png) 29 | 30 | * 新增「顶栏融合**+**」,突破顶栏与编辑区界限,带来沉浸式的阅读与编辑体验(*实验性功能,请谨慎启用;详请见脚注 3*) 31 | * 调整预设配色方案「岁禧」的配色 32 | * 去除移动端菜单的多余边框 33 | * [修复移动端块属性遮挡内容的问题](https://github.com/mustakshif/Asri/issues/162) 34 | * [修复主题导致的「侧栏备注」插件无法显示的问题](https://ld246.com/article/1746662147426/comment/1746667474590?r=Mustakshif#comments) 35 | 36 | ### ... 37 | 38 | 全部更新日志见[这里](https://github.com/mustakshif/Asri/blob/main/CHANGELOG.md)。 39 | 40 | ## 主题特性 41 | 42 | ### 🪄 简洁现代的设计 43 | 44 | * 👨‍🎨 主题色无极调节,带来完全个性化的笔记体验[^1] 45 | * ⚖️ 顶栏融合**+**,实现顶栏与页签栏和编辑器的无缝整合[^2][^3] 46 | * 🧊 引入毛玻璃材质,带来富有层次感的视觉体验 47 | * 🌓 支持亮色模式和暗色模式、模式切换平滑过渡 48 | * ➖ 精简分割线,打造一体化的界面风格 49 | * ⚙️ 现代化的控件样式设计 50 | 51 | ### 📐 优雅高效的排版 52 | 53 | * 🔢 为表格、数据库启用等宽数字变体,提升阅读效率 54 | * 👁️ 启用高可读性字形变体,适应笔记场景[^4] `#macOS` `#iOS` `#iPadOS` 55 | * 🛋️ 亮暗色模式分设字体平滑模式,保持视觉字重一致性 `#macOS` `#iOS` `#iPadOS` 56 | * 🦋 支持图片、视频、挂件、数据库、超级块等的全宽显示,提高信息展示效率 57 | * 💬 支持从右至左布局,适配阿拉伯语等从右至左书写的语言[^5] 58 | * 🚏 支持文档级别的文字方向设定,满足不同语言的排版需求 59 | * 🧩 优化超级块内外部间距,轻松实现网格、瀑布流布局 60 | * 📝 优化数据库和属性面板的布局细节,内容展现更清晰有序 61 | 62 | ### 🧭 便捷清晰的导航 63 | 64 | * 🗂️ 添加文档树、大纲缩进参考线 65 | * 🔍 层级分明的搜索列表、反链列表展示 66 | * ↕️ 采用系统原生滚动条,可自动隐藏,界面更清爽[^6] `#macOS` 67 | 68 | ### 👆 灵动流畅的交互 69 | 70 | * ⏱️ 优化动画响应时机,改善界面反馈频率,减少用户注意力分散 71 | * 💫 适当加入鲜活动效,丰富交互体验 72 | * 🚀 保持较高的流畅度表现 73 | 74 | [^1]: 新特性仅在支持 `oklch()` 及其相对颜色语法的平台有效。部分设备由于浏览器内核版本较低,仍采用旧版本配色方案。 75 | 76 | [^2]: 顶栏空白区域均可用于拖动窗口(页签间隙除外)。 77 | 78 | [^3]: 顶栏融合+对思源笔记原生样式进行了重大调整,虽经长期稳定性测试,仍无法保证完全稳定,或将长期作为实验性功能存在。当前已知问题如下: 79 | 80 | 1. 编辑器右侧动态滚动条无法实时显示文档进度(跳转功能正常) 81 | 2. 向页面顶部拖拽块时无法触发自动滚动 82 | 3. 数据库表头无法固定在编辑器可视区域内 83 | 84 | 此外还可能引发其他问题,例如: 85 | 86 | 1. 与自定义样式代码产生冲突 87 | 2. 与部分插件存在兼容性问题 88 | 3. 顶栏文字/图标可读性下降 89 | 4. 页面运行效率降低 90 | 91 | 使用过程中如遇问题请及时停用此功能。 92 | 93 | [^4]: 如需禁用此特性,或在使用自定义字体时发现字形错误,可在代码片段中添加以下 CSS 代码恢复原字形: 94 | ```CSS 95 | .layout-tab-container, .protyle-content, .b3-typography { 96 | font-feature-settings: normal !important; 97 | } 98 | ``` 99 | 100 | [^5]: 由于主题功能有限,部分界面的 UI 布局方向无法完全修改。 101 | 102 | [^6]: 自动隐藏滚动条需要在「系统设置-外观」中,将「显示滚动条」设置为「滚动时」。 103 | 104 | ## 开始使用 105 | 106 | * **应用内下载更新(推荐)**:进入思源笔记应用,在 `设置 - 集市 - 主题` 中搜索下载「Asri」并应用 107 | * GitHub 下载更新:下载 release 中的 `package.zip`,手动解压至思源笔记工作空间下的 `conf/appearance/themes`,重启思源,在应用 `设置 - 外观` 中选择 Asri 主题 108 | 109 | ## 主题配置 110 | 111 | ### 🌈 自定义主题色 112 | 113 | ![custom theme color preview](https://cdn.jsdelivr.net/gh/mustakshif/Asri@main/doc/theme-config_zh_CN.gif) 114 | 115 | 点击右上角 `外观模式` 图标即可弹出 Asri 主题配置菜单,定制主题配色。 116 | 117 | * `自定义主题色`:使用自选色作为主题基准色,生成相应配色方案并直接应用 118 | * `跟随系统强调色`:使用系统强调色作为主题基准色,仅在 Windows 和 macOS 桌面端可用 119 | * `色度滑块`:调整背景和普通文本的色彩浓度,取值范围为 `0 - 5`,`0` 表示纯灰度色,默认值为 `1` 120 | 121 | ### 📐 自定义属性 122 | 123 | #### 1. `afwd`:全宽显示(Asri full-width display) 124 | 125 | ![full-width-display preview](https://cdn.jsdelivr.net/gh/mustakshif/Asri-for-SiYuan@main/doc/custom-attributes-preview_v7.gif) 126 | 127 | 使应用了此属性的块撑满页面宽度显示,可用于强调特定内容或美化排版等。全宽显示的样式对图片、数据库、 iframe、表格和水平布局的超级块生效。 128 | 129 | 要启用全宽显示,可点击**文档块**和**上述内容块**的块标,在弹出的菜单中选择 `全宽显示`,进行相应配置即可。 130 | 131 | ##### 注意事项 132 | 133 | * 全宽显示仅对文档中**第一层级**的块生效。如果一个块被嵌套在其他内容块中,对其应用此属性不会产生任何效果。例如,对引述块中的图片段落块应用此属性,该段落块不会有样式变化,除非将外部引述块取消。 134 | * 全宽显示仅在主窗口和小窗编辑区有效,块引用预览窗、导出预览、反链面板和搜索结果预览等场景均不生效。 135 | * 启用全宽显示可能导致编辑区大小改变后,自动返回光标所在位置时页面的跳动感增强。 136 | 137 |

138 |
139 | 更多信息 140 | 此特性依赖自定义属性功能,因此也可手动配置块属性,属性名和属性值如下表所示: 141 | 142 | | 属性名 | 属性值 | 说明 | 143 | | --- | --- | --- | 144 | | `afwd`   |- `all`(使文档中支持此属性的块全部全宽显示)
- `p`(使文档中所有图片全宽显示)
- `db`(使文档中所有数据库块全宽显示)
- `iframe`(使文档中所有 iframe 块全宽显示,包括视频、挂件和嵌入的网页)
- `sb`(使文档中所有**水平布局的**超级块全宽显示)
- `t`(使文档中所有表格块全宽显示) | 应用于文档块。
除 `all` 以外的属性值均可以多个同时使用,用**空格**分隔 | 145 | | `afwd`   |- `on`(单独启用块的全宽显示)
- `off`(单独关闭块的全宽显示) | 应用于段落块、数据库块、 iframe 块、超级块和表格块。| 146 |
147 | 148 | #### 2. `tdir`:文档文字方向 149 | 150 | 仅应用于文档块,使文档内容统一从左至右或从右至左渲染,方便写作和阅读。该属性不受全局设置影响,不会覆盖文档中块的单独布局设置。该属性在反链列表和导出场景不生效。 151 | 152 | 如需进行相应配置,可点击**文档块**块标,在弹出的菜单中选择 `文档排版方向` 即可。 153 | 154 | 155 | 156 |

157 |
158 | 更多信息 159 | 160 | | 属性名 | 属性值 | 说明 | 161 | | -------- | -------- | --------- | 162 | | `tdir` | `ltr` | 使文档内容从左至右渲染,适合中文、英文等从左至右书写的文本 | 163 | | `tdir` | `rtl` | 使文档内容从右向左渲染,适合阿拉伯文等从右至左书写的文本 | 164 | 165 |
166 | 167 | ## 鸣谢 168 | 169 | 主题制作过程中参考借鉴了以下来源,在此对各位作者表示感谢: 170 | 171 | | 借鉴内容 | 来源 | 作者 | 172 | |--- | --- | --- | 173 | | - 菜单背景模糊 | 主题:[Cliff-Dark](https://github.com/chenshinshi/Cliff-Dark) | [Crowds21](https://github.com/chenshinshi) | 174 | | - 侧栏面板列表项前圆点
- 大纲列表标题图标
- 状态栏
- 搜索列表
- 表格列宽
- `/` 菜单多栏布局
- 底栏和状态栏合并
- 多级列表序号 | 主题:[Savor](https://github.com/royc01/notion-theme) | [Roy](https://github.com/royc01) | 175 | | - 顶栏页签栏合并
- 文档树缩进线
- DOM 变动观察相关函数 | 主题:[Rem Craft](https://github.com/svchord/Rem-Craft) | [Seven Chord](https://github.com/svchord) | 176 | 177 | (以上排名不分先后) 178 | 179 | ## 反馈和建议 180 | - [项目主页](https://github.com/mustakshif/Asri/)提交 issue 或 PR 181 | - 发送邮件至 mustakshif@icloud.com 182 | 183 | ## 其他 184 | 185 | -------------------------------------------------------------------------------- /doc/asri-config-menu_en_US_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/asri-config-menu_en_US_v2.png -------------------------------------------------------------------------------- /doc/asri-config-menu_zh_CN_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/asri-config-menu_zh_CN_v2.png -------------------------------------------------------------------------------- /doc/asri-palettes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/asri-palettes.png -------------------------------------------------------------------------------- /doc/banner_v12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/banner_v12.png -------------------------------------------------------------------------------- /doc/banner_v18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/banner_v18.png -------------------------------------------------------------------------------- /doc/banner_v19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/banner_v19.png -------------------------------------------------------------------------------- /doc/banner_v20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/banner_v20.png -------------------------------------------------------------------------------- /doc/banner_v21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/banner_v21.png -------------------------------------------------------------------------------- /doc/banner_v22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/banner_v22.png -------------------------------------------------------------------------------- /doc/custom-attributes-preview_v7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/custom-attributes-preview_v7.gif -------------------------------------------------------------------------------- /doc/tfp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/tfp.png -------------------------------------------------------------------------------- /doc/theme-config_en_US.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/theme-config_en_US.gif -------------------------------------------------------------------------------- /doc/theme-config_zh_CN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/doc/theme-config_zh_CN.gif -------------------------------------------------------------------------------- /i18n/ar_SA.json: -------------------------------------------------------------------------------- 1 | { 2 | "followSysAccent": "اتباع لون النظام الأساسي", 3 | "pickColor": "تخصيص لون السمة", 4 | "asriChroma": "التشبع: ", 5 | "afwdDocMenuLabel": "عرض بعرض الشاشة الكامل", 6 | "afwdMenuItem-all": "جميع الكتل القابلة للتطبيق", 7 | "afwdMenuItem-db": "قاعدة البيانات", 8 | "afwdMenuItem-t": "جدول", 9 | "afwdMenuItem-p": "صورة", 10 | "afwdMenuItem-iframe": "إطار داخلي", 11 | "afwdMenuItem-sb": "كتلة فائقة", 12 | "afwdMenuItem-clear": "مسح السمات", 13 | "afwdMenuItem-on": "تفعيل لهذه الكتلة", 14 | "afwdMenuItem-off": "تعطيل لهذه الكتلة", 15 | "tdirDocMenuLabel": "اتجاه تخطيط المستند", 16 | "tdirMenuItem-ltr": "من اليسار إلى اليمين", 17 | "tdirMenuItem-rtl": "من اليمين إلى اليسار", 18 | "palette-presets": "الإعدادات المسبقة", 19 | "prst-palette-everbliss": "النعيم الأبدي", 20 | "prst-palette-auriflow": "تدفق الذهب", 21 | "prst-palette-aerisland": "جزيرة السماء", 22 | "prst-palette-zerith": "المجال الصفري", 23 | "prst-palette-polarity": "القطب", 24 | "prst-palette-stellula": "تموُّج نجمي", 25 | "topbarFusionPlus": "دمج شريط الأعلى+", 26 | "tfp-progressive": "الضبابية التدريجية", 27 | "tfp-acrylic": "الأكريليك", 28 | "tfp-disable": "تعطيل", 29 | "tfp-experimental": "ميزة تجريبية، يرجى التفعيل بحذر.\nلمزيد من المعلومات، يرجى الاطلاع على الحاشية 3 في وصف السمة." 30 | } -------------------------------------------------------------------------------- /i18n/en_US.json: -------------------------------------------------------------------------------- 1 | { 2 | "followSysAccent": "Follow system accent color", 3 | "pickColor": "Customize theme color", 4 | "asriChroma": "Chroma: ", 5 | "afwdDocMenuLabel": "Full-width Display", 6 | "afwdMenuItem-all": "All applicable blocks", 7 | "afwdMenuItem-db": "Database", 8 | "afwdMenuItem-t": "Table", 9 | "afwdMenuItem-p": "Image", 10 | "afwdMenuItem-iframe": "IFrame", 11 | "afwdMenuItem-sb": "Superblock", 12 | "afwdMenuItem-clear": "Clear attributes", 13 | "afwdMenuItem-on": "Enable for this block", 14 | "afwdMenuItem-off": "Disable for this block", 15 | "tdirDocMenuLabel": "Doc layout direction", 16 | "tdirMenuItem-ltr": "Left to right", 17 | "tdirMenuItem-rtl": "Right to left", 18 | "palette-presets": "Presets", 19 | "prst-palette-everbliss": "Everbliss", 20 | "prst-palette-auriflow": "Auriflow", 21 | "prst-palette-aerisland": "Aerisland", 22 | "prst-palette-zerith": "Zerith", 23 | "prst-palette-polarity": "Polarity", 24 | "prst-palette-stellula": "Stellula", 25 | "topbarFusionPlus": "Topbar Fusion+", 26 | "tfp-progressive": "Progressive blur", 27 | "tfp-acrylic": "Acrylic", 28 | "tfp-disable": "Disable", 29 | "tfp-experimental": "Experimental feature; enable with caution.\nFor more information please refer to footnote 3 of the theme doc." 30 | } -------------------------------------------------------------------------------- /i18n/zh_CHT.json: -------------------------------------------------------------------------------- 1 | { 2 | "followSysAccent": "跟隨系統強調色", 3 | "pickColor": "自定義主題色", 4 | "asriChroma": "色度:", 5 | "afwdDocMenuLabel": "全寬顯示", 6 | "afwdMenuItem-all": "所有適用的塊", 7 | "afwdMenuItem-db": "數據庫", 8 | "afwdMenuItem-t": "表格", 9 | "afwdMenuItem-p": "圖片", 10 | "afwdMenuItem-iframe": "iFrame", 11 | "afwdMenuItem-sb": "超級塊", 12 | "afwdMenuItem-clear": "清除屬性", 13 | "afwdMenuItem-on": "為此塊啟用", 14 | "afwdMenuItem-off": "為此塊禁用", 15 | "tdirDocMenuLabel": "文件排版方向", 16 | "tdirMenuItem-ltr": "從左向右", 17 | "tdirMenuItem-rtl": "從右向左", 18 | "palette-presets": "預設配色方案", 19 | "prst-palette-everbliss": "歲禧", 20 | "prst-palette-auriflow": "鎏金", 21 | "prst-palette-aerisland": "空嶼", 22 | "prst-palette-zerith": "零域", 23 | "prst-palette-polarity": "極地", 24 | "prst-palette-stellula": "星漪", 25 | "topbarFusionPlus": "頂欄融合+", 26 | "tfp-progressive": "漸進模糊", 27 | "tfp-acrylic": "亞克力", 28 | "tfp-disable": "禁用", 29 | "tfp-experimental": "實驗性功能,請謹慎啟用\n更多資訊見主題文檔腳注 3" 30 | } -------------------------------------------------------------------------------- /i18n/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "followSysAccent": "跟随系统强调色", 3 | "pickColor": "自定义主题色", 4 | "asriChroma": "色度:", 5 | "afwdDocMenuLabel": "全宽显示", 6 | "afwdMenuItem-all": "所有适用的块", 7 | "afwdMenuItem-db": "数据库", 8 | "afwdMenuItem-t": "表格", 9 | "afwdMenuItem-p": "图片", 10 | "afwdMenuItem-iframe": "iFrame", 11 | "afwdMenuItem-sb": "超级块", 12 | "afwdMenuItem-clear": "清除属性", 13 | "afwdMenuItem-on": "为此块启用", 14 | "afwdMenuItem-off": "为此块禁用", 15 | "tdirDocMenuLabel": "文档排版方向", 16 | "tdirMenuItem-ltr": "从左向右", 17 | "tdirMenuItem-rtl": "从右向左", 18 | "palette-presets": "预设配色方案", 19 | "prst-palette-everbliss": "岁禧", 20 | "prst-palette-auriflow": "鎏金", 21 | "prst-palette-aerisland": "空屿", 22 | "prst-palette-zerith": "零域", 23 | "prst-palette-polarity": "极地", 24 | "prst-palette-stellula": "星漪", 25 | "topbarFusionPlus": "顶栏融合+", 26 | "tfp-progressive": "渐进模糊", 27 | "tfp-acrylic": "亚克力", 28 | "tfp-disable": "禁用", 29 | "tfp-experimental": "实验性功能,请谨慎启用\n更多信息见主题文档脚注 3" 30 | } 31 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/icon.png -------------------------------------------------------------------------------- /icons/icon-assets.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/icon-chroma.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/icon-outerLink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/icon-syLink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/iframeResizer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asri", 3 | "version": "3.4.3", 4 | "private": true, 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/mustakshif/Asri.git" 8 | }, 9 | "homepage": "https://github.com/mustakshif/Asri", 10 | "keywords": [ 11 | "Asri" 12 | ], 13 | "description": "An ultra-modern theme that delivers an elegant, efficient, and personalized note-taking experience through its clean, intuitive design.", 14 | "scripts": { 15 | "build": "webpack --mode production && sass ./theme.scss:./theme.css --no-source-map --style compressed && postcss ./theme.css -o ./theme.css", 16 | "dev": "concurrently \"webpack --watch --mode development\" \"sass --watch ./theme.scss:./theme.css --no-source-map --no-error-css\"" 17 | }, 18 | "author": "mustakshif", 19 | "license": "MIT", 20 | "devDependencies": { 21 | "@types/cssom": "^0.4.3", 22 | "@types/eslint": "^8.56.10", 23 | "@types/web": "^0.0.188", 24 | "autoprefixer": "^10.4.20", 25 | "concurrently": "^9.1.2", 26 | "html-loader": "^5.0.0", 27 | "postcss-cli": "^11.0.0", 28 | "siyuan": "^1.0.2", 29 | "terser-webpack-plugin": "^5.3.10", 30 | "ts-loader": "^9.5.1", 31 | "typescript": "^5.4.5", 32 | "webpack": "^5.97.1", 33 | "webpack-cli": "^5.1.4" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | // postcss.config.js 2 | module.exports = { 3 | plugins: [require("autoprefixer")], 4 | }; 5 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/preview.png -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { loadAsriJSModules, unloadAsriJSModules } from "./modules"; 2 | 3 | loadAsriJSModules(); 4 | 5 | window.destroyTheme = () => { 6 | let completeUnload = true; 7 | 8 | setTimeout(() => { 9 | const themePairOnDestroy = { 10 | "light": window.siyuan.config.appearance.themeLight, 11 | "dark": window.siyuan.config.appearance.themeDark, 12 | }; 13 | console.log("destroy", themePairOnDestroy); 14 | if (themePairOnDestroy.light === "Asri" && themePairOnDestroy.dark === "Asri") completeUnload = false; 15 | 16 | console.log(`\x1b[31m\x1b[1m\x1b[47mTheme destroy mode: ${completeUnload ? "complete" : "incomplete"}\x1b[0m`); 17 | unloadAsriJSModules(completeUnload); 18 | }, 0); 19 | }; 20 | -------------------------------------------------------------------------------- /src/modules/dialog.ts: -------------------------------------------------------------------------------- 1 | export function docBodyMoCallback(mutationList: MutationRecord[], observer: MutationObserver) { 2 | addExportImgClassName(); 3 | } 4 | 5 | export function addExportImgClassName() { 6 | document.body.classList.toggle("has-exportimg", !!document.querySelector('[data-key="dialog-exportimage"]')); 7 | } 8 | -------------------------------------------------------------------------------- /src/modules/docks.ts: -------------------------------------------------------------------------------- 1 | import { querySelectorAsync } from "../util/misc"; 2 | import { asriDoms as doms, environment } from "../util/rsc"; 3 | import { hasDockb, isDockLytExpanded, isDockLytPinned } from "../util/interfaceState"; 4 | 5 | export async function updateDockLBgAndBorder() { 6 | const dockL = doms.dockL ? doms.dockL : await querySelectorAsync("#dockLeft"); 7 | if (!doms.layoutDockL) await querySelectorAsync(".layout__dockl"); 8 | const dockR = doms.dockR; 9 | 10 | for (let dock of [dockL, dockR]) { 11 | let isDockLLytPinned = isDockLytPinned(dock === dockL ? "L" : "R"), 12 | isDockLLytExpanded = isDockLytExpanded(dock === dockL ? "L" : "R"); 13 | 14 | // console.log('measure: dock' , dock) 15 | 16 | if (isDockLLytPinned && isDockLLytExpanded) { 17 | dock?.classList.add("dock-layout-expanded"); 18 | } else { 19 | dock?.classList.remove("dock-layout-expanded"); 20 | } 21 | 22 | // console.log('mutate: dock' , dock) 23 | } 24 | } 25 | 26 | export async function addDockbClassName() { 27 | if (environment.isMobile) return; 28 | const dockbExist = await hasDockb(); 29 | const dockbFloat = !isDockLytPinned("B") && isDockLytExpanded("B"); 30 | 31 | doms.toolbar?.nextElementSibling!.classList.toggle("has-dockb", dockbExist); 32 | doms.toolbar?.nextElementSibling!.classList.toggle("has-layout-dockb-float", dockbFloat); 33 | doms.dockB?.classList.toggle("has-layout-dockb-float", dockbFloat); 34 | } 35 | 36 | export function removeDockbClassName() { 37 | doms.toolbar?.nextElementSibling!.classList.remove("has-dockb"); 38 | doms.toolbar?.nextElementSibling!.classList.remove("has-layout-dockb-float"); 39 | } 40 | 41 | export function destroyDockBg() { 42 | document.querySelector(".dock-layout-expanded")?.classList.remove("dock-layout-expanded"); 43 | } 44 | -------------------------------------------------------------------------------- /src/modules/editor.ts: -------------------------------------------------------------------------------- 1 | import { debounce, querySelectorAllAsync } from "../util/misc"; 2 | 3 | export const debouncedFormatProtyleWithBgImageOnly = debounce(formatProtyleWithBgImageOnly); 4 | async function formatProtyleWithBgImageOnly() { 5 | // await updateWndEls(); 6 | let protyleBgs = await querySelectorAllAsync(".protyle-top>.protyle-background"); 7 | 8 | protyleBgs?.forEach((protyleBg) => { 9 | if (!protyleBg.querySelector(".protyle-background__img img")?.classList.contains("fn__none") && protyleBg.querySelector(".protyle-background__icon.fn__none")) { 10 | protyleBg.classList.add("without-icon"); 11 | } else { 12 | protyleBg.classList.remove("without-icon"); 13 | } 14 | }); 15 | } 16 | 17 | export function removeProtyleWithBgImageOnlyClassName() { 18 | document.querySelectorAll(".protyle .protyle-background.without-icon").forEach((el) => { 19 | el.classList.remove("without-icon"); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /src/modules/env.ts: -------------------------------------------------------------------------------- 1 | import { environment as env } from "../util/rsc"; 2 | 3 | type EnvClassifier = { 4 | condition: boolean | undefined; 5 | className: string; 6 | }; 7 | 8 | const envClassifiers: EnvClassifier[] = [ 9 | { condition: env.isMacOS, className: "body-asri--mac" }, 10 | { condition: env.isLinux, className: "body-asri--linux" }, 11 | { condition: env.isMobile, className: "body-asri--mobile" }, 12 | { condition: env.isInBrowser, className: "body-asri--browser" }, 13 | { condition: env.isAndroid, className: "body-asri--android" }, 14 | { condition: env.isIOSApp, className: "body-asri--iosApp" }, 15 | { condition: env.isReadOnly, className: "body-asri--readOnly" }, 16 | { condition: env.isSafari, className: "body-asri--safari" }, 17 | ]; 18 | 19 | export function addEnvClassNames() { 20 | envClassifiers.forEach(({ condition, className }) => { 21 | if (condition) { 22 | document.body.classList.add(className); 23 | } 24 | }); 25 | } 26 | 27 | export function removeEnvClassNames() { 28 | envClassifiers.forEach(({ className }) => { 29 | document.body.classList.remove(className); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /src/modules/focusedBlock.ts: -------------------------------------------------------------------------------- 1 | export function selectionChangeCallback(e: Event) { 2 | // fix https://github.com/mustakshif/Asri/issues/133 3 | // 创建一个 Promise,等待 mouseup 事件 4 | const mouseUpPromise = new Promise((resolve) => { 5 | const mouseUpHandlerForSelectedBlock = () => { 6 | document.removeEventListener("mouseup", mouseUpHandlerForSelectedBlock, true); 7 | resolve(); 8 | }; 9 | document.addEventListener("mouseup", mouseUpHandlerForSelectedBlock, true); 10 | }); 11 | 12 | // 创建一个 Promise,等待 0.3 秒 13 | const timeoutPromise = new Promise((resolve) => { 14 | setTimeout(resolve, 300); 15 | }); 16 | 17 | // 创建一个 Promise,等待 keyup 事件 18 | const keyUpPromise = new Promise((resolve) => { 19 | const keyUpHandlerForSelectedBlock = () => { 20 | document.removeEventListener("keyup", keyUpHandlerForSelectedBlock, true); 21 | resolve(); 22 | }; 23 | document.addEventListener("keyup", keyUpHandlerForSelectedBlock, true); 24 | }); 25 | 26 | // 使用 Promise.race 等待 mouseup 事件、keyup 事件或 0.3 秒 27 | Promise.race([mouseUpPromise, keyUpPromise, timeoutPromise]).then(() => { 28 | const selection = window.getSelection(); 29 | const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null; 30 | if (!range) return; 31 | 32 | const curNode = range.commonAncestorContainer; 33 | const curParent = curNode.parentElement; 34 | const curBlock = curParent ? curParent.closest("[data-node-id]") : null; 35 | if (!curBlock) return; 36 | 37 | const curBlockType = curBlock.getAttribute("data-type"); 38 | 39 | removeFocusedBlockClass(); 40 | 41 | if (!curBlockType || ["NodeAttributeView", "NodeCodeBlock", "NodeList", "NodeHTMLBlock"].includes(curBlockType)) return; 42 | 43 | curBlock.classList.add("asri-selected-block"); 44 | // console.log(selection, range, curNode, curBlock, curBlockType); 45 | }); 46 | } 47 | 48 | export function removeFocusedBlockClass() { 49 | document.querySelectorAll(".asri-selected-block").forEach((block) => block.classList.remove("asri-selected-block")); 50 | } 51 | 52 | // export function handleFocusedBlockChange() { 53 | // const selection = window.getSelection(); 54 | // const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null; 55 | // if (!range) return; 56 | 57 | // const curNode = range.commonAncestorContainer; 58 | // const curParent = curNode.parentElement; 59 | // const curBlock = curParent ? curNode.parentElement.closest('[data-node-id]') : null; 60 | // if (!curBlock) return; 61 | 62 | // curParent && curParent.dir && curParent.dir === 'auto'; 63 | // const curBlockType = curBlock.getAttribute('data-type'); 64 | 65 | // document.querySelectorAll('.asri-selected-block').forEach(block => block.classList.remove('asri-selected-block')); 66 | // if (curBlockType === 'NodeAttributeView' || !curBlockType || curBlockType === 'NodeCodeBlock') return; 67 | 68 | // curBlock.classList.add('asri-selected-block'); 69 | // } 70 | -------------------------------------------------------------------------------- /src/modules/modeTransition.ts: -------------------------------------------------------------------------------- 1 | export async function modeTransitionOnClick(e: Event) { 2 | if (e.type !== "mouseup") return; 3 | 4 | const target = e.target as HTMLElement; 5 | 6 | if (target.closest('[data-name="barmode"] .b3-menu__item:not([id])')) { 7 | console.log(`Clicked item: ${target.textContent}`); 8 | // e.stopPropagation(); 9 | // e.preventDefault(); 10 | startFadeInFadeOutTranstition(); 11 | } 12 | } 13 | 14 | export async function startFadeInFadeOutTranstition(animDuration = 600, func?: () => void, waitDuration = 0) { 15 | // // Setup view transition support 16 | // const meta = document.createElement('meta'); 17 | // meta.name = 'view-transition'; 18 | // meta.content = 'same-origin'; 19 | // document.head.appendChild(meta); 20 | 21 | if (!document.startViewTransition) { 22 | func && func(); 23 | return; 24 | } 25 | 26 | console.log("\x1b[34m\x1b[1m\x1b[47mMode Transition started\x1b[0m"); 27 | if (waitDuration > 0) { 28 | const wait = (ms: number) => { 29 | return new Promise((r) => setTimeout(r, ms)); 30 | }; 31 | const transition = document.startViewTransition(async () => { 32 | await Promise.race([wait(waitDuration)]); 33 | func && func(); 34 | }); 35 | 36 | transition.ready.then(() => { 37 | document.documentElement.animate( 38 | { 39 | opacity: [0, 1], 40 | }, 41 | { 42 | duration: animDuration, 43 | // easing: 'ease-in-out', 44 | } 45 | ); 46 | }); 47 | } else { 48 | const transition = document.startViewTransition(func); 49 | const style = document.createElement("style"); 50 | style.textContent = ` 51 | ::view-transition-old(root), 52 | ::view-transition-new(root) { 53 | animation-duration: ${animDuration}ms; 54 | } 55 | `; 56 | document.head.appendChild(style); 57 | 58 | await transition.finished; 59 | style.remove(); 60 | } 61 | } 62 | 63 | export const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); 64 | 65 | // 圆形过渡 66 | // let lastClick: any; 67 | // // addEventListener('click', event => (lastClick = event)); 68 | 69 | // function spaNavigate() { 70 | // // Fallback for browsers that don't support this API: 71 | // if (!document.startViewTransition) { 72 | // return; 73 | // } 74 | 75 | // // Get the click position, or fallback to the middle of the screen 76 | // const x = lastClick?.clientX ?? innerWidth / 2; 77 | // const y = lastClick?.clientY ?? innerHeight / 2; 78 | // // Get the distance to the furthest corner 79 | // const endRadius = Math.hypot( 80 | // Math.max(x, innerWidth - x), 81 | // Math.max(y, innerHeight - y) 82 | // ); 83 | 84 | // // With a transition: 85 | // const transition = document.startViewTransition(() => { 86 | // }); 87 | 88 | // // Wait for the pseudo-elements to be created: 89 | // transition.ready.then(() => { 90 | // // Animate the root's new view 91 | // document.documentElement.animate( 92 | // { 93 | // clipPath: [ 94 | // `circle(0 at ${x}px ${y}px)`, 95 | // `circle(${endRadius}px at ${x}px ${y}px)`, 96 | // ], 97 | // }, 98 | // { 99 | // duration: 500, 100 | // easing: 'ease-in', 101 | // // Specify which pseudo-element to animate 102 | // pseudoElement: '::view-transition-new(root)', 103 | // } 104 | // ); 105 | // }); 106 | // } 107 | -------------------------------------------------------------------------------- /src/modules/protyleStatus.ts: -------------------------------------------------------------------------------- 1 | import { isProtyle, querySelectorAsync } from "../util/misc"; 2 | import { asriDoms } from "../util/rsc"; 3 | 4 | export async function toggleProtyleStatus(docID?: string) { 5 | let isprotyle = await isProtyle(docID); 6 | const status = asriDoms.status || (await querySelectorAsync("#status")); 7 | if (!status) return; 8 | status.classList.toggle("asri--non-protyle-status", !isprotyle); 9 | } 10 | 11 | export function removeProtyleStatusClassName() { 12 | const status = asriDoms.status; 13 | if (!status) return; 14 | status.classList.remove("asri--non-protyle-status"); 15 | } 16 | -------------------------------------------------------------------------------- /src/modules/scrollbar.ts: -------------------------------------------------------------------------------- 1 | import { environment as env } from "../util/rsc"; 2 | 3 | const { isMacOS, isMobile } = env; 4 | const asriDeletedRules: { styleSheet: CSSStyleSheet; rule: string }[] = []; 5 | export async function useMacSysScrollbar() { 6 | if (isMacOS || isMobile) { 7 | for (let i = 0; i < document.styleSheets.length; i++) { 8 | let styleSheet = document.styleSheets[i]; 9 | try { 10 | for (let j = 0; j < styleSheet.cssRules.length; j++) { 11 | let rule = styleSheet.cssRules[j] as CSSStyleRule; 12 | if (rule.selectorText && rule.selectorText.includes("::-webkit-scrollbar")) { 13 | if (rule.style.width || rule.style.height || rule.style.backgroundColor) { 14 | asriDeletedRules.push({ styleSheet: styleSheet, rule: rule.cssText }); 15 | styleSheet.deleteRule(j); 16 | j--; 17 | } 18 | } 19 | } 20 | } catch (e) { 21 | console.log(e); 22 | } 23 | } 24 | } 25 | } 26 | 27 | export async function restoreDefaultSiyuanScrollbar() { 28 | if (asriDeletedRules) { 29 | for (let i = 0; i < asriDeletedRules.length; i++) { 30 | let rule = asriDeletedRules[i]; 31 | rule.styleSheet.insertRule(rule.rule, rule.styleSheet.cssRules.length); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/modules/sidepanels.ts: -------------------------------------------------------------------------------- 1 | import { debounce, querySelectorAsync } from "../util/misc"; 2 | import { asriDoms as doms, environment } from "../util/rsc"; 3 | 4 | const { isMobile } = environment; 5 | 6 | export const debouncedFormatIndentGuidesForFocusedItems = debounce(formatIndentGuidesForFocusedItems); 7 | export async function formatIndentGuidesForFocusedItems() { 8 | if (isMobile) return; 9 | 10 | if (!doms.layoutDockL) await querySelectorAsync(".layout__dockl"); 11 | 12 | let listItemsFocus = document.querySelectorAll(".file-tree .b3-list-item--focus"); 13 | 14 | if (!listItemsFocus.length) return; 15 | 16 | document.querySelectorAll(".file-tree .has-focus").forEach((oldUl) => oldUl.classList.remove("has-focus")); 17 | 18 | listItemsFocus.forEach((li) => { 19 | if (!li.nextElementSibling || li.nextElementSibling.tagName !== "UL" || li.nextElementSibling.classList.contains("fn__none")) { 20 | if (li.parentNode instanceof Element) { 21 | li.parentNode.classList.add("has-focus"); 22 | } 23 | } 24 | }); 25 | } 26 | 27 | export function removeIndentGuidesFormatClassName() { 28 | document.querySelectorAll(".file-tree .has-focus").forEach((el) => el.classList.remove("has-focus")); 29 | } 30 | -------------------------------------------------------------------------------- /src/modules/status.ts: -------------------------------------------------------------------------------- 1 | import { hasDockb, isDockHidden, isDockLytExpanded, isDockLytPinned, isStatusHidden } from "../util/interfaceState"; 2 | import { asriDoms as doms, environment as env } from "../util/rsc"; 3 | import { debounce, isOverlapping, querySelectorAsync } from "../util/misc"; 4 | 5 | export const debouncedStatusPosition = debounce(statusPosition); 6 | 7 | /** 8 | * Calculate the position of status bar when there is a change of the display of docks and their layouts. 9 | */ 10 | export async function statusPosition() { 11 | if (env.isMobile || env.isMiniWindow) return; 12 | if (!doms.status) await querySelectorAsync("#status"); 13 | if (!(await hasDockb())) { 14 | function setStatusTransform(x: number, y: number) { 15 | // doms.status!.style.transform = `translate(${x}px, ${y}px)`; 16 | doms.status!.style.setProperty("--asri-status-transform-x", `${x}px`); 17 | doms.status!.style.setProperty("--asri-status-transform-y", `${y}px`); 18 | } 19 | 20 | let layoutCenter = (doms.layouts || (await querySelectorAsync("#layouts")))!.querySelector(".layout__center"); 21 | 22 | if (layoutCenter && doms.layoutDockR && !doms.status!.classList.contains(".fn__none")) { 23 | let layoutDockrWidth = doms.layoutDockR.clientWidth; 24 | let layoutCenterWidth = layoutCenter.clientWidth; 25 | let y = 0; 26 | 27 | doms.layoutDockB || (await querySelectorAsync(".layout__dockb")); 28 | 29 | if (doms.layoutDockB && !doms.layoutDockB.classList.contains(".fn__none") && isDockLytPinned("B")) { 30 | y = doms.layoutDockB.clientHeight * -1; 31 | } else { 32 | y = 0; 33 | } 34 | 35 | doms.status!.style.maxWidth = layoutCenterWidth - 12 + "px"; 36 | 37 | let isDockRightHidden = isDockHidden("R"), 38 | isLayoutDockRightHidden = !isDockLytPinned("R") && isDockLytExpanded("R"); 39 | if (isDockRightHidden && isLayoutDockRightHidden) setStatusTransform(0, y); 40 | else if (!isDockRightHidden && isLayoutDockRightHidden) setStatusTransform(-40, y); 41 | else if (!isDockRightHidden && !isLayoutDockRightHidden) setStatusTransform((layoutDockrWidth + 40) * -1, y); 42 | else if (isDockRightHidden && !isLayoutDockRightHidden) setStatusTransform(layoutDockrWidth * -1, y); 43 | 44 | // doms.status = document.getElementById('status'); 45 | } 46 | } else { 47 | doms.status?.style.removeProperty("max-width"); 48 | doms.status?.style.removeProperty("--asri-status-transform-x"); 49 | doms.status?.style.removeProperty("--asri-status-transform-y"); 50 | } 51 | 52 | // if (!hasDockb() && !isLayoutDockHidden('b')) { 53 | // let layoutDockbHeight = asriDoms.layoutDockb?.clientHeight; 54 | // asriDoms.status.style.transform = `translateY(-${layoutDockbHeight + 42}px)`; 55 | // } 56 | } 57 | 58 | export function setStatusHeightVar() { 59 | const statusHeight = isStatusHidden() ? 0 : 32; 60 | // fastdom.mutate(() => { 61 | document.body.style.setProperty("--status-height", `${statusHeight}px`); 62 | // }) 63 | } 64 | 65 | export function removeStatusStyles() { 66 | document.body.style.removeProperty("--status-height"); 67 | setTimeout(() => { 68 | doms.status?.style.removeProperty("max-width"); 69 | doms.status?.style.removeProperty("--asri-status-transform-x"); 70 | doms.status?.style.removeProperty("--asri-status-transform-y"); 71 | }, 200); 72 | } 73 | 74 | export function avoidOverlappingWithStatus() { 75 | if (!isStatusHidden()) { 76 | const layoutTabContainers = doms.layouts?.querySelectorAll(".layout__center .layout-tab-container"); 77 | const status = doms.status; 78 | // let statusRect = doms.status?.getBoundingClientRect(); 79 | 80 | layoutTabContainers?.forEach((layoutTabContainer) => { 81 | let fileTree = layoutTabContainer.querySelector(".file-tree"); 82 | if (fileTree && !fileTree.classList.contains("fn__none")) { 83 | // let containerRect = layoutTabContainer.getBoundingClientRect(); 84 | if (isOverlapping(layoutTabContainer as AsriDomsExtended, status)) { 85 | (layoutTabContainer as AsriDomsExtended)!.style.paddingBottom = "35px"; 86 | } else { 87 | (layoutTabContainer as AsriDomsExtended)!.style.removeProperty("padding-bottom"); 88 | } 89 | } else { 90 | (layoutTabContainer as AsriDomsExtended)!.style.removeProperty("padding-bottom"); 91 | } 92 | }); 93 | 94 | const searchList = document.getElementById("searchList") as AsriDomsExtended; 95 | const searchPreview = document.getElementById("searchPreview") as AsriDomsExtended; 96 | if (searchList || searchPreview) { 97 | // let searchListRect = searchList.getBoundingClientRect(); 98 | // let searchPreviewRect = searchPreview.getBoundingClientRect(); 99 | 100 | if (isOverlapping(searchList, status)) { 101 | searchList!.style.paddingBottom = "35px"; 102 | } else { 103 | searchList!.style.removeProperty("padding-bottom"); 104 | } 105 | 106 | if (isOverlapping(searchPreview, status)) { 107 | searchPreview!.style.paddingBottom = "35px"; 108 | } else { 109 | searchPreview!.style.removeProperty("padding-bottom"); 110 | } 111 | } 112 | 113 | // pdfviewer 114 | const viewerContainer = document.getElementById("viewerContainer"); 115 | 116 | if (viewerContainer) { 117 | // let viewerContainerRect = viewerContainer.getBoundingClientRect(); 118 | 119 | if (isOverlapping(viewerContainer, status)) { 120 | viewerContainer.style.paddingBottom = "35px"; 121 | } else { 122 | viewerContainer.style.removeProperty("padding-bottom"); 123 | } 124 | } 125 | 126 | // flashcard in tabbar 127 | doms.layouts?.querySelectorAll(".card__main").forEach((card) => { 128 | if (card) { 129 | // let cardRect = card.getBoundingClientRect(); 130 | 131 | if (isOverlapping(card as AsriDomsExtended, status)) { 132 | (card as AsriDomsExtended)!.style.paddingBottom = "35px"; 133 | } else { 134 | (card as AsriDomsExtended)!.style.removeProperty("padding-bottom"); 135 | } 136 | } 137 | }); 138 | } 139 | } 140 | 141 | export function unloadAvoidOverlappingWithStatus() { 142 | doms.layouts?.querySelectorAll(".layout__center .layout-tab-container").forEach((layoutTabContainer) => { 143 | (layoutTabContainer as AsriDomsExtended)!.style.removeProperty("padding-bottom"); 144 | }); 145 | 146 | doms.layouts?.querySelectorAll(".card__main").forEach((card) => { 147 | (card as AsriDomsExtended)!.style.removeProperty("padding-bottom"); 148 | }); 149 | 150 | const searchList = document.getElementById("searchList"); 151 | const searchPreview = document.getElementById("searchPreview"); 152 | const viewerContainer = document.getElementById("viewerContainer"); 153 | 154 | for (const el of [searchList, searchPreview, viewerContainer]) { 155 | if (el) { 156 | el.style.removeProperty("padding-bottom"); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/modules/trafficLights.ts: -------------------------------------------------------------------------------- 1 | import { remote } from "../util/electron"; 2 | import { environment as env } from "../util/rsc"; 3 | 4 | function setTrafficLightPosition(x: number, y = x) { 5 | if (remote) { 6 | remote.getCurrentWindow().setWindowButtonPosition({ x: x, y: y }); 7 | } 8 | } 9 | 10 | export function applyTrafficLightPosition() { 11 | if (env.isMacOS) { 12 | if (!env.isInBrowser) setTrafficLightPosition(16); 13 | if (env.isMiniWindow) setTrafficLightPosition(14); 14 | } 15 | } 16 | 17 | export function restoreTrafficLightPosition() { 18 | if (env.isMacOS) { 19 | if (!env.isInBrowser) setTrafficLightPosition(8); 20 | if (env.isMiniWindow) setTrafficLightPosition(8, 13); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/types/asri.d.ts: -------------------------------------------------------------------------------- 1 | type AsriDomsExtended = HTMLElement | null | undefined; 2 | type ElDir = "L" | "R" | "B"; 3 | -------------------------------------------------------------------------------- /src/types/html.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.html" { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /src/types/siyuan.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | destroyTheme: () => void; 3 | siyuan: { 4 | config: any; 5 | [key: string]: any; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /src/util/api.ts: -------------------------------------------------------------------------------- 1 | // 思源 API 2 | // [cc-baselib/siYuanApi.js at main · leolee9086/cc-baselib](https://github.com/leolee9086/cc-baselib/blob/main/src/siYuanApi.js) 3 | // Rem Craft/util/api.js 4 | 5 | export { getFile, putFile, setBlockAttrs, getBlockAttrs }; 6 | 7 | async function getFile(path: string) { 8 | const response = await fetch("/api/file/getFile", { 9 | method: "POST", 10 | // https://github.com/siyuan-note/siyuan/issues/14571 11 | // headers: { 12 | // Authorization: `Token ''`, 13 | // }, 14 | body: JSON.stringify({ 15 | path: path, 16 | }), 17 | }); 18 | if (response.ok) return response; 19 | else return null; 20 | } 21 | 22 | async function putFile(path: string, filedata: BlobPart, isDir = false, modTime = Date.now()) { 23 | let blob = new Blob([filedata]); 24 | let fileName = path.split("/").pop() as string; 25 | let file = new File([blob], fileName); 26 | let formdata = new FormData(); 27 | formdata.append("path", path); 28 | formdata.append("file", file); 29 | formdata.append("isDir", String(isDir)); 30 | formdata.append("modTime", String(modTime)); 31 | const response = await fetch("/api/file/putFile", { 32 | body: formdata, 33 | method: "POST", 34 | //https://github.com/siyuan-note/siyuan/issues/14571 35 | // headers: { 36 | // Authorization: `Token ''`, 37 | // }, 38 | }); 39 | if (response.ok) return await response.json(); 40 | else return null; 41 | } 42 | 43 | async function setBlockAttrs(blockId: string, attrObj: any) { 44 | let url = "/api/attr/setBlockAttrs"; 45 | // console.log(url, blockId, attrObj) 46 | return resolveResponse( 47 | requestFromSiyuan(url, { 48 | "id": blockId, 49 | "attrs": attrObj, 50 | }) 51 | ); 52 | } 53 | 54 | async function getBlockAttrs(id: string) { 55 | let url = "/api/attr/getBlockAttrs"; 56 | return resolveResponse( 57 | requestFromSiyuan(url, { 58 | "id": id, 59 | }) 60 | ); 61 | } 62 | 63 | async function resolveResponse(response: any) { 64 | let r = await response; 65 | // console.log(r) 66 | return r["code"] === 0 ? r["data"] : null; 67 | } 68 | async function requestFromSiyuan(url: any, data: any) { 69 | let resData = null; 70 | await fetch(url, { 71 | "body": JSON.stringify(data), 72 | "method": "POST", 73 | "headers": { 74 | "Authorization": `Token ${""}`, 75 | }, 76 | }).then(function (response) { 77 | resData = response.json(); 78 | }); 79 | return resData; 80 | } 81 | -------------------------------------------------------------------------------- /src/util/electron.ts: -------------------------------------------------------------------------------- 1 | import { environment as env } from "./rsc"; 2 | 3 | export const remote = env.isInBrowser || env.isMobile ? null : require("@electron/remote"); 4 | -------------------------------------------------------------------------------- /src/util/eventListeners.ts: -------------------------------------------------------------------------------- 1 | type EventListenerTarget = HTMLElement | Document | Window | MediaQueryList; 2 | 3 | export class AsriEventListener { 4 | callback: (e: T) => void; 5 | constructor(callback: (e: T) => void) { 6 | this.callback = callback; 7 | } 8 | 9 | start(target: E, eventName: string, option = false) { 10 | target.addEventListener(eventName, this.callback as (e: Event) => void, option); 11 | } 12 | 13 | remove(target: E, eventName: string, option = false) { 14 | target.removeEventListener(eventName, this.callback as (e: Event) => void, option); 15 | } 16 | // init() { 17 | // document.addEventListener('click', (e) => { 18 | // const target = e.target as HTMLElement 19 | // if (target.classList.contains('b3-dialog__close')) { 20 | // const dialog = target.closest('.b3-dialog') 21 | // if (dialog) { 22 | // dialog.classList.remove('b3-dialog--open') 23 | // } 24 | // } 25 | // }) 26 | // } 27 | } 28 | -------------------------------------------------------------------------------- /src/util/interfaceState.ts: -------------------------------------------------------------------------------- 1 | import { remote } from "./electron"; 2 | import { debounce, querySelectorAllAsync, querySelectorAsync } from "./misc"; 3 | import { asriDoms as doms } from "./rsc"; 4 | 5 | // top bar 6 | export let doesTopBarOverflow = false; 7 | export const debouncedUpdateTopbarOverflow = debounce(updateTopbarOverflow); 8 | 9 | export function updateTopbarOverflow() { 10 | if (!doms.toolbar) return; 11 | 12 | doesTopBarOverflow = doms.toolbar?.scrollWidth > doms.toolbar.clientWidth; 13 | if (!doms.barMore?.classList.contains("fn__none")) { 14 | doesTopBarOverflow = true; 15 | } 16 | // console.log('measure top bar overflow') 17 | } 18 | 19 | // docks and panels 20 | export function isDockLytPinned(dir: ElDir) { 21 | const dockLayoutEl = dir === "B" ? doms.layoutDockB : dir === "L" ? doms.layoutDockL : doms.layoutDockR; // read properties directly to prevent 'undefined' result after minimizing js 22 | 23 | return !!(dockLayoutEl && !dockLayoutEl.classList.contains("layout--float")); 24 | } 25 | export function isDockLytExpanded(dir: ElDir) { 26 | const dockLayoutEl = dir === "B" ? doms.layoutDockB : dir === "L" ? doms.layoutDockL : doms.layoutDockR; // read properties directly to prevent 'undefined' result after minimizing js 27 | let size: string | undefined; 28 | if (!dockLayoutEl) return false; 29 | 30 | if (dir === "B") { 31 | size = (dockLayoutEl as HTMLElement).style.height; 32 | } else { 33 | size = (dockLayoutEl as HTMLElement).style.width; 34 | } 35 | 36 | return !!(size && size !== "0px"); 37 | } 38 | 39 | export function isDockHidden(dir: ElDir = "L") { 40 | const dock = dir === "B" ? doms.dockB : dir === "L" ? doms.dockL : doms.dockR; // read properties directly to prevent 'undefined' result after minimizing js 41 | return !!(dock && dock.classList.contains("fn__none")); 42 | // uses right dock to calculate status bar position: https://github.com/mustakshif/Asri/issues/16 43 | } 44 | // export function isFloatDockLytHidden(el: HTMLElement): boolean { 45 | // return !isDockLytPinned(el) && el?.style.cssText.includes('transform: translate'); 46 | // } 47 | 48 | // bottom dock 49 | export async function hasDockb() { 50 | if (!doms.dockB) await querySelectorAsync(".layout__dockb"); 51 | return !!(doms.dockB && !doms.dockB.classList.contains("fn__none")); 52 | } 53 | 54 | // export function isLytDockbFloating() { 55 | // let result = false; 56 | // if (!env.isMobile) { 57 | // const layouts = doms.layouts; 58 | // const lytDockb = layouts?.querySelector('.layout__dockb') as AsriDomsExtended; 59 | 60 | // result = !!(layouts && lytDockb?.classList.contains('layout--float') && lytDockb?.style.height !== "0px"); 61 | // } 62 | // return result; 63 | // } 64 | 65 | // fullscreen state in macOS 66 | export function isFullScreen() { 67 | return !!(remote && remote.getCurrentWindow().isFullScreen()); 68 | } 69 | 70 | // status bar 71 | export function isStatusHidden() { 72 | return !!(doms.status && doms.status.classList.contains("fn__none")); 73 | } 74 | 75 | export let wndElements: NodeListOf | undefined = document.querySelectorAll('.layout__center [data-type="wnd"]'); 76 | 77 | /** 78 | * update wnd elements, use before calcTabbarSpacings() and calcProtyleSpacings() 79 | */ 80 | export async function updateWndEls(): Promise | undefined> { 81 | await querySelectorAllAsync('.layout__center [data-type="wnd"]').then((els) => { 82 | wndElements = els; 83 | }); 84 | return wndElements; 85 | } 86 | -------------------------------------------------------------------------------- /src/util/observers.ts: -------------------------------------------------------------------------------- 1 | export class AsriResizeObserver { 2 | ro: ResizeObserver; 3 | callback: ResizeObserverCallback; 4 | constructor(callback: ResizeObserverCallback) { 5 | this.callback = (entries, observer) => callback(entries, observer); 6 | this.ro = new ResizeObserver(this.callback); 7 | } 8 | observe(target: Element, options?: ResizeObserverOptions) { 9 | this.ro.observe(target, options); 10 | } 11 | 12 | disconnect(callback?: () => any) { 13 | this.ro.disconnect(); 14 | if (callback) callback(); 15 | } 16 | 17 | unobserve(target: Element) { 18 | this.ro.unobserve(target); 19 | } 20 | } 21 | 22 | export class AsriMutationObserver { 23 | mo: MutationObserver; 24 | callback: MutationCallback; 25 | 26 | constructor(callback: MutationCallback) { 27 | this.callback = (mutationList, observer) => callback(mutationList, observer); 28 | this.mo = new MutationObserver(this.callback); 29 | } 30 | 31 | observe(target: Node, options?: MutationObserverInit) { 32 | this.mo.observe(target, options); 33 | } 34 | 35 | disconnect(callback?: () => any) { 36 | // const mutations = this.mo.takeRecords(); 37 | // if (mutations) { 38 | // this.callback(mutations, this.mo); 39 | // } 40 | this.mo.disconnect(); 41 | if (callback) callback(); 42 | } 43 | } 44 | 45 | export const MOConfigForClassNames: MutationObserverInit = { 46 | attributes: true, // 监视属性变化 47 | subtree: true, // 包含目标节点的后代节点 48 | attributeFilter: ["class"], // 只关注"class"属性的变化 49 | attributeOldValue: true, 50 | }; 51 | -------------------------------------------------------------------------------- /src/util/rsc.ts: -------------------------------------------------------------------------------- 1 | const ua = navigator.userAgent; 2 | 3 | let _layouts: AsriDomsExtended = null; 4 | let _layoutCenter: AsriDomsExtended = null; 5 | let _toolbar: AsriDomsExtended = null; 6 | let _dockL: AsriDomsExtended = null; 7 | let _dockR: AsriDomsExtended = null; 8 | let _dockB: AsriDomsExtended = null; 9 | let _status: AsriDomsExtended = null; 10 | let _layoutDockL: AsriDomsExtended = null; 11 | let _layoutDockR: AsriDomsExtended = null; 12 | let _layoutDockB: AsriDomsExtended = null; 13 | let _barSync: AsriDomsExtended = null; 14 | let _barForward: AsriDomsExtended = null; 15 | let _toolbarVIP: AsriDomsExtended = null; 16 | let _drag: AsriDomsExtended = null; 17 | let _barPlugins: AsriDomsExtended = null; 18 | let _barSearch: AsriDomsExtended = null; 19 | let _barMode: AsriDomsExtended = null; 20 | let _barMore: AsriDomsExtended = null; 21 | 22 | export const asriDoms = { 23 | get layouts() { 24 | return (_layouts ??= document.getElementById("layouts")); 25 | }, 26 | get layoutCenter() { 27 | return (_layoutCenter ??= document.querySelector(".layout__center") as HTMLElement); 28 | }, 29 | get toolbar() { 30 | return (_toolbar ??= document.getElementById("toolbar")); 31 | }, 32 | get dockL() { 33 | return (_dockL ??= document.getElementById("dockLeft")); 34 | }, 35 | get dockR() { 36 | return (_dockR ??= document.getElementById("dockRight")); 37 | }, 38 | get dockB() { 39 | return (_dockB ??= document.getElementById("dockBottom")); 40 | }, 41 | get status() { 42 | return (_status ??= document.getElementById("status")); 43 | }, 44 | get layoutDockL() { 45 | return (_layoutDockL ??= document.querySelector(".layout__dockl") as HTMLElement); 46 | }, 47 | get layoutDockR() { 48 | return (_layoutDockR ??= document.querySelector(".layout__dockr") as HTMLElement); 49 | }, 50 | get layoutDockB() { 51 | return (_layoutDockB ??= document.querySelector(".layout__dockb") as HTMLElement); 52 | }, 53 | get barSync() { 54 | return (_barSync ??= document.getElementById("barSync")); 55 | }, 56 | get barForward() { 57 | return (_barForward ??= document.getElementById("barForward")); 58 | }, 59 | get toolbarVIP() { 60 | return (_toolbarVIP ??= document.getElementById("toolbarVIP")); 61 | }, 62 | get drag() { 63 | return (_drag ??= document.getElementById("drag")); 64 | }, 65 | get barPlugins() { 66 | return (_barPlugins ??= document.getElementById("barPlugins")); 67 | }, 68 | get barSearch() { 69 | return (_barSearch ??= document.getElementById("barSearch")); 70 | }, 71 | get barMode() { 72 | return (_barMode ??= document.getElementById("barMode")); 73 | }, 74 | get barMore() { 75 | return (_barMore ??= document.getElementById("barMore")); 76 | }, 77 | }; 78 | 79 | export const environment = { 80 | isMacOS: navigator.platform.indexOf("Mac") > -1, 81 | isLinux: navigator.platform.indexOf("Linux") > -1, 82 | isAndroid: /Android/.test(ua), 83 | isMobile: !!document.getElementById("sidebar"), 84 | isInBrowser: !ua.startsWith("SiYuan") || ua.indexOf("iPad") > -1 || (/Android/.test(ua) && !/(?:Mobile)/.test(ua)), // tablets use this too 85 | isMiniWindow: document.body.classList.contains("body--window"), 86 | isIOSApp: (/iOS/i.test(ua) || /iPad/i.test(ua)) && /AppleWebKit/i.test(ua) && ua.startsWith("SiYuan/"), 87 | lang: window.siyuan.config.lang as string, 88 | supportOklch: CSS.supports("color", "oklch(from red calc(l * 0.5) 0 h)"), 89 | isReadOnly: window.siyuan.config.readonly as boolean, 90 | appSchemeMode: window.siyuan.config.appearance.mode > 0 ? "dark" : ("light" as "dark" | "light"), 91 | isSafari: /^((?!chrome|android).)*safari/i.test(ua), 92 | }; 93 | -------------------------------------------------------------------------------- /src/util/syAPI.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2023 frostime. All rights reserved. 3 | * https://github.com/frostime/sy-plugin-template-vite 4 | * 5 | * See API Document in [API.md](https://github.com/siyuan-note/siyuan/blob/master/API.md) 6 | * API 文档见 [API_zh_CN.md](https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md) 7 | */ 8 | 9 | import { fetchSyncPost, IWebSocketData } from "siyuan"; 10 | 11 | async function request(url: string, data: any) { 12 | let response: IWebSocketData = await fetchSyncPost(url, data); 13 | let res = response.code === 0 ? response.data : null; 14 | return res; 15 | } 16 | 17 | // **************************************** File **************************************** 18 | 19 | export async function getFile(path: string): Promise { 20 | let data = { 21 | path: path, 22 | }; 23 | let url = "/api/file/getFile"; 24 | try { 25 | let file = await fetchSyncPost(url, data); 26 | return file; 27 | } catch (error_msg) { 28 | return null; 29 | } 30 | } 31 | 32 | export async function putFile(path: string, isDir = false, file: any) { 33 | let form = new FormData(); 34 | form.append("path", path); 35 | form.append("isDir", isDir.toString()); 36 | // Copyright (c) 2023, terwer. 37 | // https://github.com/terwer/siyuan-plugin-importer/blob/v1.4.1/src/api/kernel-api.ts 38 | form.append("modTime", Math.floor(Date.now() / 1000).toString()); 39 | form.append("file", file); 40 | let url = "/api/file/putFile"; 41 | return request(url, form); 42 | } 43 | 44 | export async function removeFile(path: string) { 45 | let data = { 46 | path: path, 47 | }; 48 | let url = "/api/file/removeFile"; 49 | return request(url, data); 50 | } 51 | 52 | // **************************************** Attributes **************************************** 53 | // export async function setBlockAttrs(id: string, attrs: { [key: string]: string }) { 54 | // let data = { 55 | // id: id, 56 | // attrs: attrs 57 | // } 58 | // let url = '/api/attr/setBlockAttrs'; 59 | // return request(url, data); 60 | // } 61 | 62 | // export async function getBlockAttrs(id: string): Promise<{ [key: string]: string }> { 63 | // let data = { 64 | // id: id 65 | // } 66 | // let url = '/api/attr/getBlockAttrs'; 67 | // return request(url, data); 68 | // } 69 | -------------------------------------------------------------------------------- /styles/_main.scss: -------------------------------------------------------------------------------- 1 | @use "layout"; 2 | 3 | @use "protyle"; 4 | 5 | @use "components"; 6 | 7 | @use "features"; 8 | 9 | @use "platforms"; 10 | 11 | @use "plugins"; 12 | 13 | @use "palettes"; 14 | 15 | .body-asri--linux { 16 | @extend .body--win32; 17 | } 18 | -------------------------------------------------------------------------------- /styles/_theme.scss: -------------------------------------------------------------------------------- 1 | @use "./base" as *; 2 | 3 | :root { 4 | --b3-border-radius-b: 16px; // SiYuan 定义的对话框圆角 5 | 6 | &, 7 | &:lang(zh_CN) { 8 | --b3-font-family: system-ui, ui-sans-serif, -apple-system, 9 | "Emojis Additional", "Emojis Reset", BlinkMacSystemFont, "SF Pro Text", 10 | "SF Pro Icons", "Helvetica Neue", "Luxi Sans", "DejaVu Sans", 11 | "PingFang SC", "Segoe UI", "Microsoft Yahei", "Hiragino Sans GB", 12 | sans-serif, "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", 13 | "Android Emoji", "EmojiSymbols"; 14 | 15 | --b3-font-family-code: SF Mono, "JetBrains Mono", JetBrainsMono-Regular, 16 | Menlo, mononoki, Consolas, "Liberation Mono", Courier, "Apple Color Emoji", 17 | "Segoe UI Emoji", "Noto Color Emoji", "Segoe UI Symbol", "Android Emoji", 18 | "EmojiSymbols", var(--b3-font-family), monospace; 19 | 20 | // --b3-font-family-emoji: "Apple Color Emoji", "Emojis Additional", "Emojis Reset"; 21 | 22 | // --b3-font-family-graph: mononoki; 23 | 24 | // --b3-font-family-emoji: "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "Android Emoji"; 25 | 26 | // --b3-font-family-math: KaTeX_Math; 27 | } 28 | 29 | &:lang(ja_JP) { 30 | --b3-font-family: ui-sans-serif, -apple-system, "Emojis Additional", 31 | "Emojis Reset", BlinkMacSystemFont, "SF Pro Text", "SF Pro Icons", 32 | "Helvetica Neue", "Luxi Sans", "DejaVu Sans", "Hiragino Sans", 33 | "Yu Gothic UI", "PingFang SC", "Segoe UI", "Microsoft Yahei", 34 | "Hiragino Sans GB", sans-serif, "Segoe UI Emoji", "Noto Color Emoji", 35 | "Segoe UI Symbol", "Android Emoji", "EmojiSymbols"; 36 | } 37 | 38 | // interpolate-size: allow-keywords; // https://developer.chrome.com/docs/css-ui/animate-to-height-auto/ 39 | 40 | @include common-anim-css-vars; 41 | } 42 | 43 | // dark first to fix font color and background color abnormality in pdf export 44 | [data-theme-mode="dark"] { 45 | &:root { 46 | color-scheme: dark; 47 | // https://stackoverflow.com/questions/21157231/mac-os-x-scrollbar-is-sometimes-white-transparent-and-sometimes-black-transpare 48 | } 49 | 50 | &:root // body.has-exportimg 51 | { 52 | @include theme-root($theme-dark); 53 | } 54 | 55 | // use hex to fix ios top bar color 56 | .body-asri--iosApp { 57 | --b3-theme-background: #161616; 58 | --b3-parent-background: var(--b3-theme-background); 59 | } 60 | } 61 | 62 | [data-theme-mode="light"] { 63 | &:root // fix being overridden by other themes 64 | 65 | // body.has-exportimg 66 | { 67 | @include theme-root($theme-light); 68 | } 69 | 70 | body { 71 | ::selection { 72 | background-color: var(--b3-theme-primary-lightest); 73 | } 74 | } 75 | 76 | // use hex to fix https://github.com/mustakshif/Asri/issues/39 77 | .body-asri--mobile { 78 | --b3-theme-background: #fff; 79 | --b3-parent-background: var(--b3-theme-background); 80 | } 81 | } 82 | 83 | body { 84 | text-underline-position: under; 85 | text-decoration-skip-ink: all; // not supported yet 86 | 87 | &:not(.body--win32, .body-asri--linux) { 88 | scrollbar-width: thin; 89 | scrollbar-color: var(--b3-scroll-color-hover) var(--b3-theme-background-light, #0000); 90 | } 91 | 92 | [data-theme-mode="light"] & { 93 | -webkit-font-smoothing: auto; 94 | } 95 | 96 | // fix being overridden by other themes 97 | --b3-toolbar-left-mac: 80px; 98 | --toolbar-height: 48px; 99 | 100 | // @include darkmode-counterpart { 101 | // -webkit-font-smoothing: antialiased; 102 | // } 103 | 104 | &[arco-theme] { 105 | font-family: var(--b3-font-family); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /styles/base/common.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * global vars 3 | */ 4 | $border-rd-card: 20px; 5 | $border-rd-popover: 12px; 6 | $border-rd-menu: 10px; 7 | $border-rd-tab: 8px; 8 | $border-rd-default: 6px; 9 | 10 | // $timing-function-decelerate: cubic-bezier(0, 0, 0, 1); 11 | // $timing-function-accelerate: cubic-bezier(0.3, 0, 1, 1); 12 | 13 | // $timing-function-bouncy-both: cubic-bezier(0.68, -0.55, 0.265, 1.55); 14 | // $timing-function-bouncy-end: cubic-bezier(0, 0, 0.27, 1.55); 15 | 16 | $text-underline-thickness: 0.08em; 17 | 18 | @mixin common-anim-css-vars { 19 | // copied from https://unpkg.com/open-props/easings.min.css, 2025-01-08 20 | // added prefix 'asri' to avoid potential conflicts 21 | 22 | --asri-ease-1: cubic-bezier(0.25, 0, 0.5, 1); 23 | --asri-ease-2: cubic-bezier(0.25, 0, 0.4, 1); 24 | --asri-ease-3: cubic-bezier(0.25, 0, 0.3, 1); 25 | --asri-ease-4: cubic-bezier(0.25, 0, 0.2, 1); 26 | --asri-ease-5: cubic-bezier(0.25, 0, 0.1, 1); 27 | --asri-ease-in-1: cubic-bezier(0.25, 0, 1, 1); 28 | --asri-ease-in-2: cubic-bezier(0.5, 0, 1, 1); 29 | --asri-ease-in-3: cubic-bezier(0.7, 0, 1, 1); 30 | --asri-ease-in-4: cubic-bezier(0.9, 0, 1, 1); 31 | --asri-ease-in-5: cubic-bezier(1, 0, 1, 1); 32 | --asri-ease-out-1: cubic-bezier(0, 0, 0.75, 1); 33 | --asri-ease-out-2: cubic-bezier(0, 0, 0.5, 1); 34 | --asri-ease-out-3: cubic-bezier(0, 0, 0.3, 1); 35 | --asri-ease-out-4: cubic-bezier(0, 0, 0.1, 1); 36 | --asri-ease-out-5: cubic-bezier(0, 0, 0, 1); 37 | --asri-ease-in-out-1: cubic-bezier(0.1, 0, 0.9, 1); 38 | --asri-ease-in-out-2: cubic-bezier(0.3, 0, 0.7, 1); 39 | --asri-ease-in-out-3: cubic-bezier(0.5, 0, 0.5, 1); 40 | --asri-ease-in-out-4: cubic-bezier(0.7, 0, 0.3, 1); 41 | --asri-ease-in-out-5: cubic-bezier(0.9, 0, 0.1, 1); 42 | --asri-ease-elastic-out-1: cubic-bezier(0.5, 0.75, 0.75, 1.25); 43 | --asri-ease-elastic-out-2: cubic-bezier(0.5, 1, 0.75, 1.25); 44 | --asri-ease-elastic-out-3: cubic-bezier(0.5, 1.25, 0.75, 1.25); 45 | --asri-ease-elastic-out-4: cubic-bezier(0.5, 1.5, 0.75, 1.25); 46 | --asri-ease-elastic-out-5: cubic-bezier(0.5, 1.75, 0.75, 1.25); 47 | --asri-ease-elastic-in-1: cubic-bezier(0.5, -0.25, 0.75, 1); 48 | --asri-ease-elastic-in-2: cubic-bezier(0.5, -0.5, 0.75, 1); 49 | --asri-ease-elastic-in-3: cubic-bezier(0.5, -0.75, 0.75, 1); 50 | --asri-ease-elastic-in-4: cubic-bezier(0.5, -1, 0.75, 1); 51 | --asri-ease-elastic-in-5: cubic-bezier(0.5, -1.25, 0.75, 1); 52 | --asri-ease-elastic-in-out-1: cubic-bezier(0.5, -0.1, 0.1, 1.5); 53 | --asri-ease-elastic-in-out-2: cubic-bezier(0.5, -0.3, 0.1, 1.5); 54 | --asri-ease-elastic-in-out-3: cubic-bezier(0.5, -0.5, 0.1, 1.5); 55 | --asri-ease-elastic-in-out-4: cubic-bezier(0.5, -0.7, 0.1, 1.5); 56 | --asri-ease-elastic-in-out-5: cubic-bezier(0.5, -0.9, 0.1, 1.5); 57 | --asri-ease-step-1: steps(2); 58 | --asri-ease-step-2: steps(3); 59 | --asri-ease-step-3: steps(4); 60 | --asri-ease-step-4: steps(7); 61 | --asri-ease-step-5: steps(10); 62 | --asri-ease-elastic-1: var(--asri-ease-elastic-out-1); 63 | --asri-ease-elastic-2: var(--asri-ease-elastic-out-2); 64 | --asri-ease-elastic-3: var(--asri-ease-elastic-out-3); 65 | --asri-ease-elastic-4: var(--asri-ease-elastic-out-4); 66 | --asri-ease-elastic-5: var(--asri-ease-elastic-out-5); 67 | --asri-ease-squish-1: var(--asri-ease-elastic-in-out-1); 68 | --asri-ease-squish-2: var(--asri-ease-elastic-in-out-2); 69 | --asri-ease-squish-3: var(--asri-ease-elastic-in-out-3); 70 | --asri-ease-squish-4: var(--asri-ease-elastic-in-out-4); 71 | --asri-ease-squish-5: var(--asri-ease-elastic-in-out-5); 72 | --asri-ease-spring-1: linear(0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 25.3%, 0.849 31.5%, 0.937 38.1%, 0.968 41.8%, 0.991 45.7%, 1.006 50.1%, 1.015 55%, 1.017 63.9%, 1.001); 73 | --asri-ease-spring-2: linear(0, 0.007, 0.029 2.2%, 0.118 4.7%, 0.625 14.4%, 0.826 19%, 0.902, 0.962, 1.008 26.1%, 1.041 28.7%, 1.064 32.1%, 1.07 36%, 1.061 40.5%, 1.015 53.4%, 0.999 61.6%, 0.995 71.2%, 1); 74 | --asri-ease-spring-3: linear(0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%, 0.938 16.7%, 1.017, 1.077, 1.121, 1.149 24.3%, 1.159, 1.163, 1.161, 1.154 29.9%, 1.129 32.8%, 1.051 39.6%, 1.017 43.1%, 0.991, 0.977 51%, 0.974 53.8%, 0.975 57.1%, 0.997 69.8%, 1.003 76.9%, 1); 75 | --asri-ease-spring-4: linear(0, 0.009, 0.037 1.7%, 0.153 3.6%, 0.776 10.3%, 1.001, 1.142 16%, 1.185, 1.209 19%, 1.215 19.9% 20.8%, 1.199, 1.165 25%, 1.056 30.3%, 1.008 33%, 0.973, 0.955 39.2%, 0.953 41.1%, 0.957 43.3%, 0.998 53.3%, 1.009 59.1% 63.7%, 0.998 78.9%, 1); 76 | --asri-ease-spring-5: linear(0, 0.01, 0.04 1.6%, 0.161 3.3%, 0.816 9.4%, 1.046, 1.189 14.4%, 1.231, 1.254 17%, 1.259, 1.257 18.6%, 1.236, 1.194 22.3%, 1.057 27%, 0.999 29.4%, 0.955 32.1%, 0.942, 0.935 34.9%, 0.933, 0.939 38.4%, 1 47.3%, 1.011, 1.017 52.6%, 1.016 56.4%, 1 65.2%, 0.996 70.2%, 1.001 87.2%, 1); 77 | --asri-ease-bounce-1: linear(0, 0.004, 0.016, 0.035, 0.063, 0.098, 0.141, 0.191, 0.25, 0.316, 0.391 36.8%, 0.563, 0.766, 1 58.8%, 0.946, 0.908 69.1%, 0.895, 0.885, 0.879, 0.878, 0.879, 0.885, 0.895, 0.908 89.7%, 0.946, 1); 78 | --asri-ease-bounce-2: linear(0, 0.004, 0.016, 0.035, 0.063, 0.098, 0.141 15.1%, 0.25, 0.391, 0.562, 0.765, 1, 0.892 45.2%, 0.849, 0.815, 0.788, 0.769, 0.757, 0.753, 0.757, 0.769, 0.788, 0.815, 0.85, 0.892 75.2%, 1 80.2%, 0.973, 0.954, 0.943, 0.939, 0.943, 0.954, 0.973, 1); 79 | --asri-ease-bounce-3: linear(0, 0.004, 0.016, 0.035, 0.062, 0.098, 0.141 11.4%, 0.25, 0.39, 0.562, 0.764, 1 30.3%, 0.847 34.8%, 0.787, 0.737, 0.699, 0.672, 0.655, 0.65, 0.656, 0.672, 0.699, 0.738, 0.787, 0.847 61.7%, 1 66.2%, 0.946, 0.908, 0.885 74.2%, 0.879, 0.878, 0.879, 0.885 79.5%, 0.908, 0.946, 1 87.4%, 0.981, 0.968, 0.96, 0.957, 0.96, 0.968, 0.981, 1); 80 | --asri-ease-bounce-4: linear(0, 0.004, 0.016 3%, 0.062, 0.141, 0.25, 0.391, 0.562 18.2%, 1 24.3%, 0.81, 0.676 32.3%, 0.629, 0.595, 0.575, 0.568, 0.575, 0.595, 0.629, 0.676 48.2%, 0.811, 1 56.2%, 0.918, 0.86, 0.825, 0.814, 0.825, 0.86, 0.918, 1 77.2%, 0.94 80.6%, 0.925, 0.92, 0.925, 0.94 87.5%, 1 90.9%, 0.974, 0.965, 0.974, 1); 81 | --asri-ease-bounce-5: linear(0, 0.004, 0.016 2.5%, 0.063, 0.141, 0.25 10.1%, 0.562, 1 20.2%, 0.783, 0.627, 0.534 30.9%, 0.511, 0.503, 0.511, 0.534 38%, 0.627, 0.782, 1 48.7%, 0.892, 0.815, 0.769 56.3%, 0.757, 0.753, 0.757, 0.769 61.3%, 0.815, 0.892, 1 68.8%, 0.908 72.4%, 0.885, 0.878, 0.885, 0.908 79.4%, 1 83%, 0.954 85.5%, 0.943, 0.939, 0.943, 0.954 90.5%, 1 93%, 0.977, 0.97, 0.977, 1); 82 | } 83 | 84 | @mixin line-clamp($line-clamp: 1, $orientation: vertical) { 85 | @supports (-webkit-line-clamp: 1) { 86 | display: -webkit-box; 87 | -webkit-line-clamp: $line-clamp; 88 | -webkit-box-orient: $orientation; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /styles/base/index.scss: -------------------------------------------------------------------------------- 1 | @forward "./common.scss"; 2 | @forward "./colors.scss"; 3 | @forward "./utils.scss"; 4 | @forward "./modes.scss"; 5 | -------------------------------------------------------------------------------- /styles/base/modes.scss: -------------------------------------------------------------------------------- 1 | @use "./colors.scss" as *; 2 | 3 | @mixin darkmode-counterpart($root: false) { 4 | $selector: if($root, "&[data-theme-mode=dark]", "[data-theme-mode=dark] &"); 5 | 6 | #{$selector} { 7 | @content; 8 | } 9 | } 10 | 11 | @mixin theme-variant-color($property, $theme-key, $opacity-light: 1, $opacity-dark: $opacity-light, $important: false) { 12 | $_color: map-get($theme-light, $theme-key); 13 | 14 | @if $_color !=null { 15 | @if $important { 16 | #{$property}: change-color($_color, $alpha: $opacity-light) !important; 17 | } @else { 18 | #{$property}: change-color($_color, $alpha: $opacity-light); 19 | } 20 | } @else { 21 | @warn "No color found for `#{$theme-key}` in `$theme-light`. Please check your `$theme-light` map and the `$theme-key` you are using."; 22 | } 23 | 24 | @include darkmode-counterpart { 25 | $_color: map-get($theme-dark, $theme-key); 26 | 27 | @if $_color !=null { 28 | @if $important { 29 | #{$property}: change-color($_color, $alpha: $opacity-dark) !important; 30 | } @else { 31 | #{$property}: change-color($_color, $alpha: $opacity-dark); 32 | } 33 | } @else { 34 | @warn "No color found for `#{$theme-key}` in `$theme-dark`. Please check your `$theme-dark` map and the `$theme-key` you are using."; 35 | } 36 | } 37 | } 38 | 39 | /* 40 | * 用于暗黑模式模式下给部分元素添加边框 41 | */ 42 | @mixin theme-variant-border($border: true) { 43 | // 使用outline会导致频繁重绘 44 | border: unset; 45 | // border-color: transparent; 46 | @content; 47 | 48 | @include darkmode-counterpart { 49 | @if $border ==true { 50 | outline: 1px solid #fff2; 51 | outline-offset: -1px; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /styles/base/utils.scss: -------------------------------------------------------------------------------- 1 | @function reverse-list($list) { 2 | $reversed: (); 3 | 4 | @for $i from length($list) through 1 { 5 | $reversed: append($reversed, nth($list, $i), comma); 6 | } 7 | 8 | @return $reversed; 9 | } 10 | 11 | @function negateForRTL($value) { 12 | // gnf 值,用于在 rtl 模式下反转值。rtl 模式下 --gnf 的值为 -1 13 | @return calc(var(--gnf, 1) * #{$value}); 14 | } -------------------------------------------------------------------------------- /styles/components/breadcrumb.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | @use "./utils" as *; 3 | 4 | .protyle-breadcrumb { 5 | // padding: 0 4px; 6 | height: 42px; 7 | color: var(--b3-theme-on-surface); 8 | // background-color: transparent; //全屏视图下是透明的 9 | 10 | &__bar { 11 | scrollbar-width: none; 12 | } 13 | 14 | // //面包屑居中 15 | // &::before { 16 | // content: ''; 17 | // // display: block; 18 | // // height: 100%; 19 | // flex-grow: 1; 20 | // } 21 | 22 | .block__icon:hover:not([disabled]):not(.ft__primary) { 23 | background-color: transparent; 24 | } 25 | 26 | // alt+Y 全屏视图 27 | .fullscreen > & { 28 | height: var(--toolbar-height); 29 | padding-right: 10px; 30 | 31 | > .protyle-breadcrumb__space:hover { 32 | background-color: transparent; 33 | } 34 | } 35 | 36 | &__item { 37 | // &:first-child { 38 | // padding: 0; 39 | // } 40 | 41 | // &:last-child { 42 | // .protyle-breadcrumb__text { 43 | // max-width: 21rem; 44 | // } 45 | // } 46 | 47 | svg { 48 | // outline: 2px solid var(--b3-theme-primary); 49 | border-radius: 3px; 50 | padding: 3px; 51 | width: 12px; 52 | height: 12px; 53 | } 54 | 55 | &:not(&--active):hover { 56 | svg { 57 | color: var(--b3-theme-on-background); 58 | } 59 | } 60 | 61 | &--active { 62 | background-color: transparent; 63 | 64 | &:hover { 65 | background-color: var(--b3-list-hover); 66 | } 67 | 68 | &:not(:first-child) { 69 | svg { 70 | background-color: var(--b3-theme-primary); 71 | color: var(--b3-theme-on-primary); 72 | } 73 | } 74 | } 75 | } 76 | 77 | &__arrow { 78 | color: transparent; 79 | margin: 0 6px; 80 | background-color: var(--b3-theme-on-surface); 81 | width: 1.5px; 82 | height: 1em; 83 | border-radius: 2px; 84 | transform: rotate(27deg); 85 | opacity: 0.8; 86 | } 87 | 88 | // 退出聚焦按钮 89 | & &__icon { 90 | @include button-primary; 91 | padding: 0 8px; 92 | margin-right: 4px; 93 | } 94 | 95 | .card__main & { 96 | min-height: 42px; 97 | height: auto; 98 | } // fix https://github.com/mustakshif/Asri/issues/53 99 | } 100 | -------------------------------------------------------------------------------- /styles/components/dialogs/av.scss: -------------------------------------------------------------------------------- 1 | @use "../../protyle/utils" as *; 2 | 3 | // 属性面板视图 4 | .custom-attr .block__logo.custom-attr__avheader { 5 | color: var(--b3-theme-primary); 6 | font-weight: 500; 7 | margin-right: 0; 8 | margin-bottom: 4px; 9 | opacity: 1; 10 | position: sticky; 11 | top: 0; 12 | background-color: var(--b3-theme-background); 13 | z-index: 1; 14 | } 15 | 16 | .custom-attr[data-type="NodeAttributeView"] { 17 | padding-bottom: 16px; 18 | 19 | .custom-attr__avheader { 20 | padding-left: 40px; 21 | padding-right: 16px; 22 | font-weight: 500; 23 | } 24 | 25 | .block__icons { 26 | height: auto; 27 | min-height: unset; 28 | padding: 4px 16px; 29 | } 30 | 31 | .av__row { 32 | .block__logo { 33 | font-weight: 500; 34 | } 35 | 36 | .block__logo ~ .fn__flex-1 { 37 | overflow: visible; 38 | } 39 | 40 | .custom-attr__avvalue { 41 | padding: 4px 0; 42 | 43 | &:empty { 44 | padding: 4px; 45 | } 46 | } 47 | 48 | input, 49 | select, 50 | [data-type="text"] .b3-text-field { 51 | min-height: unset; 52 | height: 28px; 53 | padding: 4px; 54 | 55 | &:hover { 56 | background-color: var(--b3-theme-surface); 57 | } 58 | 59 | &:focus { 60 | background-color: var(--b3-theme-surface); 61 | outline: 3px solid var(--b3-theme-primary-light); 62 | } 63 | } 64 | 65 | [data-type="text"] { 66 | align-self: flex-start; 67 | } 68 | 69 | .b3-chip { 70 | border-radius: 4px; 71 | padding: 2px 6px; 72 | } 73 | 74 | @include database-assets-style() { 75 | color: var(--b3-theme-on-surface); 76 | margin: 2px; 77 | } 78 | } 79 | } 80 | 81 | .custom-attr__avvalue { 82 | &[data-type="relation"] { 83 | flex-direction: column; 84 | 85 | .av__cell--relation { 86 | // margin: 4px 0; 87 | margin-left: unset; 88 | margin: 2px 0; 89 | display: flex; 90 | 91 | &:first-child { 92 | margin-top: 0; 93 | } 94 | 95 | &:last-child { 96 | margin-bottom: 0; 97 | } 98 | } 99 | 100 | .b3-menu__avemoji { 101 | display: inline; 102 | padding-top: 0.1em; 103 | align-self: auto; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /styles/components/dialogs/dialog.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | @use "../utils" as *; 3 | 4 | .b3-dialog { 5 | &__header { 6 | font-weight: 600; 7 | text-align: center; 8 | border-bottom: none; 9 | padding: 18px 18px 6px; 10 | 11 | &:not(.fn__none) + .b3-dialog__body { 12 | .config__panel { 13 | .b3-tab-bar { 14 | margin: 0 8px 8px; 15 | padding: 4px 0; 16 | border-radius: 8px; 17 | } 18 | 19 | .config__tab-container { 20 | padding: 0; 21 | 22 | .layout-tab-bar { 23 | margin-top: 0; 24 | } 25 | } 26 | } 27 | 28 | .history__panel .history__diff { 29 | margin: 0 8px 8px; 30 | border-radius: 8px; 31 | border-right: none; 32 | } 33 | } 34 | } 35 | 36 | &__container { 37 | overflow: hidden; // 窗口中有元素如果混合使用mix-blend-mode 和 backdrop-filter,会导致窗口布局跳动、窗口闪烁 38 | background-color: var(--b3-theme-background); 39 | 40 | @include theme-variant-border; 41 | @include dialog-shadow($extra-shadow-light: "0 0 0 1px rgba(0, 0, 0, 0.05)"); 42 | // box-shadow: none !important; 43 | 44 | @include darkmode-counterpart { 45 | outline-color: #ffffff08; 46 | border: 1px solid var(--b3-border-color-trans); 47 | } 48 | 49 | .resize__r { 50 | transform: translateX(-4px); 51 | } 52 | 53 | .resize__d { 54 | transform: translateY(-4px); 55 | } 56 | 57 | .resize__t { 58 | transform: translateY(4px); 59 | } 60 | 61 | .resize__l { 62 | transform: translateX(4px); 63 | } 64 | 65 | // .b3-dialog__body { 66 | // border-radius: 12px; 67 | // } 68 | } 69 | 70 | &__close { 71 | visibility: hidden; 72 | } 73 | 74 | /* 75 | * 对话框底部按钮区域 76 | */ 77 | &__action { 78 | // padding: 8px 24px; 79 | padding: 6px 18px 18px; 80 | border-top: none; 81 | 82 | .fn__space { 83 | width: 12px; 84 | } 85 | 86 | .b3-button { 87 | &--cancel { 88 | @include button-action("normal"); 89 | } 90 | 91 | &--text { 92 | @include button-action("primary"); 93 | } 94 | 95 | &--remove { 96 | @include button-action("danger"); 97 | } 98 | } 99 | } 100 | 101 | &__content { 102 | word-break: normal; 103 | line-height: 1.6; 104 | padding: 12px 18px; 105 | } 106 | 107 | &__header.fn__none ~ .b3-dialog__body .b3-dialog__content { 108 | padding-top: 18px; 109 | } 110 | 111 | .layout-tab-bar { 112 | @include dialog-tabbar; 113 | } 114 | 115 | // 弹出动画 116 | &__container { 117 | transform: translateY(-30px); 118 | transition: opacity 0.1s linear 0s, transform 0.4s var(--asri-ease-spring-1); 119 | } 120 | 121 | // [data-id]{ 122 | // &[data-type="css"], 123 | // &[data-type="js"] { 124 | // [type="text"].fn__size200.b3-text-field{ 125 | // font-weight: 500; 126 | // } 127 | // } 128 | // } 129 | 130 | &__scrim { 131 | background-color: #80808080; 132 | backdrop-filter: saturate(0.5); 133 | transition: opacity 250ms 0s, backdrop-filter 300ms 0s; 134 | 135 | @include darkmode-counterpart { 136 | background-color: #00000080; 137 | backdrop-filter: saturate(0.3); 138 | } 139 | 140 | // :root[style*="--asri-c-0"] & { 141 | // backdrop-filter: saturate(0); 142 | // } 143 | } 144 | } 145 | 146 | /* 147 | * 对话框中的 tab-bar 148 | */ 149 | // // 仅针对部分对话框的呲边修复 150 | // &[data-key="dialog-setting"], 151 | // // 设置 152 | // &[data-key="dialog-history"] // 文件历史 153 | 154 | // { 155 | // .b3-dialog__container { 156 | // overflow: hidden; 157 | // } 158 | // } 159 | 160 | #transactionError + .b3-dialog__action button:last-child { 161 | @include button-action("primary"); 162 | } 163 | -------------------------------------------------------------------------------- /styles/components/dialogs/emoji.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | 3 | // emoji 面板 4 | [data-key="dialog-emojis"] { 5 | --b3-border-radius-b: 14px; 6 | 7 | .b3-dialog__scrim { 8 | backdrop-filter: none; 9 | transition: none; 10 | 11 | @include darkmode-counterpart { 12 | backdrop-filter: none; 13 | transition: none; 14 | } 15 | } 16 | 17 | .b3-dialog__container { 18 | // outline: 1px solid rgb(map-get($theme-light, on-background), 0.1); 19 | background-color: var(--b3-menu-background); 20 | outline-offset: 0; 21 | @include theme-variant-border($border: true); 22 | 23 | .b3-dialog__body { 24 | border-radius: 11px; 25 | z-index: 0; 26 | } 27 | } 28 | } 29 | 30 | .emojis { 31 | padding: 0; 32 | 33 | // .fn__flex:first-child { 34 | // // margin: 8px 0; 35 | // padding: 8px 0; 36 | 37 | // // 搜索框 38 | // span.fn__space+.b3-form__icon { 39 | // overflow: visible; 40 | // } 41 | // } 42 | 43 | &__tabheader { 44 | padding-top: 8px; 45 | border-color: var(--b3-border-color-trans); 46 | } 47 | 48 | &__tabbody { 49 | [data-type="tab-emoji"] { 50 | > .fn__hr { 51 | display: none; 52 | } 53 | 54 | > .fn__flex:nth-child(2) { 55 | // position: absolute; 56 | // top: 6px; 57 | // margin-inline-start: 64px; 58 | // margin-inline-end: 30px; 59 | // width: -webkit-fill-available; 60 | 61 | margin: 8px 0 2px; 62 | } 63 | } 64 | } 65 | 66 | &__panel { 67 | padding: 0 8px; 68 | 69 | .emojis__content { 70 | display: grid; 71 | flex-wrap: wrap; 72 | grid-template-columns: repeat(auto-fill, minmax(36px, 4fr)); 73 | gap: 12px; 74 | min-height: unset !important; 75 | 76 | .emojis__item { 77 | padding: 0; 78 | font-size: 27px; // 27.5px以上会导致hover时饱和度突然增高??? 79 | height: 36px; 80 | width: 36px; // https://github.com/mustakshif/Asri/issues/153 81 | 82 | &--current { 83 | background-color: transparent; 84 | } 85 | 86 | &:hover { 87 | background: transparent; 88 | transform: scale(1.35); 89 | transition: transform 0.7s var(--asri-ease-spring-4); 90 | transform-origin: 50% 82.5%; 91 | } 92 | } 93 | } 94 | } 95 | 96 | // 保证自定义表情为空时正常显示 97 | &__title[data-type="1"] { 98 | + .emojis__content > div:only-child { 99 | grid-column: 1 / -1; 100 | } 101 | } 102 | 103 | &__panel + .fn__flex { 104 | border-top: 1px solid var(--b3-border-color-trans); 105 | font-family: var(--b3-font-family-emoji); 106 | 107 | .emojis__type { 108 | padding: 4px 0; 109 | filter: saturate(0.1) opacity(0.6); 110 | 111 | &:hover { 112 | filter: none; 113 | background-color: transparent; 114 | } 115 | } 116 | } 117 | 118 | &__item { 119 | border-radius: unset; 120 | } 121 | 122 | &__item img, 123 | &__item svg { 124 | height: 28px; 125 | width: 28px; 126 | margin: 0 auto; 127 | } 128 | 129 | // 自定义表情内容 130 | } 131 | -------------------------------------------------------------------------------- /styles/components/dialogs/export.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | @use "../utils" as *; 3 | 4 | // 导出界面 5 | body[style="-webkit-print-color-adjust: exact;"] { 6 | #action { 7 | .b3-label { 8 | border-bottom: none; 9 | display: flex; 10 | 11 | &:nth-child(-n + 3) { 12 | flex-direction: column; 13 | } 14 | 15 | .fn__hr { 16 | flex-grow: 1; 17 | } 18 | 19 | .b3-switch { 20 | margin-left: 8px; 21 | align-self: center; 22 | } 23 | } 24 | 25 | .b3-button--cancel { 26 | @include button-action("normal"); 27 | } 28 | 29 | .b3-button--text { 30 | @include button-action("primary"); 31 | } 32 | 33 | // padding-bottom: 8px; // unnecessary, use default value 34 | // >:last-child { 35 | // padding: 8px 16px !important; 36 | // } // ❓ don't konw why this statement causes large cpu usage on mobile 37 | } 38 | } 39 | 40 | /* 41 | * 导出窗口 42 | */ 43 | 44 | // #preview { 45 | // font-feature-settings: "ss06" on; 46 | // } //避免在非苹果设备上出现意外的字形渲染结果 47 | 48 | // #aciton { 49 | // .b3-button--cancel { 50 | // @include button-action('normal'); 51 | // } 52 | 53 | // .b3-button--text { 54 | // @include button-action('primary'); 55 | // } 56 | // } 57 | 58 | /* 59 | * 图片预览 60 | */ 61 | .viewer-backdrop { 62 | animation: fadeIn 0.3s; 63 | transform-origin: var(--mouseX) var(--mouseY); 64 | background-color: #bbb; 65 | 66 | @include darkmode-counterpart { 67 | background-color: var(--b3-theme-background); 68 | } 69 | 70 | animation-timing-function: var(--asri-ease-out-5); 71 | 72 | @keyframes fadeIn { 73 | from { 74 | opacity: 0; 75 | transform: scale(0.1); 76 | } 77 | 78 | to { 79 | opacity: 1; 80 | transform: none; 81 | } 82 | } 83 | } 84 | 85 | .viewer-title { 86 | padding: 4px 8px; 87 | background-color: var(--b3-theme-surface); 88 | border-radius: 99px; 89 | @include theme-variant-border($border: false); 90 | } 91 | 92 | .viewer-toolbar { 93 | > ul { 94 | background-color: var(--b3-theme-surface); 95 | padding: 8px; 96 | border-radius: 99px; 97 | @include theme-variant-border($border: false); 98 | 99 | > li { 100 | background-color: transparent; 101 | 102 | &:hover { 103 | background-color: var(--b3-list-hover); 104 | 105 | > svg { 106 | color: var(--b3-theme-on-background); 107 | } 108 | } 109 | 110 | &:focus { 111 | background-color: var(--b3-theme-on-background); 112 | box-shadow: none; 113 | 114 | > svg { 115 | color: var(--b3-menu-background); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /styles/components/dialogs/flashcard.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | @use "../utils" as *; 3 | 4 | /* 5 | * 闪卡复习 6 | */ 7 | .card__main { 8 | .layout-tab-container & { 9 | border-radius: 0; 10 | } 11 | 12 | .card__action { 13 | > div { 14 | body:not(.body-asri--mobile) & { 15 | margin: 0 12px 8px; 16 | } 17 | 18 | // fix https://github.com/mustakshif/Asri/issues/61 19 | } 20 | 21 | .b3-button { 22 | font-weight: 600; 23 | border-radius: $border-rd-card; 24 | transition: 0.2s; 25 | 26 | &:hover { 27 | transform: scale(1.05); 28 | } 29 | 30 | &:active { 31 | transform: scale(0.95); 32 | opacity: 0.8; 33 | box-shadow: none; 34 | } 35 | 36 | &:focus { 37 | box-shadow: none; 38 | } 39 | 40 | $button-colors: ((map-get($theme-light, card-error), map-get($theme-dark, card-error)), (map-get($theme-light, card-warning), map-get($theme-dark, card-warning)), (map-get($theme-light, card-info), map-get($theme-dark, card-info)), (map-get($theme-light, card-success), map-get($theme-dark, card-success))); 41 | 42 | @for $i from 1 through 4 { 43 | &[data-type="#{$i}"]:hover { 44 | @include menu-shadow(nth($button-colors, $i)..., $opacity-dark: 0.2); 45 | } 46 | } 47 | 48 | // 显示答案按钮、(p)按钮 49 | &[data-type="-1"], 50 | &[data-type="-2"] { 51 | &:hover { 52 | transform: none; 53 | box-shadow: none; 54 | } 55 | 56 | &:active { 57 | transform: scale(0.9); 58 | } 59 | } 60 | 61 | // 跳过按钮 62 | &[data-type="-3"]:hover { 63 | background-color: var(--b3-list-hover); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /styles/components/dialogs/functional.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | @use "../utils" as *; 3 | 4 | /* 5 | * 最近文档 6 | */ 7 | [data-key="dialog-recentdocs"] { 8 | .b3-dialog__header { 9 | padding: 12px; 10 | border-bottom: 1px solid var(--b3-border-color); 11 | } 12 | 13 | .b3-list--background:first-child { 14 | background-color: var(--b3-theme-surface); 15 | } 16 | } 17 | 18 | /* 19 | * 笔记本设置 20 | */ 21 | [data-key="dialog-notebookconf"] { 22 | .b3-dialog__header { 23 | > .fn__flex { 24 | margin: auto; 25 | width: fit-content; 26 | } 27 | 28 | .b3-button { 29 | @include button-action("normal"); 30 | padding: 4px 8px; 31 | background-color: transparent; 32 | } 33 | } 34 | } 35 | 36 | /* 37 | * 块属性 38 | */ 39 | [data-key="dialog-attr"] { 40 | button[data-action="addCustom"], 41 | button[data-type="addColumn"] { 42 | @include button-action("normal"); 43 | } 44 | 45 | button[data-type="addColumn"] { 46 | margin-left: unset; 47 | margin-inline-start: 28px; 48 | } 49 | } 50 | 51 | /* 52 | * 命令面板 53 | */ 54 | [data-key="dialog-commandpanel"] { 55 | .search__header { 56 | > .b3-form__icon-icon { 57 | left: 20px; 58 | } 59 | 60 | > .b3-text-field { 61 | background-color: var(--b3-theme-background); 62 | margin: 0 12px; 63 | } 64 | } 65 | 66 | #commands { 67 | padding: 8px; 68 | 69 | ~ .fn__hr { 70 | display: none; 71 | } 72 | } 73 | } 74 | 75 | /* 76 | * 代码片段对话框 77 | */ 78 | #addCodeSnippetCSS, 79 | #addCodeSnippetJS { 80 | inset-inline-end: 79px; 81 | 82 | + .fn__space { 83 | display: none; 84 | } 85 | 86 | &, 87 | ~ .b3-switch { 88 | position: absolute; 89 | top: 16px; 90 | } 91 | 92 | ~ .b3-switch { 93 | inset-inline-end: 24px; 94 | top: 19px; 95 | } 96 | } 97 | 98 | [data-key="dialog-snippets"] { 99 | // textarea { 100 | // height: fit-content; 101 | // max-height: 8em; 102 | // } 103 | 104 | .b3-switch--side { 105 | margin-right: unset; 106 | margin-inline-end: unset; 107 | } 108 | 109 | .b3-form__icon + .fn__space { 110 | display: none; 111 | } 112 | } 113 | 114 | /* 115 | * 随机题头图列表 116 | */ 117 | [data-key="dialog-backgroundrandom"] { 118 | .b3-dialog__body { 119 | position: relative; 120 | z-index: 0; 121 | 122 | & > .b3-cards { 123 | grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); 124 | margin: 0; 125 | padding: 32px; 126 | gap: 32px; 127 | display: grid; 128 | 129 | .b3-card { 130 | width: auto !important; 131 | min-width: unset; 132 | margin: 0; 133 | border-radius: $border-rd-card; 134 | padding: 0; 135 | box-shadow: none; 136 | top: 0; 137 | // transform: scale(0.9); 138 | 139 | &:hover { 140 | transform: scale(1.05); 141 | // box-shadow: 0 4px 18px -8px #0000001b; 142 | @include menu-shadow; 143 | 144 | @include darkmode-counterpart { 145 | box-shadow: 0 8px 28px -8px #00000062; 146 | } 147 | } 148 | } 149 | } 150 | } 151 | } 152 | 153 | /* 154 | * 移动块窗口 155 | */ 156 | [data-key="dialog-movepathto"] { 157 | .b3-dialog__header > div { 158 | text-wrap: nowrap; 159 | overflow-x: auto; 160 | } 161 | 162 | #foldList .b3-list-item__showall { 163 | line-height: 1.5; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /styles/components/dialogs/history.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * 数据历史 3 | */ 4 | .history__repo { 5 | background-color: unset; 6 | 7 | .history__action { 8 | border-bottom: none; 9 | } 10 | 11 | select.b3-select { 12 | width: auto; 13 | } 14 | } 15 | 16 | .history__panel { 17 | & > .b3-list, 18 | & > .history__diff { 19 | // width: min(256px, 30%); 20 | // min-width: fit-content; // 导致宽度根据条目长度频繁变动 21 | padding: 8px 0; 22 | background-color: var(--b3-theme-surface); 23 | } 24 | 25 | .b3-chip { 26 | padding: 0 4px; 27 | } 28 | 29 | // 同步? 30 | .b3-chip--success { 31 | background-color: var(--b3-font-background9); 32 | color: var(--b3-font-color9); 33 | } 34 | 35 | // 更新 36 | .b3-chip--info { 37 | background-color: var(--b3-font-background6); 38 | color: var(--b3-font-color6); 39 | } 40 | 41 | // 替换 42 | .b3-chip--secondary { 43 | background-color: var(--b3-font-background4); 44 | color: var(--b3-font-color4); 45 | } 46 | 47 | // 删除 48 | .b3-chip--error { 49 | background-color: var(--b3-font-background13); 50 | color: var(--b3-font-color13); 51 | } 52 | 53 | // 排版 54 | .b3-chip--pink { 55 | background-color: var(--b3-font-background11); 56 | color: var(--b3-font-color11); 57 | } 58 | 59 | // 大纲 60 | .b3-chip--warning { 61 | background-color: var(--b3-font-background5); 62 | color: var(--b3-font-color5); 63 | } 64 | } 65 | 66 | :not(.b3-dialog__body) > .history__panel { 67 | border-top: 1px solid var(--b3-border-color-trans); 68 | 69 | // .b3-list--background { 70 | // border-right: 1px solid var(--b3-border-color); 71 | // } 72 | } 73 | 74 | #historyContainer { 75 | [data-type="doc"] > div:first-child { 76 | border-bottom: none !important; 77 | } 78 | } 79 | 80 | .history__resize { 81 | box-shadow: none; 82 | } 83 | -------------------------------------------------------------------------------- /styles/components/dialogs/index.scss: -------------------------------------------------------------------------------- 1 | @use "./dialog.scss"; 2 | @use "./functional.scss"; 3 | @use "./settings.scss"; 4 | @use "./marketplace.scss"; 5 | @use "./search.scss"; 6 | @use "./preview.scss"; 7 | @use "./history.scss"; 8 | @use "./export.scss"; 9 | @use "./mini-window.scss"; 10 | @use "./flashcard.scss"; 11 | @use "./emoji.scss"; 12 | @use "./av.scss"; 13 | -------------------------------------------------------------------------------- /styles/components/dialogs/mini-window.scss: -------------------------------------------------------------------------------- 1 | body.body--window { 2 | .toolbar__window { 3 | .toolbar__item { 4 | app-region: no-drag; 5 | color: var(--b3-theme-on-surface); 6 | 7 | &:hover { 8 | color: var(--b3-theme-on-background); 9 | } 10 | 11 | &--active { 12 | color: var(--b3-theme-primary); 13 | 14 | &:hover { 15 | color: var(--b3-theme-primary); 16 | } 17 | } 18 | } 19 | } 20 | 21 | // &.body-asri--mac { 22 | // .fn__flex:first-child>[data-type="wnd"] { 23 | // .layout-tab-bar:not(.layout-tab-bar--readonly) { 24 | // margin-left: var(--b3-toolbar-left-mac); 25 | // } 26 | // } 27 | // } // -> js 28 | 29 | #status { 30 | right: 8px !important; 31 | padding-right: 0; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /styles/components/dialogs/preview.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | @use "../utils" as *; 3 | 4 | /* 5 | * 弹出预览窗口 6 | */ 7 | .block__popover { 8 | @include dialog-shadow($extra-shadow-light: "0 0 0 1px rgba(0, 0, 0, 0.05)"); 9 | @include theme-variant-border($border: false); 10 | 11 | @include darkmode-counterpart { 12 | // outline-color: transparent; 13 | border: 1px solid var(--b3-border-color-trans); 14 | } 15 | 16 | // outline: 1px solid rgb(map-get($theme-light, on-background), 0.1); 17 | 18 | > .block__icons--menu { 19 | background-color: var(--b3-theme-background); 20 | } 21 | 22 | .block__icons { 23 | .block__icon { 24 | &:hover:not([disabled]):not(.ft__primary) { 25 | background-color: transparent; 26 | } 27 | 28 | &--active { 29 | color: var(--b3-theme-primary); 30 | background-color: transparent; 31 | 32 | &:hover:not([disabled]):not(.ft__primary) { 33 | color: var(--b3-theme-primary); 34 | } 35 | } 36 | } 37 | } 38 | 39 | &--open { 40 | animation: scaleBounce 0.5s var(--asri-ease-spring-3); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /styles/components/index.scss: -------------------------------------------------------------------------------- 1 | @use "dialogs"; 2 | @use "menu"; 3 | @use "breadcrumb"; 4 | @use "misc"; 5 | -------------------------------------------------------------------------------- /styles/features/cover-image-fading.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | @use "./utils" as *; 3 | 4 | .protyle-background__img { 5 | //遮罩层 6 | // &::before { 7 | // content: ""; 8 | // display: inline-block; 9 | // width: -webkit-fill-available; 10 | // height: 90%; 11 | // position: absolute; 12 | // bottom: 0; 13 | // right: 0; 14 | // background: linear-gradient(to top, pickThemeColor($theme-light, background) 2%, pickThemeColor($theme-light, background, 0.97) 10%, pickThemeColor($theme-light, background, 0.9) 18%, pickThemeColor($theme-light, background, 0.75) 33%, pickThemeColor($theme-light, background, 0.05) 92%, transparent 99%); 15 | // pointer-events: none; 16 | 17 | // @include darkmode-counterpart { 18 | // background: linear-gradient(to top, pickThemeColor($theme-dark, background) 2%, pickThemeColor($theme-dark, background, 0.97) 10%, pickThemeColor($theme-dark, background, 0.9) 18%, pickThemeColor($theme-dark, background, 0.75) 33%, pickThemeColor($theme-dark, background, 0.05) 92%, transparent 99%); 19 | // } 20 | // } 21 | 22 | img { 23 | // mask-image: linear-gradient(to bottom, 24 | // black 2%, 25 | // rgba(0, 0, 0, 0.97) 10%, 26 | // rgba(0, 0, 0, 0.9) 18%, 27 | // rgba(0, 0, 0, 0.75) 33%, 28 | // rgba(0, 0, 0, 0.05) 92%, 29 | // transparent 99%); 30 | 31 | mask-image: linear-gradient(to top, transparent 2%, rgba(0, 0, 0, 0.03) 10%, rgba(0, 0, 0, 0.1) 18%, rgba(0, 0, 0, 0.25) 33%, rgba(0, 0, 0, 0.95) 92%, black 99%), linear-gradient(to top, black, black); 32 | mask-size: auto 90%, auto 11%; 33 | mask-position: bottom, top; 34 | mask-repeat: no-repeat; 35 | 36 | // mask-image: linear-gradient(to bottom, hsl(0, 0%, 0%) 0%, hsl(0, 0%, 0%, .96) 11%, hsla(0, 0%, 0%, 0.9) 16%, hsla(0, 0%, 0%, 0.738) 27.1%, hsla(0, 0%, 0%, 0.541) 40.6%, hsla(0, 0%, 0%, 0.382) 52.3%, hsla(0, 0%, 0%, 0.278) 60.85%, hsla(0, 0%, 0%, 0.194) 68.5%, hsla(0, 0%, 0%, 0.126) 75.7%, hsla(0, 0%, 0%, 0.075) 82.18%, hsla(0, 0%, 0%, 0.042) 87.49%, hsla(0, 0%, 0%, 0.021) 91.9%, hsla(0, 0%, 0%, 0.008) 95.68%, hsla(0, 0%, 0%, 0.002) 98.38%, hsla(0, 0%, 0%, 0) 100%); 37 | // mask-position: bottom; 38 | // mask-repeat: no-repeat; 39 | } 40 | 41 | &::after { 42 | content: ""; 43 | display: inline-block; 44 | width: 100%; 45 | height: 13.5vh; 46 | position: absolute; 47 | bottom: 0; 48 | right: 0; 49 | backdrop-filter: blur(4px); 50 | mask-image: linear-gradient(to top, black 50%, transparent); 51 | transform: translateZ(0); 52 | pointer-events: none; 53 | } 54 | } 55 | 56 | body:not(.body-asri--mobile) { 57 | .protyle-background { 58 | .protyle-background__img { 59 | position: relative; 60 | 61 | &:not(.fn__none) { 62 | margin-bottom: -24px; 63 | 64 | + .protyle-background__ia .protyle-background__icon.fn__none ~ .protyle-background__action { 65 | @include theme-variant-color(background-color, surface, 0.8, 0.6); 66 | @include theme-variant-color(color, on-background, 0.6, 1); 67 | 68 | padding: 2px; 69 | width: fit-content; 70 | border-radius: 99px; 71 | mix-blend-mode: luminosity; 72 | 73 | @include theme-variant-border($border: false); 74 | 75 | &:hover { 76 | @include bg-blur($saturate-value: 1, $brightness-light: 1, $brightness-dark: 1); 77 | } 78 | 79 | .b3-button { 80 | margin-top: 0; 81 | 82 | &:hover { 83 | background-color: unset; 84 | color: var(--b3-theme-on-background); 85 | } 86 | } 87 | } 88 | } 89 | 90 | &.fn__none { 91 | + .protyle-background__ia { 92 | margin-top: 48px; 93 | } 94 | } 95 | 96 | .protyle-icons:nth-last-child(2) { 97 | width: fit-content; 98 | top: calc(15vh - 24px); 99 | } 100 | } 101 | 102 | // 无图标 103 | &.without-icon { 104 | .protyle-background__img { 105 | margin-bottom: -100px; 106 | } 107 | 108 | .protyle-background__ia { 109 | flex-direction: column-reverse; 110 | } 111 | } 112 | 113 | // 有图标 114 | &:not(.without-icon) { 115 | // 有题头图 116 | .protyle-background__img + .protyle-background__ia { 117 | // 无标签 118 | > .protyle-background__action { 119 | position: absolute; 120 | top: auto; 121 | transform: translateX(88px); // 可能是导致 https://github.com/mustakshif/Asri/issues/58 的原因 122 | } 123 | 124 | // 有标签 125 | .b3-chips .fn__space:not(:first-child) + .protyle-background__action { 126 | position: static; 127 | transform: none; 128 | } 129 | } 130 | 131 | // 无题头图 132 | .protyle-background__img.fn__none + .protyle-background__ia .protyle-background__action { 133 | top: 48px; 134 | } 135 | } 136 | } 137 | 138 | .protyle-top { 139 | &:hover { 140 | .b3-chips .b3-button { 141 | opacity: 1; 142 | } 143 | } 144 | } 145 | 146 | .protyle-background__ia { 147 | display: flex; 148 | flex-direction: column; 149 | } 150 | 151 | .protyle-background__action { 152 | &:hover { 153 | opacity: 1 !important; 154 | } 155 | 156 | .b3-button { 157 | &:hover { 158 | background-color: unset; 159 | color: var(--b3-theme-on-background); 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /styles/features/cover-image-parallax-scrolling.scss: -------------------------------------------------------------------------------- 1 | .protyle { 2 | @supports not (animation-timeline: view()) { 3 | .protyle-background__img { 4 | &::after { 5 | content: ""; 6 | display: inline-block; 7 | width: -webkit-fill-available; 8 | height: 30vh; 9 | position: absolute; 10 | top: 0; 11 | right: 0; 12 | background: linear-gradient(to top, var(--b3-theme-background) 2%, rgba(from var(--b3-theme-background) r g b / 0.97) 9%, rgba(from var(--b3-theme-background) r g b / 0.9) 18%, rgba(from var(--b3-theme-background) r g b / 0.75) 33%, rgba(from var(--b3-theme-background) r g b / 0.05) 92%, transparent 99%); 13 | pointer-events: none; 14 | } 15 | } 16 | } 17 | 18 | @supports (animation-timeline: view()) { 19 | // 滚动条方案 20 | // &-content { 21 | // scroll-timeline-name: --protyle-content; 22 | // scroll-timeline-axis: y; 23 | // } 24 | 25 | // .protyle-background__img { 26 | 27 | // img { 28 | // animation-name: move-up; 29 | // animation-timeline: --protyle-content; 30 | // // animation-duration: 1ms; /* Firefox requires this to apply the animation */ 31 | // // margin: 0 12px 0; 32 | // // width: calc(100% - 24px); 33 | // // border-radius: 16px; 34 | // } 35 | // } 36 | 37 | &.fullscreen { 38 | --bgimg-top-space: 48px; 39 | } 40 | 41 | &-background__img { 42 | overflow: hidden; 43 | view-timeline-name: --protyle-background; 44 | 45 | img { 46 | --offset-y: 50px; 47 | // view-timeline-name: --protyle-background; 48 | animation-timeline: --protyle-background; 49 | // view-timeline-axis: y; 50 | animation-range: calc(100vh - var(--bgimg-top-space, 84px)) normal; 51 | animation-fill-mode: both; 52 | animation-name: parallax-cover-img, cover-img-fade-out, // cover-img-blur 53 | ; 54 | animation-timing-function: linear; 55 | // margin: 0 12px 0; 56 | // width: calc(100% - 24px); 57 | // border-radius: 16px; 58 | // min-width: calc(100% + 60px); 59 | // margin: 0 -30px; 60 | // transform: scale(1.2); 61 | transform: translateY(0) scale(var(--bgimg-scale, 1.03)); 62 | transform-origin: 50% calc(50% + var(--offset-y)); 63 | 64 | //临时解决方案,待优化 65 | // &[style^="object-position"] { 66 | // animation-name: cover-img-fade-out; 67 | // // animation: none; 68 | // } 69 | } 70 | } 71 | 72 | // &-wysiwyg { 73 | // animation-name: testanim; 74 | // animation-timeline: --protyle-background; 75 | // } 76 | 77 | @keyframes parallax-cover-img { 78 | 100% { 79 | // filter: saturate(0); 80 | // margin: 0; 81 | // width: 100%; 82 | // border-radius: 0; 83 | // height: 0vh; 84 | // min-width: calc(100%); 85 | transform: translateY(max(calc(30vh - var(--offset-y)), 80px)) scale(1); 86 | // filter: blur(20px); 87 | // object-position: center calc(var(--obj-position-offset-y, 50%) + min(calc(30vh - 40px), 120px)); // 30vh 正好保持相对静止 88 | } 89 | } 90 | 91 | @keyframes cover-img-fade-out { 92 | 0%, 93 | 50% { 94 | opacity: 1; 95 | } 96 | 97 | 90%, 98 | 100% { 99 | opacity: 0; 100 | } 101 | } 102 | 103 | @keyframes cover-img-blur { 104 | 0%, 105 | 20% { 106 | filter: none; 107 | } 108 | 109 | 100% { 110 | filter: blur(20px); 111 | } 112 | } 113 | } 114 | } 115 | 116 | // @keyframes testanim { 117 | // 0% { 118 | // background-color: #000; 119 | // } 120 | 121 | // 100% { 122 | // background-color: #fff; 123 | // } 124 | // } 125 | -------------------------------------------------------------------------------- /styles/features/doc-attr-reposition.scss: -------------------------------------------------------------------------------- 1 | body:not(.body-asri--mobile) { 2 | .protyle-title { 3 | // 属性位置调整至标题下方 4 | .protyle-attr { 5 | position: static; 6 | // font-family: serif; 7 | // font-style: italic; 8 | font-size: 14px; 9 | // font-weight: 500; 10 | // flex-wrap: wrap; 11 | // align-items: flex-start; 12 | // overflow: auto; 13 | 14 | &::-webkit-scrollbar { 15 | display: none; 16 | } 17 | scrollbar-width: none; 18 | 19 | > div:not(.protyle-attr--refcount) svg { 20 | // margin-top: 3px; 21 | // margin-bottom: 3px; 22 | height: 14px; 23 | width: 14px; 24 | // color: var(--b3-theme-accent); 25 | } 26 | 27 | > :not(.protyle-attr--memo) { 28 | flex-shrink: 0; 29 | max-width: 50%; 30 | // margin-top: 8px; 31 | // display: flex !important; 32 | // align-items: center; 33 | // justify-content: center; 34 | } 35 | 36 | > .protyle-attr--bookmark { 37 | flex-grow: unset; 38 | // flex-shrink: 0; 39 | flex-basis: fit-content; 40 | 41 | &::before { 42 | transform: translateY(1.5px) scale(1.2); 43 | mask-image: url('data:image/svg+xml, '); 44 | } 45 | 46 | &:hover::before { 47 | background-color: var(--b3-theme-on-background); 48 | } 49 | } 50 | 51 | // 属性分隔符 52 | > :not(:nth-last-child(1), .protyle-attr--memo, .protyle-attr--refcount) { 53 | &::after { 54 | content: "·"; 55 | display: inline-block; 56 | font-size: 1.8em; 57 | margin-inline-start: 7px; 58 | line-height: 0; 59 | vertical-align: -2px; 60 | color: var(--b3-theme-on-surface); 61 | } 62 | 63 | &:hover::after { 64 | color: var(--b3-theme-on-surface); 65 | } 66 | } 67 | 68 | > .protyle-attr--memo:not(:nth-last-child(1)) { 69 | &::after { 70 | content: attr(aria-label) " •"; 71 | } 72 | } 73 | 74 | > .protyle-attr--refcount { 75 | position: static; 76 | font-size: inherit; 77 | line-height: 14px; 78 | font-family: inherit; 79 | height: 18px; 80 | color: var(--b3-theme-on-surface); 81 | 82 | &::before { 83 | transform: translateY(2px) scale(1.4); 84 | mask-image: url('data:image/svg+xml, '); 85 | } 86 | 87 | &:hover { 88 | font-weight: 400; 89 | color: var(--b3-theme-accent); 90 | 91 | &::before { 92 | background-color: var(--b3-theme-accent); 93 | } 94 | } 95 | } 96 | 97 | > .protyle-attr--refcount, 98 | .protyle-attr--bookmark { 99 | &::before { 100 | content: ""; 101 | display: inline-block; 102 | // background-color: var(--b3-theme-accent); 103 | // background-color: var(--b3-theme-error); 104 | background-color: var(--b3-theme-on-surface); 105 | width: 1em; 106 | height: 1em; 107 | margin-right: 4px; 108 | mask-size: contain; 109 | mask-repeat: no-repeat; 110 | transition: inherit; 111 | } 112 | } 113 | 114 | // 备注常显 115 | > .protyle-attr--memo { 116 | display: flex; 117 | 118 | svg { 119 | min-width: 12px; 120 | } 121 | 122 | &::after { 123 | position: static; 124 | margin: 0; 125 | opacity: 1; 126 | transform: none; 127 | padding: 0; 128 | background-color: transparent; 129 | font-size: inherit; 130 | color: var(--b3-theme-on-surface); 131 | // line-height: 1.625; 132 | margin-inline-start: 4px; 133 | border-radius: 0; 134 | z-index: unset; 135 | transition: inherit; 136 | box-shadow: none; 137 | // text-wrap: wrap; 138 | } 139 | 140 | &:hover::after { 141 | border: none; 142 | box-shadow: none; 143 | transform: none; 144 | display: inline; 145 | overflow: hidden; 146 | outline: none; 147 | color: var(--b3-theme-on-background); 148 | } 149 | } 150 | } 151 | 152 | // 文档标题分隔线 153 | &::after { 154 | content: ""; 155 | display: block; 156 | height: 8px; 157 | // height: 4px; 158 | // width: calc(100% - .5em); 159 | // background-color: var(--b3-border-color-trans); 160 | // margin: 16px auto 8px; 161 | // border-radius: 99px; 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /styles/features/filetree-indents-indicator.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | // 文档树项目小圆点位置 4 | .layout-tab-container .b3-list-item .b3-list-item__toggle.fn__hidden { 5 | position: relative; 6 | 7 | &::before { 8 | left: auto !important; 9 | inset-inline-end: 7px; 10 | } 11 | } 12 | 13 | // 大纲数字层级标识 14 | .sy__outline .b3-list-item[data-type="NodeHeading"] .b3-list-item__text::before { 15 | transform: translateX(negateForRTL(-18px)); 16 | left: auto; 17 | } 18 | 19 | // 文档树缩进参考线 indent guides(方案一) 20 | .file-tree > .fn__flex-1 { 21 | $uls: ">ul"; 22 | $indent: 18px; 23 | // $indent-start: 22px; 24 | --indent-offset: 0px; // fix .sy__tag indent offset 25 | 26 | --indent-color-inactive: rgb(from var(--b3-theme-on-background) r g b / 0.15); 27 | --indent-color-active: rgb(from var(--b3-theme-on-background) r g b / 0.3); 28 | --indent-color: #0000; 29 | 30 | @for $i from 1 through 7 { 31 | $uls: str-insert( 32 | $string: $uls, 33 | $insert: ">ul", 34 | $index: 100, 35 | ); 36 | 37 | &#{$uls} { 38 | margin-inline-start: $indent; 39 | --indent-color: #0000; 40 | box-shadow: negateForRTL(1px) 0 var(--indent-color) inset; 41 | 42 | .b3-list-item { 43 | margin-inline-start: calc($indent * $i * -1 + 6px + var(--indent-offset)); 44 | 45 | > .b3-list-item__toggle { 46 | padding-left: unset !important; 47 | padding-inline-start: calc($indent * $i + 4px) !important; 48 | } 49 | } 50 | } 51 | } 52 | 53 | & > ul ul { 54 | transition-duration: 0.2s; 55 | transition-property: box-shadow, height; 56 | } 57 | 58 | // 颜色控制 59 | &:hover > ul ul, 60 | li.b3-list-item--focus + ul, 61 | ul.has-focus { 62 | --indent-color: var(--indent-color-inactive); 63 | } 64 | 65 | &:hover li.b3-list-item--focus + ul, 66 | &:hover ul.has-focus { 67 | --indent-color: var(--indent-color-active); 68 | } 69 | 70 | & > ul { 71 | box-shadow: none !important; 72 | } 73 | } 74 | 75 | // .sy__outline>.fn__flex-1 { 76 | // --indent-offset: -1px; 77 | // } 78 | 79 | /* 80 | * 文档树缩进参考线 indent guides(方案二,性能更差,导致展开文档目录动画卡顿) 81 | */ 82 | // @property --indent-color { 83 | // syntax: ''; 84 | // initial-value: #0000; 85 | // inherits: false; 86 | // } 87 | 88 | // .file-tree>.fn__flex-1 { 89 | // $uls: '>ul'; 90 | // $indent: 18px; 91 | 92 | // --indent-color-inactive: rgb(from var(--b3-theme-on-background) r g b / .15); 93 | // --indent-color-active: rgb(from var(--b3-theme-on-background) r g b / .3); 94 | 95 | // --indent-color: #0000; 96 | 97 | // @for $i from 1 through 7 { 98 | // $uls: str-insert($string: $uls, $insert: '>ul', $index: 100); 99 | 100 | // &#{$uls} { 101 | // background-image: linear-gradient( 102 | // 90deg, 103 | // #0000 0 $indent, 104 | // var(--indent-color) $indent calc($indent + 1px), 105 | // #0000 calc($indent + 1px) 100% 106 | // ); 107 | 108 | // $indent: $indent + 18px; 109 | // } 110 | // } 111 | 112 | // &>ul ul { 113 | // transition-duration: 0.2s; 114 | // transition-property: --indent-color, height; // added height to fix https://github.com/mustakshif/Asri/issues/118 115 | // } 116 | 117 | // &:hover>ul ul, 118 | // li.b3-list-item--focus+ul, 119 | // ul.has-focus { 120 | // --indent-color: var(--indent-color-inactive); 121 | // // box-shadow: 1px 0 oklch(from var(--b3-theme-on-background) l c h / .15) inset; 122 | 123 | // // @include darkmode-counterpart { 124 | // // box-shadow: 1px 0 oklch(from var(--b3-theme-on-background) l c h / .15) inset; 125 | // // } 126 | // } 127 | 128 | // &:hover li.b3-list-item--focus+ul, 129 | // &:hover ul.has-focus { 130 | // --indent-color: var(--indent-color-active); 131 | // // box-shadow: 1px 0 oklch(from var(--b3-theme-on-background) l c h / .3) inset; 132 | 133 | // // @include darkmode-counterpart { 134 | // // box-shadow: 1px 0 oklch(from var(--b3-theme-on-background) l c h / .3) inset; 135 | // // } 136 | // } 137 | 138 | // } 139 | -------------------------------------------------------------------------------- /styles/features/floating-docks.scss: -------------------------------------------------------------------------------- 1 | .dock { 2 | position: fixed; 3 | z-index: 99; 4 | background-color: transparent !important; 5 | top: 50%; 6 | transform: translateY(-25%); 7 | 8 | .dock__item--space { 9 | flex-grow: 0; 10 | } 11 | 12 | &#dockLeft { 13 | left: 0; 14 | } 15 | 16 | &#dockRight { 17 | right: 0; 18 | } 19 | } 20 | 21 | #dockLeft.dock-layout-expanded:not(.fn__none) + #layouts { 22 | .layout__dockl { 23 | padding-left: 42px; 24 | background-color: var(--b3-theme-surface); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /styles/features/gradient-headings.scss: -------------------------------------------------------------------------------- 1 | @supports (color: oklch(from #00f l clamp(0, c, 0.2) calc(h + 0))) { 2 | #layouts { 3 | --heading-clr-primary-base: var(--b3-theme-primary); 4 | --hchs: 30; // heading color hue shift. [0, 60] 5 | } 6 | @for $i from 1 through 6 { 7 | :is(.h#{$i}, h#{$i}) { 8 | --heading-clr-primary: oklch(from var(--heading-clr-primary-base) l clamp(0, c, 0.2) calc(h + var(--hchs) * #{($i - 1)})); 9 | // --heading-clr-primary:oklch(from var(--heading-clr-primary-base) calc(l - (l - .89)/6 * #{$i}) calc(c - (c - clamp(0, .01 * var(--asri-c-factor, 1) * var(--asri-c-0, 1), .04))/6 * #{$i}) h); 10 | 11 | // >div, ~div { 12 | // --b3-theme-primary: oklch(from var(--heading-clr-primary-base) l clamp(0, c, .2) calc(h + #{50 * ($i - 1)})); 13 | // } 14 | } 15 | } 16 | 17 | :is(.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6) { 18 | color: var(--heading-clr-primary); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /styles/features/heading-indicators.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | $headingContent: ""; 4 | 5 | .protyle, 6 | .b3-typography { 7 | --prefix: var(--asri-heading-prefix, "#"); 8 | --suffix: var(--asri-heading-suffix, ""); 9 | } 10 | 11 | @for $i from 1 through 6 { 12 | $headingContent: $headingContent + "#"; 13 | 14 | .h#{$i}, 15 | h#{$i} { 16 | &:before { 17 | content: var(--prefix) "#{$i}" var(--suffix); 18 | // content:$headingContent; 19 | } 20 | } 21 | } 22 | 23 | :is(.h1, .h2, .h3, .h4, .h5, .h6, ), :where(h1, h2, h3, h4, h5, h6) { 24 | &::before { 25 | display: block; 26 | overflow: visible; 27 | font-weight: 900; 28 | font-size: 2.4em; 29 | // font-style: italic; 30 | position: absolute; 31 | // top: -0.36em; 32 | // right: 8px; 33 | top: -0.6em; 34 | left: 0; 35 | color: inherit; 36 | opacity: 0.15; 37 | pointer-events: none; 38 | user-select: none; 39 | mask-image: linear-gradient(to bottom, black 20%, transparent 80%); 40 | 41 | // @include darkmode-counterpart { 42 | // opacity: 0.2; 43 | // } 44 | } 45 | } 46 | 47 | :where(h1, h2, h3, h4, h5, h6) { 48 | position: relative; 49 | } 50 | -------------------------------------------------------------------------------- /styles/features/hide-side-panel-block-icons.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | // 顶部控件自动隐藏 4 | body:not(.body-asri--mobile, .body-asri--android, .body-asri--iosApp) { 5 | .file-tree .block__icons { 6 | app-region: no-drag; 7 | } 8 | 9 | .sy__backlink { 10 | --exgf: 1.5; // exaggerate factor 11 | --icons2dots-dur: 0.5s; 12 | --dots2icons-dur: 0.4s; 13 | 14 | > :nth-child(2 of .block__icons) { 15 | position: relative; 16 | } 17 | } 18 | 19 | // .sy__globalGraph, .sy__graph // 导致关系图闪烁 20 | .file-tree:where(.sy__file, .sy__outline, .sy__bookmark, .sy__tag, .sy__backlink) { 21 | position: relative; 22 | 23 | --dots-clr: var(--b3-border-color-trans); 24 | --icons2dots-timing-func: var(--asri-ease-spring-3); 25 | --dots2icons-timing-func: var(--asri-ease-spring-3); 26 | --icons2dots-dur: 0.4s; 27 | --dots2icons-dur: 0.35s; 28 | --icons2dots-delay: 0.2s; 29 | --dots2icons-delay: 0.125s; 30 | 31 | .block__icons { 32 | transition: var(--icons2dots-dur) var(--icons2dots-timing-func) var(--icons2dots-delay); 33 | 34 | height: 20px; 35 | min-height: unset; 36 | 37 | // dots 38 | &::before { 39 | content: ""; 40 | width: 4px; 41 | height: 4px; 42 | background-color: var(--dots-clr); 43 | box-shadow: 8px 0 0 0 var(--dots-clr), 16px 0 0 0 var(--dots-clr), 24px 0 0 0 var(--dots-clr); 44 | border-radius: 50%; 45 | position: absolute; 46 | top: 10px; 47 | left: 50%; 48 | transform: translateX(-12px); 49 | transform-origin: top center; 50 | transition: var(--icons2dots-dur) var(--icons2dots-timing-func) var(--icons2dots-delay); 51 | } 52 | 53 | > :where(div, span) { 54 | transform: scale(0.6); 55 | transition: var(--icons2dots-dur) var(--icons2dots-timing-func) var(--icons2dots-delay); 56 | opacity: 0 !important; 57 | // transform-origin: top center; 58 | 59 | &:first-child { 60 | transform-origin: negateForRTL(calc(max(calc(15.5em - 100%), 100%) * var(--exgf, 1))) 50%; 61 | } 62 | 63 | &.counter { 64 | transform-origin: negateForRTL(calc(400% * var(--exgf, 1))) 50%; 65 | } 66 | 67 | &:nth-last-child(3 of .block__icon) { 68 | transform-origin: negateForRTL(calc(-200% * var(--exgf, 1))) 50%; 69 | } 70 | 71 | &:nth-last-child(2 of .block__icon) { 72 | transform-origin: negateForRTL(calc(-300% * var(--exgf, 1))) 50%; 73 | } 74 | 75 | &:last-child { 76 | transform-origin: negateForRTL(calc(-500% * var(--exgf, 1))) 50%; 77 | } 78 | } 79 | 80 | &:hover, 81 | &:focus-within { 82 | height: 42px; 83 | 84 | transition-timing-function: var(--dots2icons-timing-func); 85 | transition-duration: var(--dots2icons-dur); 86 | transition-delay: var(--dots2icons-delay); 87 | 88 | &::before { 89 | transform: translateX(calc(-12px * 3.5)) scale(3.5); 90 | opacity: 0; 91 | transition-timing-function: var(--dots2icons-timing-func); 92 | transition-duration: var(--dots2icons-dur); 93 | transition-delay: var(--dots2icons-delay); 94 | } 95 | 96 | > :where(div, span) { 97 | transform: none; 98 | opacity: 1 !important; 99 | transition-timing-function: var(--dots2icons-timing-func); 100 | transition-duration: var(--dots2icons-dur); 101 | transition-delay: var(--dots2icons-delay); 102 | } 103 | } 104 | 105 | .search__label:not(.fn__none) ~ .block__icon { 106 | opacity: 0 !important; 107 | } 108 | } 109 | } 110 | } 111 | 112 | // 方案二,减少局部重绘 113 | 114 | // .file-tree .block__icons { 115 | // app-region: no-drag; 116 | // } 117 | 118 | // // .sy__globalGraph, .sy__graph // 导致关系图闪烁 119 | // .file-tree:where(.sy__file, .sy__outline, .sy__bookmark, .sy__tag) { 120 | // position: relative; 121 | 122 | // .block__icons { 123 | // position: absolute; 124 | // z-index: 1; 125 | // background-color: transparent; 126 | // // border: 1px solid var(--b3-border-color-trans); 127 | // transition: .2s; 128 | // transition-property: background-color; 129 | // top: 4px; 130 | // left: 0; 131 | // right: 0; 132 | // margin: auto; 133 | // width: fit-content; 134 | // min-height: 20px; 135 | // transform-origin: 50% 0%; 136 | // // min-width: 20px; 137 | // animation: blockIconsShrink .5s var(--asri-ease-spring-3); 138 | // border-radius: 99px; 139 | // // backdrop-filter: blur(20px); 140 | 141 | // --dots-clr: #fff5; 142 | 143 | // ~.fn__flex-1 { 144 | // padding-top: 20px !important; 145 | // } 146 | 147 | // >:where(div, span) { 148 | // content-visibility: hidden; 149 | // } 150 | 151 | // &::before { 152 | // content: ''; 153 | // width: 4px; 154 | // height: 4px; 155 | // background-color: var(--dots-clr); 156 | // box-shadow: 8px 0 0 0 var(--dots-clr), 16px 0 0 0 var(--dots-clr), 24px 0 0 0 var(--dots-clr); 157 | // border-radius: 50%; 158 | // position: absolute; 159 | // top: 10px; 160 | // left: 50%; 161 | // transform: translateX(-12px); 162 | // transform-origin: top center; 163 | // transition: var(--icons2dots-dur) var(--icons2dots-timing-func) var(--icons2dots-delay); 164 | // } 165 | 166 | // &:hover, 167 | // &:focus-within { 168 | // min-height: 42px; 169 | // animation: blockIconsExpand .5s var(--asri-ease-spring-3); 170 | // backdrop-filter: blur(20px); 171 | // background-color: rgb(from var(--b3-theme-surface) r g b /.8); 172 | // border: 1px solid var(--b3-border-color-trans); 173 | 174 | // >:where(div, span) { 175 | // content-visibility: visible; 176 | // } 177 | 178 | // &::before{ 179 | // visibility: hidden; 180 | // } 181 | // } 182 | // } 183 | 184 | // @keyframes blockIconsShrink { 185 | // 0% { 186 | // transform: scale(2, calc(42/20)); 187 | // } 188 | 189 | // 100% { 190 | // transform: none; 191 | // } 192 | // } 193 | 194 | // @keyframes blockIconsExpand { 195 | // 0% { 196 | // transform: scale(.5, calc(20/42)); 197 | // opacity: 0; 198 | // } 199 | 200 | // 90%,100% { 201 | // opacity: 1; 202 | // } 203 | 204 | // 100% { 205 | // transform: none; 206 | // } 207 | // } 208 | 209 | // // .sy__backlink { 210 | // // >:nth-child(2 of .block__icons) { 211 | // // position: relative; 212 | // // } 213 | // // } 214 | // } 215 | -------------------------------------------------------------------------------- /styles/features/high-readability-variants.scss: -------------------------------------------------------------------------------- 1 | body:not(.body-asri--android, .body--win32, .body-asri--linux) { 2 | .layout-tab-container, 3 | .protyle-content, 4 | .b3-typography { 5 | font-feature-settings: "ss06" on; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /styles/features/index.scss: -------------------------------------------------------------------------------- 1 | @use "colorful-asri"; 2 | @use "rtl"; 3 | @use "high-readability-variants"; 4 | // @use 'panda-scheme'; 5 | // @use 'mode-transition'; 6 | // @use 'hide-toolbar'; 7 | // @use 'cover-image-fading'; 8 | @use "topbar-fusion"; 9 | @use "blur"; 10 | @use "cover-image-parallax-scrolling"; 11 | @use "doc-attr-reposition"; 12 | @use "filetree-indents-indicator"; 13 | @use "custom-attributes"; 14 | // @use 'heading-indicators'; 15 | // @use 'gradient-headings'; 16 | @use "overflow-indicator"; 17 | @use "list-counter-style"; 18 | // @use 'reading-mode'; 19 | @use "topbar-fusion-plus"; 20 | @use "selected-block-indicator"; 21 | @use "hide-side-panel-block-icons"; 22 | @use "performance-improvements"; 23 | // @use 'floating-docks'; 24 | // @use 'layout-bento'; 25 | // @use "layout-paper"; 26 | -------------------------------------------------------------------------------- /styles/features/layout-bento.scss: -------------------------------------------------------------------------------- 1 | @use "../components/utils" as *; 2 | 3 | body { 4 | $gap-unit: 8px; 5 | $br-unit: 6px; 6 | $border-clr: rgba(from var(--b3-theme-on-background) r g b / 0.08); 7 | 8 | @mixin bento { 9 | border-radius: calc($br-unit * 2); 10 | // box-shadow: 0 0 0 1px $border-clr; 11 | } 12 | 13 | background-color: var(--b3-theme-surface); 14 | 15 | > .fn__flex { 16 | margin: 0 $gap-unit $gap-unit; 17 | } 18 | 19 | // docks & side panels 20 | 21 | .dock { 22 | background-color: var(--b3-theme-surface) !important; 23 | border-color: transparent !important; 24 | } 25 | 26 | .file-tree { 27 | @include bento(); 28 | background-color: var(--b3-theme-background); 29 | margin-left: 1px; 30 | margin-right: 1px; 31 | margin-bottom: 1px; 32 | } 33 | 34 | // .dock.fn__none+.layout { 35 | // .layout__dockl .file-tree { 36 | // margin-left: $gap-unit; 37 | // } 38 | 39 | // .layout__dockr .file-tree { 40 | // margin-right: $gap-unit; 41 | // } 42 | // } 43 | 44 | // layout center 45 | .fn__flex-column[data-type="wnd"] > .fn__flex:first-child { 46 | background-color: var(--b3-theme-surface); 47 | } 48 | 49 | .layout-tab-container { 50 | background-color: var(--b3-theme-surface); 51 | } 52 | 53 | .protyle:not(.fullscreen) { 54 | @include bento(); 55 | margin-top: $gap-unit; 56 | } 57 | 58 | .protyle-background__img { 59 | margin: $gap-unit; 60 | width: calc(100% - $gap-unit * 2); 61 | border-radius: calc($br-unit + 4px); 62 | } 63 | 64 | // .layout__center { 65 | 66 | // // 处理分栏边距 67 | // .fn__flex-column, 68 | // &.fn__flex-column { 69 | 70 | // // 横向 71 | // >.fn__flex:not(:last-child) .protyle { 72 | // margin-bottom: 1px; 73 | // } 74 | // } 75 | 76 | // // 纵向 77 | // >.fn__flex:not(.fn__flex-column)>:where(.fn__flex, .fn__flex-column):not(:last-child) .protyle, 78 | // .fn__flex-column>.fn__flex>:where(.fn__flex, .fn__flex-column):not(:last-child) .protyle, 79 | // >.fn__flex:not(.fn__flex-column):not(:last-child) .protyle { 80 | // margin-right: 1px; 81 | // } 82 | // } 83 | 84 | .layout__resize { 85 | height: 8px; 86 | margin: 0; 87 | &--lr { 88 | width: 8px; 89 | height: auto; 90 | } 91 | &::after { 92 | background-color: transparent; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /styles/features/layout-paper.scss: -------------------------------------------------------------------------------- 1 | //https://github.com/mustakshif/Asri/issues/120#issuecomment-2566140825 2 | 3 | .dock-layout-expanded+#layouts { 4 | overflow: visible; 5 | 6 | >.fn__flex-1:first-child { 7 | overflow: visible; 8 | } 9 | 10 | .layout__center { 11 | overflow: visible; 12 | z-index: 1; 13 | 14 | >.fn__flex-1 { 15 | overflow: visible; 16 | 17 | >[data-type="wnd"] { 18 | overflow: visible; 19 | 20 | >.layout-tab-container { 21 | box-shadow: rgba(244, 244, 244, .12) 0px 0px 0px 1px, rgba(0, 0, 0, .16) 0px 24px 48px, rgba(0, 0, 0, .12) 0px 4px 16px; 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | .layout-tab-container { 29 | transition: box-shadow .2s; 30 | } -------------------------------------------------------------------------------- /styles/features/list-counter-style.scss: -------------------------------------------------------------------------------- 1 | $li-types: ".li[data-subtype=o]", ".li[data-subtype=u]"; 2 | 3 | .list[data-subtype="o"] { 4 | counter-reset: olcounter1 0 olcounter2 0 olcounter3 0; 5 | } 6 | 7 | .protyle-wysiwyg { 8 | @each $type in $li-types { 9 | $start: $type; 10 | $j: 1; 11 | 12 | @for $i from 1 through 3 { 13 | @if $type == ".li[data-subtype=o]" { 14 | #{$start} { 15 | counter-increment: olcounter1; 16 | 17 | @if $j >3 { 18 | > .protyle-action { 19 | color: transparent !important; 20 | 21 | &::after { 22 | content: counter(olcounter1) "."; 23 | } 24 | } 25 | } 26 | 27 | #{$type} { 28 | counter-increment: olcounter2; 29 | 30 | > .protyle-action { 31 | color: transparent !important; 32 | 33 | &::after { 34 | content: counter(olcounter2, lower-alpha) "."; 35 | } 36 | } 37 | 38 | #{$type} { 39 | counter-increment: olcounter3; 40 | 41 | > .protyle-action { 42 | color: transparent !important; 43 | 44 | &::after { 45 | content: counter(olcounter3, lower-roman) "."; 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } @else { 52 | #{$start} { 53 | > .protyle-action::after { 54 | content: "•"; 55 | } 56 | 57 | #{$type} { 58 | > .protyle-action::after { 59 | content: "◦"; 60 | } 61 | 62 | #{$type} { 63 | > .protyle-action::after { 64 | content: "▪"; 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | $start: $start + " " + $type + " " + $type + " " + $type; 72 | $j: $j + 3; 73 | } 74 | } 75 | 76 | // other styles 77 | // ordered list starting from 2nd level li 78 | .li .li[data-subtype="o"] > .protyle-action { 79 | &::after { 80 | color: var(--b3-theme-on-background); 81 | white-space: nowrap; 82 | // text-align: end; 83 | } 84 | 85 | &:hover { 86 | // color: transparent !important; 87 | 88 | &::after { 89 | color: var(--b3-theme-primary); 90 | } 91 | } 92 | } 93 | 94 | .li:not([data-subtype="t"]) > .protyle-action { 95 | line-height: 1em; 96 | } 97 | 98 | // unordered list 99 | .li[data-subtype="u"] > .protyle-action { 100 | // color: transparent !important; 101 | svg { 102 | visibility: hidden; 103 | } 104 | 105 | &::after { 106 | font-family: Arial; 107 | font-size: 1.5em; 108 | text-align: center; 109 | // color: var(--b3-theme-on-background); 110 | line-height: 1; 111 | color: inherit; 112 | left: unset; 113 | top: unset; 114 | margin: 0; 115 | } 116 | } 117 | 118 | // folded list 119 | .li[fold="1"] { 120 | &:not([data-subtype="t"]) { 121 | .protyle-action { 122 | &::after { 123 | transform: none; 124 | // outline: .25em solid rgb(from var(--b3-theme-on-background) r g b / .1); 125 | box-shadow: 0 0 0 0.25em rgb(from var(--b3-theme-on-background) r g b / 0.1); 126 | } 127 | 128 | &:hover::after { 129 | background-color: rgb(from var(--b3-theme-on-background) r g b / 0.1); 130 | } 131 | } 132 | } 133 | 134 | &[data-subtype="u"] { 135 | .protyle-action::after { 136 | box-shadow: none; 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /styles/features/mode-transition.scss: -------------------------------------------------------------------------------- 1 | ::view-transition-old(root), 2 | ::view-transition-new(root) { 3 | animation-duration: 0.5s; 4 | } 5 | 6 | // Material Design 的共享轴过渡 7 | // https://developer.chrome.com/docs/web-platform/view-transitions/same-document?hl=zh-cn 8 | // @keyframes fade-in { 9 | // from { 10 | // opacity: 0; 11 | // } 12 | // } 13 | 14 | // @keyframes fade-out { 15 | // to { 16 | // opacity: 0; 17 | // } 18 | // } 19 | 20 | // @keyframes slide-from-right { 21 | // from { 22 | // transform: translateX(30px); 23 | // } 24 | // } 25 | 26 | // @keyframes slide-to-left { 27 | // to { 28 | // transform: translateX(-30px); 29 | // } 30 | // } 31 | 32 | // ::view-transition-old(root) { 33 | // animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out, 34 | // 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left; 35 | // } 36 | 37 | // ::view-transition-new(root) { 38 | // animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 39 | // 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right; 40 | // } 41 | // material design 共享轴过渡结束 42 | 43 | // old 44 | // .asri-mode-transition { 45 | // &, 46 | // > :where(.fn__flex-1, [id], [data-key], .block__popover) *, 47 | // ::before, 48 | // ::after { 49 | // transition-property: background-color, color, border-color, outline-color; 50 | // transition-duration: .5s !important; 51 | // transition-delay: .1s; 52 | // transition-timing-function: cubic-bezier(.2, 0, 0, 1); 53 | // } 54 | 55 | // #status, #dockBottom { 56 | // transition-duration: .5s !important; 57 | // } 58 | 59 | // .asri-config > svg { 60 | // transition: none; 61 | // } 62 | // } 63 | -------------------------------------------------------------------------------- /styles/features/overflow-indicator.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | @use "./utils" as *; 3 | 4 | $fadeout-size-s: 18px; 5 | $fadeout-size-m: 32px; 6 | $fadeout-size-l: 40px; 7 | $fadeout-size-xl: 50px; 8 | 9 | // .layout-tab-bar { 10 | // @include overflow-indicator-fadein-mask($fadeout-size-s, $range: 'left right'); 11 | // } 12 | 13 | .file-tree:not(.sy__backlink) .block__icons ~ .fn__flex-1, 14 | .sy__file > .b3-list > .fn__flex-1 { 15 | @include overflow-indicator-fadein-mask($fadeout-size-m, "top"); 16 | } 17 | 18 | .file-tree.sy__file .block__icons ~ .fn__flex-1 { 19 | @include overflow-indicator-fadein-mask($fadeout-size-m, "top bottom"); 20 | } 21 | 22 | .layout__dockb.layout--float .file-tree:not(.sy__backlink) .block__icons ~ .fn__flex-1 { 23 | @include overflow-indicator-fadein-mask($fadeout-size-s, "top bottom"); 24 | } 25 | 26 | // .file-tree.sy__backlink .backlinkList { 27 | // @include overflow-indicator-fadein-mask($fadeout-size-s, 'bottom'); 28 | // } //文字编辑工具条会被裁切 29 | 30 | .layout__dockb { 31 | .file-tree:not(.sy__backlink) .block__icons ~ .fn__flex-1 { 32 | @include overflow-indicator-fadein-mask($fadeout-size-s, "top"); 33 | } 34 | } 35 | 36 | [data-name="bazaar"] .config-bazaar__panel { 37 | @include overflow-indicator-fadein-bgClr($fadeout-size-l, $range: "top"); 38 | 39 | &::before { 40 | top: 44px; 41 | z-index: 2; 42 | } 43 | } 44 | 45 | [data-name="AI"] .layout-tab-bar + .fn__flex-1, 46 | .history__repo[data-type="repo"] .b3-list--background { 47 | @include overflow-indicator-fadein-bgClr($fadeout-size-m, $range: "top"); 48 | } 49 | 50 | // pdf 侧边导航 51 | #thumbnailView, 52 | #outlineView { 53 | @include overflow-indicator-fadein-bgClr($fadeout-size-m, $range: "top"); 54 | 55 | &::before { 56 | top: -10px; 57 | } 58 | } 59 | 60 | // 部分插件配置窗口,移动文档窗口 61 | .b3-dialog__header:not(.fn__none) + .b3-dialog__body :where(.config__tab-container, .layout-tab-bar + .fn__flex-1) { 62 | @include overflow-indicator-fadein-bgClr($fadeout-size-m, $range: "top"); 63 | } 64 | 65 | #foldTree { 66 | @include overflow-indicator-fadein-bgClr($fadeout-size-m, $range: "top bottom"); 67 | } 68 | 69 | // body:not(.has-exportimg) // https://github.com/mustakshif/Asri/issues/106 70 | .b3-dialog__header:not(.fn__none) + .b3-dialog__body .b3-dialog__content { 71 | @include overflow-indicator-fadein-bgClr($fadeout-size-m, $range: "top bottom"); 72 | 73 | &::before { 74 | top: -12px; 75 | } 76 | 77 | &::after { 78 | bottom: -12px; 79 | } 80 | } 81 | 82 | // 可能导致打开代码片段时渲染进程崩溃 83 | // [data-key="dialog-snippets"] .b3-dialog__body>.fn__flex-1 { 84 | // @include overflow-indicator-fadein-bgClr($fadeout-size-m, $range: 'top bottom'); 85 | 86 | // &::before { 87 | // top: -16px; 88 | // } 89 | 90 | // &::after { 91 | // bottom: -16px; 92 | // } 93 | // } 94 | 95 | [data-key="dialog-attr"] .b3-dialog__body .layout-tab-bar + .fn__flex-1 { 96 | @include overflow-indicator-fadein-bgClr($fadeout-size-m, $range: "top"); 97 | } 98 | 99 | [data-key="dialog-backgroundrandom"] .b3-dialog__body > .b3-cards { 100 | @include overflow-indicator-fadein-bgClr($fadeout-size-xl, $range: "top"); 101 | 102 | padding-top: 0; 103 | 104 | &::before { 105 | grid-column: 1/-1; 106 | } 107 | } 108 | 109 | // #message>.fn__flex-1 { 110 | // @include overflow-indicator-fadein-mask($fadeout-size-m, $range: 'top bottom'); 111 | // } 112 | 113 | .b3-dialog .emojis__panel { 114 | // @include overflow-indicator-line; 115 | @include overflow-indicator-fadein-mask($fadeout-size-l, $range: "top"); 116 | 117 | &::before { 118 | width: calc(100% + 16px); 119 | margin-left: -8px; 120 | margin-right: -8px; 121 | } 122 | } 123 | 124 | body:not(.asri-tfp-progressive) .protyle-breadcrumb__bar { 125 | @include overflow-indicator-fadein-mask($fadeout-size-s, $range: "left right"); 126 | } 127 | 128 | // body:not(.asri-tfp) { 129 | // .protyle-content { 130 | // @include overflow-indicator-fadein-bgClr($fadeout-size-xl, $range: 'top'); 131 | 132 | // .protyle-background__icon { 133 | // z-index: auto; 134 | // } 135 | // } 136 | // } 137 | 138 | [data-key="dialog-exportimage"] .b3-dialog__content::before, 139 | [data-key="dialog-replacetype"] .b3-dialog__content::before, 140 | [data-key="dialog-searchtype"] .b3-dialog__content::before { 141 | display: none !important; // fix https://github.com/mustakshif/Asri/issues/80 142 | } 143 | 144 | [data-key="dialog-searchtype"] .b3-dialog__content::after { 145 | grid-column: 1 / -1; 146 | } 147 | 148 | [data-key="dialog-searchtype"] .b3-dialog__content, 149 | [data-key="dialog-replacetype"] .b3-dialog__content { 150 | @include overflow-indicator-fadein-mask($fadeout-size-m, $range: "top"); 151 | } 152 | 153 | @keyframes maskAppear-bgClr { 154 | 0% { 155 | opacity: 0; 156 | } 157 | 158 | 1% { 159 | opacity: 1; 160 | } 161 | 162 | 100% { 163 | opacity: 1; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /styles/features/panda-scheme.scss: -------------------------------------------------------------------------------- 1 | @supports (color: oklch(from red calc(l * 0.5) 0 h)) { 2 | :root[data-theme-mode="light"] { 3 | body // body.asri-enable-panda-scheme 4 | 5 | //[]左停靠栏收起的情况 6 | //[]列表项目高亮背景颜色 7 | //[]分割线颜色 8 | //[]反链面板 9 | { 10 | #dockLeft.dock-layout-expanded, 11 | .layout__dockl:not(.layout--float), 12 | #toolbar button:not(#AsriTopbarLeftSpacing.asri-expanded ~ button), 13 | #toolbar div:not(#AsriPluginsIconsDivider, #AsriPluginsIconsDivider ~ div, #AsriTopbarLeftSpacing.asri-expanded ~ div) // .config__panel .b3-tab-bar 14 | { 15 | --l-background: 0.25; 16 | --l-background-grayscale: 0.24; 17 | --l-surface: 0.34; 18 | --l-surface-grayscale: 0.34; 19 | --l-on-background: 0.92; 20 | 21 | --asri-composite-background: oklch(from var(--asri-base-color) 0.25 calc(0.01 * var(--asri-c-factor, 1) * var(--asri-c-0, 1)) h); 22 | --asri-composite-surface: oklch(from var(--asri-base-color) 0.34 calc(0.012 * var(--asri-c-factor, 1) * var(--asri-c-0, 1)) h); 23 | --asri-composite-on-background: oklch(from var(--asri-base-color) 0.89 clamp(0, 0.01 * var(--asri-c-factor, 1) * var(--asri-c-0, 1), 0.04) h); 24 | 25 | --b3-theme-background: var(--asri-composite-background-grayscale, var(--asri-composite-background, var(--asri-fallback-background))); 26 | --b3-theme-surface: var(--asri-composite-surface-grayscale, var(--asri-composite-surface, var(--asri-fallback-surface))); 27 | 28 | --b3-theme-on-background: var(--asri-composite-on-background-grayscale, var(--asri-composite-on-background, var(--asri-fallback-on-background))); 29 | --b3-theme-on-surface: oklch(from var(--b3-theme-on-background) l c h / 0.65); 30 | 31 | --b3-list-hover: oklch(from var(--b3-theme-on-background) l c h / 0.08); 32 | 33 | --b3-border-color-trans: oklch(from var(--b3-theme-on-background) l c h / 0.15); 34 | 35 | color-scheme: dark; 36 | -webkit-font-smoothing: antialiased; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /styles/features/performance-improvements.scss: -------------------------------------------------------------------------------- 1 | // no effect 2 | 3 | // .layout__center .protyle-content { 4 | // contain: content; 5 | // } 6 | 7 | // .file-tree:where(.sy__file, .sy__outline, .sy__bookmark, .sy__tag, .sy__backlink) { 8 | // contain: strict; 9 | // } 10 | 11 | // .protyle-top { 12 | // // content-visibility: auto; 13 | // // contain: content; // conflict with sidebar memo plugin 14 | // } 15 | 16 | // .layout__dockl, .layout__dockr { 17 | // contain: content; // https://github.com/mustakshif/Asri/issues/150 18 | // } 19 | -------------------------------------------------------------------------------- /styles/features/reading-mode.scss: -------------------------------------------------------------------------------- 1 | .protyle-wysiwyg:where([custom-rdmd="s"]) { 2 | font-family: "Cardo", "Charter", "Palatino", "Geeza Pro", "Songti", "Times New Roman", Times, serif; 3 | 4 | > div:not(.h1, .h2, .h3, .h4, .h5, .h6), 5 | > :where(.h1, .h2, .h3, .h4, .h5, .h6) > div:not(.protyle-attr) { 6 | font-size: 105%; 7 | } 8 | } 9 | 10 | .protyle-wysiwyg[custom-rdmd="k"] { 11 | font-family: "EB Garamond", "Muna", "Damascus", "Sakkal Majalla", "Kaiti", "STKaiti", "Times New Roman", Times, serif; 12 | 13 | > div:not(.h1, .h2, .h3, .h4, .h5, .h6), 14 | > :where(.h1, .h2, .h3, .h4, .h5, .h6) > div:not(.protyle-attr) { 15 | font-size: 110%; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /styles/features/rtl.scss: -------------------------------------------------------------------------------- 1 | :where(:lang(ar_SA), :lang(he_IL)) { 2 | --gnf: -1; // global negate factor 3 | 4 | // 所有 rtl 元素 5 | .file-tree:where(.sy__file, .sy__outline, .sy__tag, .sy__bookmark, .sy__globalGraph, .sy__graph, .sy__backlink), 6 | .b3-menu, 7 | .protyle-breadcrumb, 8 | #tooltip, 9 | .b3-button, 10 | .protyle-util .block__icons--menu, 11 | .protyle-hint.hint--menu > div, 12 | :where( 13 | [data-key="dialog-setting"], 14 | [data-key="dialog-confirm"], 15 | [data-key="dialog-snippets"], 16 | [data-key="dialog-emojis"], 17 | [data-key="dialog-recentdocs"], 18 | [data-key="dialog-searchtype"], 19 | [data-key="dialog-wechatreminder"], 20 | [data-key="dialog-setpassword"], 21 | [data-key="dialog-saveworkspace"], 22 | [data-key="dialog-createnotebook"], 23 | [data-key="dialog-rename"], 24 | [data-key="dialog-commandpanel"], 25 | [data-key="dialog-aiupdatecustomaction"], 26 | [data-key="dialog-backgroundlink"], 27 | [data-key="dialog-aicustomaction"] 28 | ) 29 | .b3-dialog__container { 30 | direction: rtl; 31 | } 32 | 33 | // 所有 ltr 元素 34 | // 集市包详情页 35 | .item__main, 36 | // 集市卡片描述 37 | .b3-card .b3-card__info, 38 | // “/”菜单字符类快捷键提示 39 | .protyle-hint .b3-list-item--two .b3-list-item__meta { 40 | direction: ltr; 41 | } 42 | 43 | // 侧栏面板 ********************** 44 | 45 | .sy__tag, 46 | .sy__outline { 47 | .b3-list-item__toggle { 48 | margin-right: unset !important; 49 | margin-inline-end: 2px; 50 | } 51 | } 52 | 53 | .sy__outline .b3-list-item[data-type="NodeHeading"] .b3-list-item__text::before { 54 | transform: translateX(18px); 55 | } 56 | 57 | .block__logo { 58 | margin-right: unset; 59 | margin-inline-end: 8px; 60 | } 61 | 62 | .sy__bookmark { 63 | .b3-list-item__toggle { 64 | margin-right: unset !important; 65 | margin-inline-end: 2px; 66 | } 67 | } 68 | 69 | .search__label { 70 | right: unset; 71 | inset-inline-end: 8px; 72 | } 73 | 74 | // 杂项 *********************** 75 | 76 | .protyle-breadcrumb__icon { 77 | margin-right: unset; 78 | margin-inline-end: 8px; 79 | } 80 | 81 | .b3-menu { 82 | &__icon { 83 | margin-right: unset; 84 | margin-inline-end: 8px; 85 | // transform: scaleX(-1); 86 | 87 | &--small { 88 | margin-left: unset; 89 | margin-inline-start: 8px; 90 | transform: scaleX(-1); 91 | } 92 | } 93 | 94 | .b3-menu__action { 95 | margin-left: unset; 96 | margin-inline-start: 8px; 97 | } 98 | 99 | &__item { 100 | text-align: start; 101 | } 102 | 103 | &__accelerator:not([style="margin-left: 0"]) { 104 | margin-left: unset; 105 | margin-inline-start: 16px; 106 | } 107 | } 108 | 109 | .b3-button { 110 | svg { 111 | margin-right: unset; 112 | margin-inline-end: 4px; 113 | transform: scaleX(-1); 114 | } 115 | } 116 | 117 | .b3-list-item__graphic { 118 | margin-right: unset; 119 | margin-inline-end: 4px; 120 | } 121 | 122 | .b3-list-item__text { 123 | text-align: start; 124 | } 125 | 126 | .color__square--list { 127 | margin-right: unset; 128 | margin-inline-end: 8px; 129 | } 130 | 131 | .config__panel > .b3-tab-bar .b3-list-item__graphic { 132 | padding-left: unset; 133 | padding-right: unset; 134 | padding-inline-start: 5px; 135 | padding-inline-end: 10px; 136 | } 137 | 138 | .b3-chip svg:not(.b3-chip__close) { 139 | margin-right: unset; 140 | margin-inline-end: 6px; 141 | } 142 | 143 | .b3-switch { 144 | transform: scaleX(-1); 145 | } 146 | 147 | .config-bazaar__panel .config-bazaar__title .b3-switch { 148 | transform: scaleX(-1) translateX(11px); 149 | } 150 | 151 | .b3-card__actions--right .block__icon { 152 | margin-left: unset; 153 | margin-inline-start: 8px; 154 | } 155 | 156 | [data-type="goBack"] svg, 157 | .av__panel .b3-menu .block__icon svg, 158 | .config-keymap .b3-list-item__arrow:not(.b3-list-item__arrow--open), 159 | .file-tree:where(.sy__file, .sy__outline, .sy__tag, .sy__bookmark, .sy__globalGraph, .sy__graph, .sy__backlink) .b3-list-item__arrow:not(.b3-list-item__arrow--open) // .b3-list-item__toggle, 160 | 161 | // [data-type="docnext"] svg, 162 | // [data-type="docprevious"] svg, 163 | // .block__icon[data-type="next"] svg, 164 | // .block__icon[data-type="previous"] svg 165 | { 166 | transform: rotate(180deg); 167 | } 168 | 169 | // 设置-快捷键 170 | .b3-list--border .b3-list__panel { 171 | margin-left: unset; 172 | margin-inline-start: 34px; 173 | } 174 | 175 | // 设置-标题 176 | // .config__tab-title.resize__move { 177 | // pointer-events: none; 178 | // } 179 | 180 | // .resize__rd, .resize__ld, .resize__lt, .resize__rt, .resize__l, .resize__r, .resize__t, .resize__d { 181 | // pointer-events: none; 182 | // } 183 | 184 | .b3-menu__avemoji { 185 | margin-left: unset; 186 | margin-right: unset; 187 | margin-inline: -4px 4px; 188 | } 189 | 190 | // 数据库 191 | .av__panel .b3-menu__item .b3-chip { 192 | float: unset; 193 | } 194 | 195 | // 通知 196 | .b3-snackbar--error .b3-snackbar__content { 197 | padding-left: unset; 198 | padding-inline-start: 47px; 199 | padding-right: unset; 200 | padding-inline-end: 16px; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /styles/features/selected-block-indicator.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | .protyle-wysiwyg[data-readonly="false"] { 4 | [data-node-id].asri-selected-block:not(.rc-focus) { 5 | // https://github.com/mustakshif/Asri/issues/156 6 | 7 | // box-shadow: none !important; 8 | &::before { 9 | content: ""; 10 | position: absolute; 11 | height: calc(100% - 16px); 12 | width: 3px; 13 | border-radius: 99px; 14 | top: 8px; 15 | inset-inline-start: -5px; 16 | inset-inline-end: 0; 17 | bottom: 0; 18 | background-color: var(--b3-theme-primary); 19 | animation: selected-block-indicator-appear 0.6s var(--asri-ease-spring-4); 20 | // animation-delay: .2s; 21 | transform-origin: top center; 22 | transition-property: opacity, transform; 23 | transition-duration: 0.3s; 24 | transition-timing-function: var(--asri-ease-spring-2); 25 | } 26 | 27 | &.protyle-wysiwyg--hl { 28 | &::before { 29 | opacity: 0; 30 | transform: scaleY(0.5); 31 | transition-duration: 0.3s; 32 | transition-timing-function: var(--asri-ease-elastic-in-out-3); 33 | } 34 | } 35 | 36 | &#plugin-focus-unique-id, 37 | &[data-plugin-focus="true"] { 38 | &::before { 39 | display: none; 40 | } 41 | } 42 | } 43 | } 44 | 45 | @keyframes selected-block-indicator-appear { 46 | 0% { 47 | transform: scaleY(0.8); 48 | opacity: 0; 49 | } 50 | 51 | 100% { 52 | transform: scaleY(1); 53 | opacity: 1; 54 | } 55 | } 56 | 57 | //内容块根据视口位置淡入淡出 58 | // .protyle-wysiwyg { 59 | // >[data-node-id]:not(.asri-selected-block) { 60 | // @supports (animation-timeline: view()) { 61 | // view-timeline-name: --content-block-view; 62 | 63 | // animation-timeline: --content-block-view; 64 | // animation-range: 0% 100%; 65 | // animation-fill-mode: both; 66 | // animation-name: content-block-fadeinout; 67 | // animation-timing-function: linear; 68 | // } 69 | 70 | // @keyframes content-block-fadeinout { 71 | 72 | // 0%, 73 | // 10%, 74 | // 90%, 75 | // 100% { 76 | // opacity: 0; 77 | // // filter: blur(4px); 78 | // } 79 | 80 | // 0%, 10% { 81 | // transform: translateY(40px); 82 | // } 83 | 84 | // // 90%, 100% { 85 | // // transform: translateY(-20px); 86 | // // } 87 | 88 | // 40%, 89 | // 60% { 90 | // opacity: 1; 91 | // transform: none; 92 | // } 93 | 94 | // // 30%, 95 | // // 70% { 96 | // // filter: none; 97 | // // } 98 | // } 99 | // } 100 | // } 101 | -------------------------------------------------------------------------------- /styles/layout/dock.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | .dock { 4 | box-sizing: border-box; 5 | background-color: transparent; 6 | 7 | &[style~="z-index"] { 8 | z-index: auto !important; 9 | } 10 | 11 | .dock__items { 12 | min-width: unset; 13 | } 14 | 15 | .dock__item { 16 | // @include theme-variant-color(color, on-background, 0.6); 17 | color: var(--b3-theme-on-surface); 18 | 19 | &:not(.dock__item--activefocus, .dock--active):hover { 20 | color: var(--b3-theme-on-background); 21 | } 22 | 23 | &:hover { 24 | background-color: transparent; 25 | } 26 | 27 | &--activefocus, 28 | &--active { 29 | color: var(--b3-theme-primary) !important; 30 | background-color: transparent !important; 31 | } 32 | } 33 | 34 | &#dockLeft { 35 | --border-clr: var(--b3-border-color); 36 | // box-shadow: 1px var(--toolbar-height) 0 var(--border-clr); 37 | // border:none; 38 | // padding-left: 1px; 39 | border-right-width: 1px; 40 | border-right-color: var(--border-clr); 41 | } 42 | 43 | &#dockRight { 44 | --border-clr: var(--b3-border-color); 45 | // box-shadow: -1px var(--toolbar-height) 0 var(--border-clr); 46 | // border: none; 47 | border-left-width: 1px; 48 | border-left-color: var(--border-clr); 49 | 50 | // .body-asri--mac &, 51 | // .body-asri--browser & { 52 | // box-shadow: -1px 0 0 var(--border-clr); 53 | // } 54 | } 55 | 56 | &#dockBottom { 57 | padding: 0 0 0 34px; 58 | border-top-width: 1px; 59 | background-color: var(--b3-theme-background); // fix https://github.com/mustakshif/Asri/issues/37 60 | 61 | // .fn__flex:first-child, 62 | // .fn__flex:last-child { 63 | // .dock__item:not(:first-child){ 64 | // margin-left: 0; 65 | // } 66 | // } 67 | 68 | .dock__item { 69 | margin: 7px 3.5px; 70 | } 71 | 72 | .dock__item--pin { 73 | position: fixed; 74 | left: 3.5px; 75 | opacity: 1; 76 | } 77 | 78 | &.has-layout-dockb-float { 79 | .fn__flex:last-child .dock__item:last-child { 80 | margin-right: 8px; 81 | } 82 | } 83 | 84 | &:not(.has-layout-dockb-float) { 85 | .fn__flex-1 { 86 | flex: 0 0 15px; 87 | } 88 | 89 | .fn__flex:last-child:not(:empty) { 90 | &::before { 91 | content: ""; 92 | display: block; 93 | background-color: var(--b3-border-color-trans); 94 | height: 20px; 95 | width: 2px; 96 | margin-top: 10px; 97 | transform: translateX(-7.5px); 98 | border-radius: 2px; 99 | } 100 | } 101 | } 102 | } 103 | 104 | &.dock-layout-expanded { 105 | // -> js 106 | background-color: var(--b3-theme-surface); 107 | 108 | &#dockLeft, 109 | &#dockRight { 110 | --border-clr: transparent; 111 | } 112 | } 113 | } 114 | 115 | /* 以下代码影响性能 */ 116 | // #dockLeft:has(+ #layouts .layout__dockl:not(.layout--float)>.fn__flex-1:not(.fn__none)), 117 | // #layouts:has(.layout__dockr:not(.layout--float, [style="width: 0px;"])> .fn__flex-1:first-child:not(.fn__none))~#dockRight { 118 | // border-color: transparent; 119 | // @include layout__dock-bg($theme-light); 120 | // @include darkmode-counterpart { 121 | // @include layout__dock-bg($theme-dark); 122 | // } 123 | // } 124 | -------------------------------------------------------------------------------- /styles/layout/index.scss: -------------------------------------------------------------------------------- 1 | @use "dock"; 2 | @use "status"; 3 | @use "topbar"; 4 | @use "tab-bar"; 5 | @use "side-panels"; 6 | -------------------------------------------------------------------------------- /styles/layout/tab-bar.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | // tab-bar 容器 4 | .fn__flex-column[data-type="wnd"] { 5 | > .fn__flex:first-child { 6 | height: 42px; 7 | background-color: var(--b3-theme-background); // 适配 `替换图片背景` 插件 8 | 9 | // transition: padding, .2s cubic-bezier(0.25, 0.46, 0.45, 0.94); 10 | } 11 | } 12 | 13 | .layout-tab-bar { 14 | background-color: transparent; 15 | height: 28px; 16 | border-bottom: 0; 17 | overflow-y: hidden; 18 | border-radius: 6px; 19 | margin: 8px 8px 6px; 20 | transition: margin 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); 21 | scrollbar-width: none; 22 | 23 | .item { 24 | // transition: none; 25 | height: 28px; 26 | min-width: unset; 27 | min-height: unset; 28 | line-height: 24px; 29 | margin-inline-end: 8px; 30 | border-radius: 6px; 31 | overflow: visible; 32 | background-color: var(--b3-list-hover); 33 | // transition-property: max-width, width, backdrop-filter, background-color, color; 34 | 35 | &:last-child { 36 | margin-inline-end: unset; 37 | } 38 | 39 | &:not(.item--readonly, .item--full.item--focus):hover { 40 | @include theme-variant-color(background-color, list-hover, 0.12, 0.15); 41 | } 42 | 43 | &__icon { 44 | padding: 2px 0 0 8px; 45 | display: flex; 46 | justify-content: center; 47 | align-items: center; 48 | line-height: 28px; 49 | font-size: 14px; 50 | // vertical-align: -1px; // 无用声明 51 | 52 | .body--win32 & { 53 | padding-top: 0; 54 | } 55 | 56 | .body-asri--mac & > img { 57 | transform: translateY(-1px); 58 | } 59 | } 60 | 61 | &__text { 62 | padding: 2px 6px 2px 6px; 63 | mask-image: linear-gradient(to left, rgba(0, 0, 0, 0) 0, #000 8px); 64 | transition-timing-function: var(--asri-ease-out-5); 65 | } 66 | 67 | &__close { 68 | padding: 4px 6px 4px 2px; 69 | 70 | svg { 71 | width: 10px; 72 | height: 10px; 73 | } 74 | } 75 | 76 | &--pin { 77 | height: 24px; 78 | padding: 2px; 79 | 80 | .item__icon { 81 | display: flex; 82 | justify-content: center; 83 | align-items: center; 84 | padding: 2px 5px 0; 85 | 86 | body.body--win32 & { 87 | padding: 2px 5px; 88 | } 89 | } 90 | 91 | & + .item:not(.item--pin, .item--readonly) { 92 | margin-inline-start: 14px; 93 | 94 | &::before { 95 | content: ""; 96 | position: absolute; 97 | inset-inline-start: -12px; 98 | display: block; 99 | width: 2px; 100 | background-color: var(--b3-border-color-trans); 101 | height: 1.5em; 102 | border-radius: 9px; 103 | pointer-events: none; 104 | } 105 | } 106 | } 107 | 108 | &--focus { 109 | max-width: 21rem; 110 | // font-weight: 500; 111 | transition: 0.2s; 112 | // border-radius: 7px; 113 | @include theme-variant-color(background-color, list-hover, 0.12, 0.15); 114 | // box-shadow: 0 0 0 1.2px var(--tab-border-clr) inset; 115 | animation: click 0.2s; 116 | 117 | &::after { 118 | display: none; 119 | } 120 | } 121 | 122 | &:not(.item--pin, .item--full, .item--focus) { 123 | .item__text { 124 | transform: translateX(12px); 125 | } 126 | 127 | :is(.item__icon, .item__graphic), 128 | :is(.item__icon, .item__graphic) + .item__text { 129 | transform: translateX(10px); 130 | } 131 | } 132 | 133 | &:hover { 134 | .item__text, 135 | :is(.item__icon, .item__graphic), 136 | :is(.item__icon, .item__graphic) + .item__text { 137 | transform: none; 138 | } 139 | } 140 | 141 | &__icon, 142 | &__graphic { 143 | transition-duration: 0.2s; 144 | transition-property: transform; 145 | transition-timing-function: var(--asri-ease-out-5); 146 | } 147 | 148 | &--unupdate:not(.item--pin) .item__icon { 149 | font-style: normal; 150 | } 151 | 152 | // &__icon, &__text { 153 | // transition-delay: .125s; 154 | // } 155 | 156 | // --tab-border-clr: var(--b3-border-color-trans); 157 | // @include darkmode-counterpart { 158 | // --tab-border-clr: rgba(from var(--b3-theme-on-background) r g b / .3); 159 | // } 160 | } 161 | } 162 | 163 | .layout-tab-bar--readonly { 164 | margin-left: 0; 165 | min-width: 59px; 166 | 167 | .item { 168 | background-color: transparent; 169 | padding: 0; 170 | height: 28px; 171 | cursor: default; 172 | 173 | &:hover { 174 | background-color: transparent; 175 | } 176 | 177 | .block__icon { 178 | padding: 8px; 179 | 180 | svg { 181 | width: 12px; 182 | height: 12px; 183 | } 184 | } 185 | 186 | span:nth-child(2) { 187 | font-size: 0; 188 | } 189 | } 190 | } 191 | 192 | body.body--blur .layout__wnd--active .layout-tab-bar .item--focus { 193 | box-shadow: none; 194 | } 195 | 196 | @keyframes click { 197 | 0% { 198 | transform: scale(1); 199 | opacity: 1; 200 | } 201 | 202 | 50% { 203 | transform: scale(0.95); 204 | opacity: 0.8; 205 | } 206 | 207 | 100% { 208 | transform: scale(1); 209 | opacity: 1; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /styles/layout/topbar.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | #toolbar { 4 | height: var(--toolbar-height); 5 | background-color: var(--b3-theme-background); 6 | border-bottom: 1px solid var(--b3-border-color); 7 | overflow: visible; 8 | 9 | #barWorkspace { 10 | // background-color: var(--b3-theme-primary-lighter); 11 | background-color: #0000; 12 | color: var(--b3-theme-on-surface); 13 | font-weight: 500; 14 | height: 28px; 15 | position: relative; 16 | // box-shadow: 0 0 0 1px var(--b3-border-color-trans) inset; 17 | transition-property: background-color, color, outline; 18 | outline: 1px solid var(--b3-border-color-trans); 19 | outline-offset: -1px; 20 | 21 | &:hover { 22 | background-color: var(--b3-theme-primary); 23 | outline-color: transparent; 24 | color: var(--b3-theme-on-primary); 25 | // box-shadow: 0 0 0 1px transparent inset; 26 | } 27 | 28 | .toolbar__text { 29 | font-size: 14px; 30 | align-self: center; 31 | z-index: 1; 32 | line-height: normal; 33 | } 34 | 35 | svg.toolbar__svg { 36 | align-self: center; 37 | } 38 | } 39 | 40 | .toolbar__item { 41 | height: var(--toolbar-height); 42 | color: var(--b3-theme-on-surface); 43 | 44 | &:hover { 45 | background-color: transparent; 46 | } 47 | 48 | svg { 49 | align-self: center; 50 | } 51 | 52 | &--active { 53 | background-color: transparent; 54 | color: var(--b3-theme-primary); 55 | } 56 | 57 | &--disabled { 58 | opacity: 0.4; 59 | } 60 | 61 | &:not(.toolbar__item--disabled):not(.toolbar__item--close):hover { 62 | color: var(--b3-theme-on-background); 63 | } 64 | } 65 | 66 | &.toolbar--browser, 67 | body.body--win32 & { 68 | padding-left: 8px; 69 | } 70 | 71 | #closeWindow { 72 | padding: 9px; 73 | padding-right: 16px; 74 | 75 | &:hover, 76 | body.body--win32 &:hover { 77 | color: var(--b3-theme-error); 78 | background-color: transparent; 79 | } 80 | } 81 | 82 | // 应用全屏时 83 | .body-asri--fullscreen & { 84 | padding-inline-start: 8px !important; 85 | } 86 | } 87 | 88 | body:not(.body-asri--browser, .body-asri--mobile) { 89 | #barZoom, 90 | #barExit { 91 | display: none; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /styles/palettes/index.scss: -------------------------------------------------------------------------------- 1 | @use "./prst-palette-auriflow.scss"; 2 | @use "./prst-palette-everbliss.scss"; 3 | @use "./prst-palette-aerisland.scss"; 4 | @use "./prst-palette-zerith.scss"; 5 | // @use "./prst-palette-polarity.scss"; 6 | @use "./prst-palette-stellula.scss"; 7 | -------------------------------------------------------------------------------- /styles/palettes/prst-palette-aerisland.scss: -------------------------------------------------------------------------------- 1 | [data-asri-palette="aerisland"] { 2 | &[data-theme-mode="light"] { 3 | --aerisland-base-accent: #93dcd4; 4 | --asri-theme-accent-customized: var(--aerisland-base-accent); 5 | --b3-theme-primary: #4fbdb0; 6 | --b3-theme-accent: #2ea5a2; 7 | 8 | --b3-theme-on-background: #0c544c; 9 | --b3-theme-on-surface: #09423ba2; 10 | } 11 | 12 | &[data-theme-mode="dark"] { 13 | --aerisland-base-accent: #4d9c93; 14 | --asri-theme-accent-customized: var(--aerisland-base-accent); 15 | --b3-theme-primary: var(--aerisland-base-accent); 16 | 17 | --b3-theme-on-background: #c6c9b3; 18 | --b3-theme-on-surface: #c6c9b3a2; 19 | } 20 | 21 | .protyle-title__input, 22 | [data-type="NodeHeading"], 23 | .b3-dialog__header { 24 | color: var(--b3-theme-primary); 25 | } 26 | } 27 | 28 | #barWorkspace, 29 | #message, 30 | .b3-button--outline:hover, 31 | .b3-dialog__action .b3-button--text, 32 | #transactionError + .b3-dialog__action button:last-child, 33 | #configBazaarReadme .item__side .b3-button:not(.b3-button--progress):hover, 34 | .protyle-breadcrumb__icon:hover, 35 | .protyle-breadcrumb__item, 36 | .config-account__info .b3-button, 37 | .b3-menu, 38 | .b3-switch, 39 | .b3-button--outline, 40 | .protyle-breadcrumb__icon { 41 | [data-asri-palette="aerisland"][data-theme-mode="light"] & { 42 | --b3-theme-primary: var(--aerisland-base-accent); 43 | --b3-theme-on-primary: #07443d; 44 | } 45 | 46 | [data-asri-palette="aerisland"][data-theme-mode="dark"] & { 47 | --b3-theme-primary: var(--aerisland-base-accent); 48 | // --b3-theme-on-primary: #fffaf1; 49 | } 50 | } 51 | 52 | .b3-button--outline, 53 | .protyle-breadcrumb__icon { 54 | [data-asri-palette="aerisland"][data-theme-mode="light"] & { 55 | --b3-theme-primary: var(--b3-theme-accent); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /styles/palettes/prst-palette-auriflow.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | @mixin goldfoil-background { 4 | background: var(--texture-goldfoil); 5 | background-blend-mode: var(--texture-goldfoil-blend-mode); 6 | } 7 | 8 | @mixin goldfoil-border($border-width: 1px, $border-radius: 8px, $container-bg: var(--b3-theme-background)) { 9 | @include goldfoil-background; 10 | // border: $border-width solid transparent; 11 | // background-clip: border-box; 12 | position: relative; 13 | 14 | &::after { 15 | content: ""; 16 | background: $container-bg; 17 | position: absolute; 18 | inset: $border-width; 19 | z-index: -1; 20 | border-radius: $border-radius; 21 | } 22 | } 23 | 24 | [data-asri-palette="auriflow"] { 25 | --foil-local-clr: rgb(231, 205, 164); // 本色 26 | --foil-base-clr: rgb(252, 243, 148); // 底色 27 | --foil-highlight-opacity: 0.5; // 高光透明度 28 | --foil-shadow-opacity: 0.4; // 阴影透明度 29 | 30 | // https://www.zhangxinxu.com/wordpress/2023/06/css-noise/ 31 | $texture-goldfoil: repeating-radial-gradient(rgba(180, 135, 30, var(--foil-shadow-opacity)) 0 0.0001%, #0000 0 0.0002%) 30% 50% / 2500px 2500px, repeating-conic-gradient(var(--foil-local-clr) 0 0.0001%, #0000 0 0.0002%) 60% 60% / 2500px 2500px, repeating-conic-gradient(rgba(245, 227, 199, var(--foil-highlight-opacity)) 0 0.0001%, #0000 0 0.0002%) 50% 50% / 2500px 2500px, var(--foil-base-clr); 32 | 33 | --texture-goldfoil: #{$texture-goldfoil}; 34 | --texture-goldfoil-blend-mode: multiply, normal, hard-light, normal; 35 | 36 | @include darkmode-counterpart(true) { 37 | --b3-theme-on-background: #e8d9be; 38 | --b3-theme-on-surface: #e8d9bead; 39 | 40 | --foil-local-clr: rgb(190, 165, 100); 41 | --foil-base-clr: rgb(225, 207, 145); 42 | --foil-highlight-opacity: 0.4; 43 | --foil-shadow-opacity: 0.5; 44 | 45 | .b3-switch:checked { 46 | --foil-base-clr: rgb(178, 132, 6); 47 | background: $texture-goldfoil; // 解决css变量引用作用域问题 48 | } 49 | } 50 | 51 | // &[data-theme-mode=dark] .b3-switch:checked { 52 | // --foil-base-clr: rgb(178, 132, 6); 53 | // } 54 | 55 | // @include darkmode-counterpart(true) { 56 | // .b3-switch:checked { 57 | // --foil-base-clr: rgb(178, 132, 6); 58 | // } 59 | // } 60 | 61 | .config-bazaar__panel .b3-card:hover { 62 | @include goldfoil-border(1.5px, $border-radius: 18.5px); 63 | outline: none !important; 64 | } 65 | 66 | .b3-switch:checked, 67 | .b3-button--outline:hover, 68 | .b3-menu .b3-menu__items .b3-menu__item:hover:not(.b3-menu__item--readonly):not(.b3-menu__item--custom, .b3-menu__item--disabled):not([disabled]):not([data-type="nobg"]), 69 | .b3-menu .b3-menu__items .b3-menu__item--current:not(.b3-menu__item--readonly, .b3-menu__item--disabled):not([disabled]):not([data-type="nobg"]), 70 | .b3-menu__submenu .b3-menu__items .b3-menu__item:hover:not(.b3-menu__item--readonly):not(.b3-menu__item--custom, .b3-menu__item--disabled):not([disabled]):not([data-type="nobg"]), 71 | .b3-menu__submenu .b3-menu__items .b3-menu__item--current:not(.b3-menu__item--readonly, .b3-menu__item--disabled):not([disabled]):not([data-type="nobg"]), 72 | .protyle-wysiwyg .li.protyle-task--done > .protyle-action--task::before, 73 | .protyle-wysiwyg .li[data-subtype="t"] .protyle-action--task::before, 74 | .protyle-wysiwyg[data-readonly="false"] [data-node-id].asri-selected-block::before, 75 | #toolbar #barWorkspace:hover, 76 | .config__panel .config__tab-wrap .config__tab-container[data-name="account"] .config-account .b3-button--text:not(#activationCode), 77 | .config__panel .config__tab-wrap .config__tab-container[data-name="account"] .config-account button#login, 78 | .protyle-breadcrumb__icon:hover, 79 | .protyle-breadcrumb__item--active:not(:first-child) svg, 80 | .b3-button--text { 81 | @include goldfoil-background; 82 | // -webkit-font-smoothing: auto; 83 | } 84 | 85 | .protyle-title__input, 86 | [data-type="NodeHeading"]:not([style*="background-color"]), 87 | .b3-dialog__header { 88 | @include goldfoil-background; 89 | background-clip: text; 90 | color: rgba(from var(--b3-theme-on-background) r g b / 0.1); 91 | 92 | @include darkmode-counterpart { 93 | color: rgba(from var(--b3-theme-on-background) r g b / 0.2); 94 | } 95 | } 96 | 97 | [data-type="NodeHeading"]:not([style*="background-color"]) { 98 | [data-type="kbd"] { 99 | color: var(--b3-theme-on-surface); 100 | } 101 | } 102 | 103 | .protyle-wysiwyg [data-node-id].hr > div:after { 104 | @include goldfoil-background; 105 | // height: 1px; 106 | border-radius: 0; 107 | opacity: 0.7; 108 | } 109 | 110 | .b3-button--outline:hover { 111 | box-shadow: none; 112 | } 113 | 114 | .protyle-wysiwyg[data-readonly="false"] [data-node-id].asri-selected-block::before { 115 | // opacity: .6; 116 | border-radius: 0; 117 | width: 2px; 118 | } 119 | 120 | #toolbar #barWorkspace { 121 | transition-property: color; 122 | } 123 | 124 | .config-bazaar__title .b3-button--outline:hover { 125 | background: none; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /styles/palettes/prst-palette-everbliss.scss: -------------------------------------------------------------------------------- 1 | [data-asri-palette="everbliss"] { 2 | &[data-theme-mode="light"] { 3 | --everbliss-base-accent: #f06255; 4 | --asri-theme-accent-customized: var(--everbliss-base-accent); 5 | --b3-theme-primary: var(--everbliss-base-accent); 6 | 7 | --b3-theme-on-background: #4d3d5f; 8 | --b3-theme-on-surface: #4d3d5fa2; 9 | } 10 | 11 | &[data-theme-mode="dark"] { 12 | --everbliss-base-accent: #e4545e; 13 | --asri-theme-accent-customized: var(--everbliss-base-accent); 14 | --b3-theme-primary: var(--everbliss-base-accent); 15 | 16 | --b3-theme-on-background: #e3c9b0; 17 | --b3-theme-on-surface: #e3c9b0a2; 18 | } 19 | 20 | .protyle-title__input, 21 | [data-type="NodeHeading"], 22 | .b3-dialog__header { 23 | color: var(--b3-theme-primary); 24 | } 25 | } 26 | 27 | #barWorkspace, 28 | #message, 29 | .b3-button--outline:hover, 30 | .b3-dialog__action .b3-button--text, 31 | #transactionError + .b3-dialog__action button:last-child, 32 | #configBazaarReadme .item__side .b3-button:not(.b3-button--progress):hover, 33 | .protyle-breadcrumb__icon:hover, 34 | .protyle-breadcrumb__item, 35 | .config-account__info .b3-button, 36 | .b3-menu, 37 | .b3-switch, 38 | .b3-button--outline, 39 | .protyle-breadcrumb__icon { 40 | [data-asri-palette="everbliss"][data-theme-mode="light"] & { 41 | --b3-theme-primary: var(--everbliss-base-accent); 42 | --b3-theme-on-primary: #fefaef; 43 | } 44 | 45 | [data-asri-palette="everbliss"][data-theme-mode="dark"] & { 46 | --b3-theme-primary: var(--everbliss-base-accent); 47 | --b3-theme-on-primary: #f3d9c1; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /styles/palettes/prst-palette-polarity.scss: -------------------------------------------------------------------------------- 1 | @use "sass:list"; 2 | 3 | [data-asri-palette="polarity"] { 4 | &[data-theme-mode="light"] { 5 | --polarity-base-accent: #000; 6 | --asri-theme-accent-customized: var(--polarity-base-accent); 7 | --b3-theme-primary: var(--polarity-base-accent); 8 | --b3-theme-accent: #3478f6; 9 | 10 | --b3-theme-surface: #F5F5F7; 11 | 12 | --b3-theme-on-background: #1d1d1f; 13 | --b3-theme-on-surface: #1d1d1f81; 14 | 15 | // .layout__center 16 | // :not(.av__views) 17 | // > .layout-tab-bar 18 | // .item:not(.item--readonly, .item--full.item--focus):hover, 19 | // .layout__center :not(.av__views) > .layout-tab-bar .item--focus { 20 | // background-color: #c7ea008e; 21 | // } 22 | 23 | // [data-type="wnd"]:not(.layout__wnd--active) 24 | // :not(.av__views) 25 | // > .layout-tab-bar 26 | // .item--focus { 27 | // background-color: #c7ea0052 !important; 28 | // } 29 | } 30 | 31 | &[data-theme-mode="dark"] { 32 | --polarity-base-accent: #fff; 33 | --asri-theme-accent-customized: #50f555; 34 | --b3-theme-primary: var(--polarity-base-accent); 35 | 36 | --b3-theme-background: #000; 37 | --b3-theme-surface: #1f1f22; 38 | 39 | --b3-theme-on-background: #dddddd; 40 | --b3-theme-on-surface: #dddddda2; 41 | 42 | .code-block, 43 | code, 44 | .config-account__center:not(.config-account__center--text) { 45 | box-shadow: 0 0 0 1px var(--b3-border-color-trans); 46 | } 47 | } 48 | 49 | :is(.layout, .b3-typography) { 50 | --b3-theme-primary: var(--b3-theme-accent); 51 | --b3-theme-primary-light: oklch(from var(--b3-theme-primary) l c h / 0.56); 52 | --b3-theme-primary-lighter: oklch(from var(--b3-theme-primary) l c h / 0.38); 53 | --b3-theme-primary-lightest: oklch(from var(--b3-theme-primary) l c h / 0.2); 54 | } 55 | 56 | .protyle-title__input, 57 | [data-type="NodeHeading"], 58 | :where(h1, h2, h3, h4, h5, h6) { 59 | color: var(--b3-theme-primary); 60 | } 61 | 62 | .layout__dockl + .layout__resize--lr::after { 63 | background-color: var(--b3-border-color); 64 | } 65 | 66 | .config__panel { 67 | .b3-tab-bar, 68 | .item__side { 69 | border-right: 1px solid var(--b3-border-color); 70 | } 71 | } 72 | 73 | .layout__dockl, 74 | .dock, 75 | .config__panel :is(.b3-tab-bar, .item__side), 76 | .config-account { 77 | --b3-theme-surface: var(--b3-theme-background); 78 | } 79 | 80 | body:not(.asri-tfp) { 81 | .protyle .protyle-breadcrumb { 82 | box-shadow: 0 -1px 0 0 var(--b3-border-color) inset; 83 | } 84 | } 85 | 86 | // @supports (color: oklch(from #00f l clamp(0, c, 0.2) calc(h + 0))) { 87 | // :is(.layout, .b3-typography) { 88 | // --heading-clr-primary-base: #50f555; 89 | // --hchs: 45; // heading color hue shift. [0, 60] 90 | 91 | // @for $i from 1 through 6 { 92 | // --heading-clr-primary-h#{$i}: oklch( 93 | // from var(--heading-clr-primary-base) 94 | // 0.8 95 | // clamp(0, c, 2) 96 | // calc(h + var(--hchs) * #{$i - 1}) 97 | // ); 98 | // } 99 | // } 100 | 101 | // @for $i from 1 through 6 { 102 | // $lv: ":is(.h#{$i}, h#{$i})"; 103 | 104 | // #{$lv} { 105 | // color: var(--heading-clr-primary-h#{$i}); 106 | 107 | // --b3-theme-primary: var(--heading-clr-primary-h#{$i}); 108 | // } 109 | // } 110 | // } 111 | } 112 | 113 | #barWorkspace, 114 | #message, 115 | .b3-button--outline:hover, 116 | .b3-dialog__action .b3-button--text, 117 | #transactionError + .b3-dialog__action button:last-child, 118 | #configBazaarReadme .item__side .b3-button:not(.b3-button--progress):hover, 119 | .protyle-breadcrumb__icon:hover, 120 | .protyle-breadcrumb__item, 121 | .config-account__info .b3-button, 122 | .b3-menu, 123 | .b3-switch, 124 | .b3-button--outline, 125 | .protyle-breadcrumb__icon { 126 | // [data-asri-palette="polarity"][data-theme-mode="light"] & { 127 | // --b3-theme-primary: var(--polarity-base-accent); 128 | // --b3-theme-on-primary: var(--b3-theme-on-background); 129 | // } 130 | 131 | [data-asri-palette="polarity"][data-theme-mode="dark"] & { 132 | --b3-theme-primary: var(--polarity-base-accent); 133 | --b3-theme-on-primary: #000; 134 | } 135 | } 136 | 137 | // .b3-button--outline, 138 | // .protyle-breadcrumb__icon { 139 | // [data-asri-palette="polarity"][data-theme-mode="light"] & { 140 | // --b3-theme-primary: var(--b3-theme-accent); 141 | // } 142 | // } 143 | -------------------------------------------------------------------------------- /styles/palettes/prst-palette-stellula.scss: -------------------------------------------------------------------------------- 1 | [data-asri-palette="stellula"] { 2 | body { 3 | --b3-scroll-color-hover: var(--b3-theme-primary-lighter); 4 | --b3-scroll-color-track: var(--b3-theme-background-light); 5 | } 6 | 7 | &[data-theme-mode="light"] { 8 | --stellula-base-accent: #7ed5db; 9 | --asri-theme-accent-customized: var(--stellula-base-accent); 10 | --b3-theme-primary: #48b2ba; 11 | --b3-theme-accent: #3ea2a9; 12 | 13 | // --b3-theme-background: #fdf6f0; 14 | --b3-theme-surface: #e0ece8; 15 | 16 | --b3-theme-on-background: #424074; 17 | --b3-theme-on-surface: #373379a2; 18 | 19 | .layout__center 20 | :not(.av__views) 21 | > .layout-tab-bar 22 | .item:not(.item--readonly, .item--full.item--focus):hover, 23 | .layout__center :not(.av__views) > .layout-tab-bar .item--focus { 24 | background-color: #7ed5db8e; 25 | } 26 | 27 | [data-type="wnd"]:not(.layout__wnd--active) 28 | :not(.av__views) 29 | > .layout-tab-bar 30 | .item--focus { 31 | background-color: #7ed5db52 !important; 32 | } 33 | } 34 | 35 | &[data-theme-mode="dark"] { 36 | // --stellula-base-accent: #FC8B60; 37 | --stellula-base-accent: #6cc3c9; 38 | --asri-theme-accent-customized: var(--stellula-base-accent); 39 | --b3-theme-primary: var(--stellula-base-accent); 40 | 41 | --b3-theme-surface: #313842; 42 | --b3-theme-background: #232227; 43 | 44 | --b3-theme-on-background: #e6cfbc; 45 | --b3-theme-on-surface: #e6cfbca2; 46 | } 47 | 48 | .protyle-title__input, 49 | [data-type="NodeHeading"], 50 | // .b3-dialog__header, 51 | :where(h1, h2, h3, h4, h5, h6) { 52 | color: var(--b3-theme-primary); 53 | } 54 | } 55 | 56 | #barWorkspace, 57 | #message, 58 | .b3-button--outline:hover, 59 | .b3-dialog__action .b3-button--text, 60 | #transactionError + .b3-dialog__action button:last-child, 61 | #configBazaarReadme .item__side .b3-button:not(.b3-button--progress):hover, 62 | .protyle-breadcrumb__icon:hover, 63 | .protyle-breadcrumb__item, 64 | .config-account__info .b3-button, 65 | .b3-menu, 66 | .b3-switch, 67 | .b3-button--outline, 68 | .protyle-breadcrumb__icon { 69 | [data-asri-palette="stellula"][data-theme-mode="light"] & { 70 | --b3-theme-primary: var(--stellula-base-accent); 71 | --b3-theme-on-primary: var(--b3-theme-on-background); 72 | } 73 | 74 | [data-asri-palette="stellula"][data-theme-mode="dark"] & { 75 | --b3-theme-primary: #4fb1b8; 76 | // --b3-theme-on-primary: #fff; 77 | } 78 | } 79 | 80 | .b3-button--outline, 81 | .protyle-breadcrumb__icon { 82 | [data-asri-palette="stellula"][data-theme-mode="light"] & { 83 | --b3-theme-primary: var(--b3-theme-accent); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /styles/palettes/prst-palette-zerith.scss: -------------------------------------------------------------------------------- 1 | [data-asri-palette="zerith"] { 2 | &[data-theme-mode="light"] { 3 | --zerith-base-accent: #cfea00; 4 | --asri-theme-accent-customized: var(--zerith-base-accent); 5 | --b3-theme-primary: #8bc600; 6 | --b3-theme-accent: #73a400; 7 | 8 | --b3-theme-on-background: #265970; 9 | --b3-theme-on-surface: #265970a2; 10 | 11 | .layout__center :not(.av__views) > .layout-tab-bar .item:not(.item--readonly, .item--full.item--focus):hover, 12 | .layout__center :not(.av__views) > .layout-tab-bar .item--focus { 13 | background-color: #c7ea008e; 14 | } 15 | 16 | [data-type="wnd"]:not(.layout__wnd--active) :not(.av__views) > .layout-tab-bar .item--focus { 17 | background-color: #c7ea0052 !important; 18 | } 19 | 20 | // .protyle-title__input, 21 | // [data-type="NodeHeading"], 22 | // .b3-dialog__header, 23 | // :where(h1, h2, h3, h4, h5, h6) { 24 | // color: #21597394; 25 | // } 26 | } 27 | 28 | &[data-theme-mode="dark"] { 29 | --zerith-base-accent: #dbf611; 30 | --asri-theme-accent-customized: var(--zerith-base-accent); 31 | --b3-theme-primary: var(--zerith-base-accent); 32 | 33 | --b3-theme-on-background: #bfd1cc; 34 | --b3-theme-on-surface: #bfd1cca2; 35 | 36 | .protyle-title__input, 37 | [data-type="NodeHeading"], 38 | .b3-dialog__header, 39 | :where(h1, h2, h3, h4, h5, h6) { 40 | color: var(--b3-theme-primary); 41 | } 42 | } 43 | } 44 | 45 | #barWorkspace, 46 | #message, 47 | .b3-button--outline:hover, 48 | .b3-dialog__action .b3-button--text, 49 | #transactionError + .b3-dialog__action button:last-child, 50 | #configBazaarReadme .item__side .b3-button:not(.b3-button--progress):hover, 51 | .protyle-breadcrumb__icon:hover, 52 | .protyle-breadcrumb__item, 53 | .config-account__info .b3-button, 54 | .b3-menu, 55 | .b3-switch, 56 | .b3-button--outline, 57 | .protyle-breadcrumb__icon { 58 | [data-asri-palette="zerith"][data-theme-mode="light"] & { 59 | --b3-theme-primary: var(--zerith-base-accent); 60 | --b3-theme-on-primary: var(--b3-theme-on-background); 61 | } 62 | 63 | [data-asri-palette="zerith"][data-theme-mode="dark"] & { 64 | --b3-theme-primary: var(--zerith-base-accent); 65 | // --b3-theme-on-primary: #fffaf1; 66 | } 67 | } 68 | 69 | .b3-button--outline, 70 | .protyle-breadcrumb__icon { 71 | [data-asri-palette="zerith"][data-theme-mode="light"] & { 72 | --b3-theme-primary: var(--b3-theme-accent); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /styles/platforms/index.scss: -------------------------------------------------------------------------------- 1 | @use "linux"; 2 | @use "mobile"; 3 | @use "windows"; 4 | -------------------------------------------------------------------------------- /styles/platforms/linux.scss: -------------------------------------------------------------------------------- 1 | body.body-asri--linux:not(.body-asri--mobile, .body-asri--browser) { 2 | border: 1px solid #80808080; 3 | } 4 | -------------------------------------------------------------------------------- /styles/platforms/mobile.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | .body-asri--mobile { 4 | // -> js 5 | 6 | //编辑区 7 | .protyle-background { 8 | --cover-img-height: 200px; 9 | 10 | &__img { 11 | --bgimg-top-space: 92px; // 修复题头图跳动(实际为 90.5px, 这里给一点变动空间) 12 | --bgimg-scale: 1.1; 13 | } 14 | } 15 | 16 | .protyle-wysiwyg { 17 | padding-right: 24px !important; 18 | 19 | .bq, 20 | .protyle-wysiwyg blockquote, 21 | [data-node-id].render-node[data-type="NodeBlockQueryEmbed"] { 22 | padding: 4px 8px; 23 | } 24 | } 25 | 26 | .protyle-title .protyle-attr { 27 | height: -webkit-fill-available; // 修复文档标题属性显示不全 28 | } 29 | 30 | .b3-typography, 31 | .protyle-wysiwyg { 32 | font-family: var(--b3-font-family); 33 | } 34 | 35 | .protyle-scroll { 36 | opacity: 1; 37 | transform: none; 38 | z-index: 4; // 高于数据库表头 39 | 40 | &__bar { 41 | right: calc(8px - var(--b3-dynamicscroll-width) / 2); 42 | } 43 | } 44 | 45 | //菜单 46 | .b3-menu, 47 | .b3-menu__submenu { 48 | &, 49 | &::before { 50 | border-radius: 0 !important; 51 | } 52 | } 53 | .b3-menu--fullscreen, 54 | .b3-menu__submenu { 55 | box-shadow: none; 56 | outline: none; 57 | } 58 | 59 | .b3-menu__submenu .b3-menu__items { 60 | max-height: calc(100% - 10px); 61 | } 62 | 63 | border-radius: 0; 64 | 65 | #commonMenu { 66 | [id^="afwd"] .b3-menu__label { 67 | white-space: unset; 68 | } 69 | } 70 | 71 | .b3-menu__separator { 72 | height: 1px; 73 | margin: 16px; 74 | width: calc(100% - 32px); 75 | background-color: var(--b3-border-color-trans); 76 | } 77 | 78 | // 状态栏 79 | .status { 80 | padding: 8px; 81 | background-color: var(--b3-theme-surface); 82 | } 83 | 84 | //侧栏遮罩 85 | [style="transform: translateX(0px);"] ~ .side-mask { 86 | opacity: 0 !important; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /styles/platforms/windows.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | body.body--win32 { 4 | ::-webkit-scrollbar { 5 | background-color: transparent; 6 | 7 | &-thumb { 8 | -webkit-border-radius: 10px; 9 | background-clip: padding-box; 10 | border: 2px solid transparent; 11 | background-color: var(--b3-scroll-color); 12 | 13 | &:hover { 14 | background-color: var(--b3-scroll-color-hover); 15 | } 16 | } 17 | 18 | // &-track { 19 | // .b3-dialog & { 20 | // margin: 8px 0; 21 | // } 22 | 23 | // :where(.b3-menu, .protyle-hint, .protyle-util) & { 24 | // margin: 4px 0; 25 | // } 26 | // } 27 | } 28 | 29 | .b3-dialog ::-webkit-scrollbar-track { 30 | margin: 8px 0; 31 | } 32 | 33 | :where(.b3-menu, .protyle-hint, .protyle-util) ::-webkit-scrollbar-track { 34 | margin: 4px 0; 35 | } 36 | 37 | .protyle-content::-webkit-scrollbar-track { 38 | margin-bottom: 4px; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /styles/plugins/backlink-panel.scss: -------------------------------------------------------------------------------- 1 | .backlink-panel-document-bottom__area { 2 | margin-bottom: 42px; 3 | } 4 | -------------------------------------------------------------------------------- /styles/plugins/bookmark-plus.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | .custom-bookmark-group { 4 | .custom-bookmark-group-header { 5 | &.b3-list-item--focus { 6 | background-color: var(--b3-theme-surface) !important; 7 | 8 | .layout__dockl:not(.layout--float) & { 9 | background-color: var(--b3-theme-background) !important; 10 | 11 | @supports (color: oklch(from red clamp(0, (l * 0.5), 0.3) 0 h)) { 12 | background-color: oklch(from var(--b3-theme-surface) 0.91 c h) !important; 13 | 14 | @include darkmode-counterpart { 15 | background-color: oklch(from var(--b3-theme-surface) 0.41 c h) !important; 16 | } 17 | } 18 | } 19 | } 20 | 21 | .layout__dockl:not(.layout--float) & { 22 | background-color: var(--b3-theme-surface) !important; 23 | } 24 | 25 | .layout--float &:not(.b3-list-item--focus):hover, 26 | .layout__dockr &:not(.b3-list-item--focus):hover { 27 | background-color: var(--b3-theme-background) !important; 28 | } 29 | 30 | background-color: var(--b3-theme-background); 31 | position: sticky; 32 | top: 0; 33 | z-index: 1; 34 | } 35 | 36 | .b3-list-item__toggle.fn__hidden::before { 37 | left: unset !important; 38 | } 39 | } 40 | 41 | .custom-bookmark-body.card-view { 42 | .layout__dockr &, 43 | .layout--float & { 44 | background-color: unset !important; 45 | } 46 | 47 | .custom-bookmark-group { 48 | padding-top: 4px !important; 49 | padding-bottom: 4px !important; 50 | 51 | .layout__dockr &, 52 | .layout--float & { 53 | outline: 1px solid var(--b3-border-color-trans); 54 | outline-offset: -1px; 55 | } 56 | } 57 | 58 | .custom-bookmark-group-header { 59 | &.b3-list-item--focus { 60 | background-color: var(--b3-theme-background) !important; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /styles/plugins/custom-block.scss: -------------------------------------------------------------------------------- 1 | :root:not([plugin-custom-block-disabled~="list-view-map"]) .protyle-content [custom-block-list-view="map"] [data-node-id].li:before { 2 | opacity: 1; 3 | } 4 | 5 | .protyle-wysiwyg [custom-block-render][data-node-id] { 6 | border-radius: 0; 7 | } 8 | 9 | :root:not([plugin-custom-block-disabled~="list-view-table"]) .protyle-content [custom-block-list-view="table"] { 10 | [data-node-id] { 11 | border-radius: 0; 12 | 13 | &.li { 14 | outline-color: var(--b3-border-color) !important; 15 | outline-offset: -0.5px; 16 | } 17 | } 18 | 19 | > [data-node-id]:first-child { 20 | border-top-left-radius: 10px; 21 | border-top-right-radius: 10px; 22 | } 23 | 24 | > :nth-last-child(1 of [data-node-id]) { 25 | border-bottom-left-radius: 10px; 26 | border-bottom-right-radius: 10px; 27 | } 28 | } 29 | 30 | :root:not([plugin-custom-block-disabled~="list-view-board"]) .protyle-content [custom-block-list-view="board"][data-node-id].list > [data-node-id].li:nth-child(12n + 1) > [data-node-id]:not(.list) { 31 | outline: 1px solid var(--b3-border-color-trans); 32 | } 33 | -------------------------------------------------------------------------------- /styles/plugins/database-properties.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | @use "../protyle/utils" as *; 3 | 4 | .plugin-database-properties-wrapper { 5 | .b3-chip--middle { 6 | &::before { 7 | display: none; 8 | } 9 | 10 | border-radius: 4px; 11 | } 12 | 13 | // @for $i from 1 through 13 { 14 | // .b3-chip[style*="color: var(--b3-font-color#{$i})"] { 15 | // outline: .5px solid rgb(from var(--b3-font-color#{$i}) r g b / .3); 16 | // outline-offset: -.5px; 17 | // } 18 | // } 19 | 20 | @include database-assets-style; 21 | } 22 | -------------------------------------------------------------------------------- /styles/plugins/fake-breadcrumb.scss: -------------------------------------------------------------------------------- 1 | .og-fake-doc-breadcrumb-container { 2 | // 单行 3 | &.og-breadcrumb-oneline { 4 | align-self: center; 5 | display: flex; 6 | margin-right: 0; 7 | 8 | body.asri-tfp-progressive & { 9 | margin-right: 6px; 10 | } 11 | 12 | .protyle-breadcrumb__space { 13 | display: none; 14 | } 15 | 16 | // .og-fake-doc-breadcrumb-arrow-span:last-child>svg { 17 | // background-color: var(--b3-theme-primary); 18 | // } 19 | 20 | // +.protyle-breadcrumb__bar .protyle-breadcrumb__item:first-child>svg { 21 | // color: var(--b3-theme-primary); 22 | // } 23 | 24 | // &::after { 25 | // content: ''; 26 | // display: block; 27 | // min-width: 2px; 28 | // background-color: var(--b3-border-color-trans); 29 | // margin: 0 0.6em; 30 | // height: 1.5em; 31 | // align-self: center; 32 | // } 33 | } 34 | 35 | // 多行 36 | &.protyle-breadcrumb { 37 | border-bottom: 1px solid var(--b3-border-color-trans); 38 | // >.protyle-breadcrumb__bar { 39 | // border-bottom: 1px solid var(--b3-border-color-trans); 40 | // } 41 | } 42 | } 43 | 44 | .fullscreen > .og-fake-doc-breadcrumb-container.protyle-breadcrumb + .protyle-breadcrumb { 45 | padding-left: 10px; 46 | } 47 | -------------------------------------------------------------------------------- /styles/plugins/fold-list-preview.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mustakshif/Asri/c58f9fead3db3d65bff8f983f7659bfc8aec2c52/styles/plugins/fold-list-preview.css -------------------------------------------------------------------------------- /styles/plugins/index.scss: -------------------------------------------------------------------------------- 1 | @use "custom-block"; 2 | @use "siyuan-plugin-enhance"; 3 | @use "webview"; 4 | // @use 'bookmark-plus'; 5 | @use "fake-breadcrumb"; 6 | @use "database-properties"; 7 | @use "backlink-panel"; 8 | @use "media-player"; 9 | // @use 'typewriter'; // Typewriter plugin uses :has() selector, which affects performance 10 | -------------------------------------------------------------------------------- /styles/plugins/media-player.scss: -------------------------------------------------------------------------------- 1 | .asri-tfp .media-player-tab { 2 | top: 42px; 3 | } 4 | -------------------------------------------------------------------------------- /styles/plugins/siyuan-plugin-enhance.scss: -------------------------------------------------------------------------------- 1 | .enhanceProtyleBottomContainer { 2 | .ProtyleBottomContainer .backlinkArea { 3 | padding-bottom: 42px !important; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /styles/plugins/typewriter.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | 3 | // .protyle-wysiwyg [data-node-id]#plugin-focus-unique-id, 4 | // .protyle-wysiwyg [data-node-id][data-plugin-focus=true] { 5 | // animation: typewriter-focus .3s; 6 | // outline: 0px solid var(--b3-theme-primary-lighter); 7 | // } 8 | 9 | .protyle .protyle-wysiwyg [data-node-id]#plugin-focus-unique-id, 10 | .protyle .protyle-wysiwyg [data-node-id][data-plugin-focus="true"] { 11 | box-shadow: none; 12 | 13 | &::before { 14 | content: ""; 15 | position: absolute; 16 | height: calc(100% - 16px); 17 | width: 3px; 18 | border-radius: 99px; 19 | top: 8px; 20 | inset-inline-start: -5px; 21 | inset-inline-end: 0; 22 | bottom: 0; 23 | background-color: var(--b3-theme-primary); 24 | opacity: 1; 25 | animation: selected-block-indicator-appear 0.3s var(--asri-ease-spring-2); 26 | // animation-delay: .2s; 27 | transform-origin: top center; 28 | transition-property: opacity, transform; 29 | transition-duration: 0.3s; 30 | transition-timing-function: var(--asri-ease-spring-2); 31 | } 32 | 33 | &.protyle-wysiwyg--hl { 34 | &::before { 35 | opacity: 0; 36 | transform: scaleY(0.5); 37 | transition-duration: 0.3s; 38 | transition-timing-function: var(--asri-ease-spring-2); 39 | } 40 | } 41 | } 42 | 43 | .protyle .protyle-wysiwyg [data-node-id][data-plugin-focus="true"] { 44 | &::before { 45 | background-color: var(--b3-theme-primary-light); 46 | } 47 | } 48 | 49 | .protyle .protyle-wysiwyg [data-node-id].av .av__row .av__cell#plugin-focus-unique-id, 50 | .protyle .protyle-wysiwyg [data-node-id].av .av__row .av__cell[data-plugin-focus="true"] { 51 | box-shadow: none; 52 | } 53 | -------------------------------------------------------------------------------- /styles/plugins/webview.scss: -------------------------------------------------------------------------------- 1 | .layout__center .layout-tab-container .fn__flex-column > .protyle-breadcrumb { 2 | height: 42px; 3 | 4 | .address-field { 5 | margin: 8px 4px; 6 | } 7 | } 8 | 9 | body.body-asri--fullscreen, 10 | body.body-asri--browser { 11 | .fullscreen > { 12 | .protyle-breadcrumb, 13 | .block__icons { 14 | padding-left: 10px; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /styles/protyle/_utils.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * 弹性复选框 3 | */ 4 | @mixin bouncy-check-box($checked: false, $icon-size: 1.1em, $stroke-width: 0.1em) { 5 | &::before { 6 | content: "" !important; // fix https://github.com/mustakshif/Asri/issues/113 7 | position: absolute; 8 | // display: block !important; 9 | 10 | @if $checked==false { 11 | width: calc($icon-size - 0.05em); 12 | height: calc($icon-size - 0.05em); 13 | background-color: currentColor; 14 | mask-image: url('data:image/svg+xml,'); 15 | animation: uncheck 0.3s var(--asri-ease-elastic-in-out-3) forwards; // Animation adds mousewheel event listener to the block and the content in it, which is not good? This can be checked in the render tab of the inspector. 16 | } @else { 17 | width: $icon-size; 18 | height: $icon-size; 19 | background-color: var(--b3-theme-primary); 20 | mask-image: url('data:image/svg+xml, '); 21 | animation: check 0.3s var(--asri-ease-elastic-in-out-3) forwards; 22 | } 23 | 24 | @content; 25 | } 26 | } 27 | 28 | @keyframes check { 29 | 0%, 30 | 100% { 31 | transform: none; 32 | } 33 | 34 | 10% { 35 | transform: scale(1.2); 36 | } 37 | } 38 | 39 | @keyframes uncheck { 40 | 0%, 41 | 100% { 42 | transform: none; 43 | } 44 | 45 | 3% { 46 | transform: scale(1.2); 47 | } 48 | } 49 | 50 | /* 51 | * 数据库资源列样式 52 | */ 53 | @mixin database-assets-style($level: "non-chip") { 54 | $selector: if($level == "non-chip", ".av__celltext--url", ".b3-chip.av__celltext--url"); 55 | 56 | #{$selector} { 57 | // 资源列超链接或资源链接 58 | text-decoration: none; 59 | background-color: transparent; 60 | outline: 1px solid var(--b3-border-color-trans); 61 | // outline-offset: -1.5px; 62 | font-size: 100%; 63 | border-radius: 4px; 64 | 65 | &:hover { 66 | outline-color: var(--b3-theme-primary-lighter); 67 | color: var(--b3-theme-primary); 68 | 69 | &::before { 70 | background-color: var(--b3-theme-primary); 71 | } 72 | } 73 | 74 | &::before { 75 | content: ""; 76 | width: 1em; 77 | height: 1em; 78 | display: inline-block; 79 | background-color: var(--b3-theme-on-surface); 80 | mask-image: url(icons/icon-assets.svg); 81 | mask-size: 100% 100%; 82 | vertical-align: -2px; 83 | margin-right: 0.2em; 84 | } 85 | 86 | &[data-url^="http"]::before { 87 | mask-image: url(icons/icon-outerLink.svg); 88 | } 89 | 90 | &[data-url^="siyuan"]::before { 91 | mask-image: url(icons/icon-syLink.svg); 92 | } 93 | 94 | @content; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /styles/protyle/elements/doc-header.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | 3 | .protyle { 4 | // 题头图区域 5 | &-background { 6 | // 工具条 7 | .protyle-icons { 8 | width: fit-content; 9 | 10 | .protyle-icon { 11 | height: 30px; 12 | padding: 8px 6px; 13 | 14 | &--first { 15 | padding-left: 12px; 16 | } 17 | 18 | &--last { 19 | padding-right: 12px; 20 | } 21 | 22 | &--text { 23 | //调整题头图上下位置 24 | border-radius: 99px; 25 | padding-left: 12px; 26 | padding-right: 12px; 27 | } 28 | } 29 | } 30 | 31 | // 添加标签/表情/背景按钮 32 | &__ia > &__action { 33 | position: absolute; 34 | // bottom: 0; 35 | top: 0; 36 | padding: 2px 4px; 37 | width: fit-content; 38 | border-radius: 99px; 39 | 40 | transform: translate(var(--x, 0), var(--y, calc(56px - 100%))); 41 | 42 | mix-blend-mode: luminosity; 43 | // @include theme-variant-color(background-color, surface, 0.8); 44 | // @include theme-variant-color(color, on-background, 0.6); 45 | background-color: rgb(from var(--b3-theme-surface) r g b / 0.8); 46 | color: var(--b3-theme-on-surface); 47 | 48 | @include theme-variant-border($border: false); 49 | 50 | @include darkmode-counterpart { 51 | outline-offset: unset; 52 | } 53 | 54 | &:empty { 55 | padding: 0; 56 | } 57 | 58 | .b3-button--cancel { 59 | transition: 0.1s; 60 | 61 | &:hover { 62 | background-color: transparent; 63 | color: var(--b3-theme-on-background); 64 | } 65 | } 66 | } 67 | 68 | &__img.fn__none { 69 | + .protyle-background__ia { 70 | padding-top: 48px; 71 | 72 | .protyle-background__action { 73 | padding-left: 0; 74 | padding-right: 0; 75 | background-color: transparent; 76 | backdrop-filter: none; 77 | mix-blend-mode: normal; 78 | outline: none; 79 | } 80 | } 81 | } 82 | 83 | &__img { 84 | &.fn__none + .protyle-background__ia { 85 | .b3-chips:not(.fn__none) ~ .protyle-background__action { 86 | --y: 20px; 87 | --x: -12px; 88 | } 89 | 90 | .protyle-background__icon:not(.fn__none) ~ .protyle-background__action { 91 | --y: 108px; 92 | --x: 96px; 93 | } 94 | } 95 | 96 | &:not(.fn__none) + .protyle-background__ia { 97 | .protyle-background__action, 98 | .b3-chips:not(.fn__none) ~ .protyle-background__action { 99 | --y: calc(var(--cover-img-height, 30vh) - 100% - 12px); 100 | } 101 | 102 | .protyle-background__icon:not(.fn__none) ~ .protyle-background__action { 103 | --y: calc(var(--cover-img-height, 30vh) - 100% + 40px); 104 | } 105 | 106 | .protyle-background__icon:not(.fn__none) ~ .protyle-background__action { 107 | background-color: transparent; 108 | backdrop-filter: none; 109 | mix-blend-mode: normal; 110 | outline: none; 111 | } 112 | } 113 | } 114 | 115 | &__icon:not(.fn__none) ~ &__action { 116 | --x: 96px; 117 | } 118 | 119 | // 文档标签 120 | .b3-chips { 121 | // margin: 0 -4px; 122 | padding: 4px; 123 | margin-top: 24px; 124 | margin-bottom: -24px; 125 | position: relative; 126 | 127 | .b3-chip { 128 | background-color: var(--b3-theme-background); 129 | align-self: center; 130 | } 131 | 132 | .b3-chip--pointer { 133 | opacity: unset; 134 | } 135 | 136 | .b3-button { 137 | // mix-blend-mode: luminosity; 138 | opacity: 0; 139 | transition: opacity 0.2s, color 0.2s; 140 | 141 | &:hover { 142 | background-color: unset; 143 | color: var(--b3-theme-on-background); 144 | } 145 | } 146 | 147 | .b3-chip--secondary, 148 | .b3-chip--primary, 149 | .b3-chip--info, 150 | .b3-chip--success, 151 | .b3-chip--warning, 152 | .b3-chip--error, 153 | .b3-chip--pink { 154 | background-color: unset; 155 | font-weight: 500; 156 | color: var(--b3-theme-on-surface); 157 | outline: 0.12em solid var(--b3-border-color-trans); 158 | outline-offset: -0.12em; 159 | } 160 | } 161 | 162 | &__img { 163 | .protyle-icons { 164 | @include darkmode-counterpart { 165 | outline-offset: unset; 166 | } 167 | } 168 | } 169 | } 170 | 171 | &-top:hover { 172 | .protyle-background--enable .protyle-background__img .protyle-icons { 173 | opacity: 0; 174 | } 175 | 176 | .protyle-background--enable .protyle-background__img:hover .protyle-icons, 177 | .protyle-background--enable .protyle-background__icon:hover, 178 | .protyle-background--enable .protyle-background__action, 179 | .b3-chips .protyle-background__action .b3-button { 180 | opacity: 1; 181 | } 182 | } 183 | 184 | //文档标题 185 | &-title { 186 | &__input { 187 | font-weight: 600; 188 | font-size: 2.4em; 189 | color: var(--b3-theme-primary); 190 | // font-style: italic; 191 | // font-family: var(--b3-font-family-code); 192 | line-height: 1.4; 193 | padding-top: 8px; 194 | padding-bottom: 8px; 195 | 196 | &:empty:after { 197 | opacity: 0.6; 198 | } 199 | } 200 | 201 | &__icon { 202 | top: calc(2.4em * 1.4 / 2 + 8px) !important; // fix https://github.com/mustakshif/Asri/issues/45 203 | transform: scale(0.8); 204 | transform-origin: right center; 205 | transition-timing-function: var(--asri-ease-spring-5); 206 | transition-duration: 0.8s; 207 | } 208 | 209 | &:hover .protyle-title__icon { 210 | transform: none; 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /styles/protyle/elements/gutters.scss: -------------------------------------------------------------------------------- 1 | .protyle-gutters { 2 | > button { 3 | transform-origin: right center; 4 | 5 | &:hover { 6 | svg { 7 | color: var(--b3-theme-primary); 8 | } 9 | } 10 | } 11 | 12 | > button:not([data-type="NodeAttributeViewRow"], [data-type="NodeAttributeViewRowMenu"], :only-child) { 13 | animation: gutters-appear 0.5s var(--asri-ease-spring-3) forwards; 14 | opacity: 0; 15 | 16 | @for $i from 1 through 7 { 17 | &:nth-last-child(#{$i + 1}) { 18 | animation-delay: calc($i * 1s / (2 + $i) / 8); 19 | } 20 | } 21 | } 22 | 23 | > button:where([data-type="NodeAttributeViewRow"], [data-type="NodeAttributeViewRowMenu"], :only-child) { 24 | animation: gutters-appear-simple 0.5s var(--asri-ease-spring-3); 25 | } 26 | 27 | button[data-type="fold"] svg { 28 | transition: transform, 0.8s var(--asri-ease-spring-5); 29 | } 30 | 31 | @keyframes gutters-appear { 32 | from { 33 | // opacity: 0; 34 | transform: scale(0.5) translateX(4px); 35 | // filter: blur(12px); 36 | } 37 | 38 | to { 39 | opacity: 1; 40 | transform: none; 41 | // filter: none; 42 | } 43 | } 44 | 45 | @keyframes gutters-appear-simple { 46 | from { 47 | opacity: 0; 48 | transform: scale(0.5); 49 | // filter: blur(12px); 50 | } 51 | 52 | to { 53 | opacity: 1; 54 | transform: none; 55 | // filter: none; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /styles/protyle/elements/index.scss: -------------------------------------------------------------------------------- 1 | @use "gutters"; 2 | @use "tools"; 3 | @use "doc-header"; 4 | 5 | @forward "inline-elements"; // 内联元素相关 mixin 6 | @forward "block-elements"; // 块级元素相关 mixin 7 | -------------------------------------------------------------------------------- /styles/protyle/elements/tools.scss: -------------------------------------------------------------------------------- 1 | @use "../../base" as *; 2 | @use "../../components/utils.scss" as *; 3 | 4 | /* 页面小工具条 */ 5 | // 普通工具条、代码块工具条 6 | .protyle-icons, 7 | .protyle-action { 8 | border-radius: 99px; 9 | // transition: none; 10 | 11 | // &:hover { 12 | // transition: none; 13 | // opacity: 1 !important; 14 | // } 15 | 16 | .protyle-icon { 17 | @include theme-variant-color(background-color, surface, 0.8); 18 | @include theme-variant-color(color, on-background, 0.6); 19 | padding: 5px 6px; 20 | 21 | &:not(.protyle-icon--text, .protyle-icon--only):hover { 22 | color: var(--b3-theme-on-background); 23 | } 24 | 25 | &--first { 26 | border-radius: 99px 0 0 99px; 27 | padding-left: 10px; 28 | } 29 | 30 | &--last { 31 | border-radius: 0 99px 99px 0; 32 | padding-right: 10px; 33 | } 34 | 35 | &--only { 36 | // 正文图片 37 | border-radius: 99px; 38 | padding: 5px; 39 | transition: none; 40 | 41 | &:hover { 42 | color: var(--b3-theme-on-background); 43 | transition: none; 44 | } 45 | } 46 | } 47 | 48 | .protyle-icon.fn__none:first-child + .protyle-icon:last-child { 49 | border-radius: 99px; 50 | } 51 | 52 | // 只读模式下HTML块工具条 53 | } 54 | 55 | .protyle-icons { 56 | // 普通工具条(嵌入入块等) 57 | @include theme-variant-border($border: false); 58 | 59 | .protyle-wysiwyg [data-node-id].render-node:hover > & { 60 | opacity: 1; 61 | } 62 | } 63 | 64 | /* 字体样式 */ 65 | .protyle-font { 66 | .protyle-font__style { 67 | font-size: 14px; 68 | border-radius: 8px; 69 | 70 | &:hover { 71 | transform: scale(1.08); 72 | box-shadow: 0 0 0 1px inset var(--b3-border-color-trans); 73 | border-color: transparent; 74 | background-color: var(--b3-list-hover); 75 | } 76 | } 77 | 78 | .b3-button { 79 | @include button-action("normal"); 80 | box-shadow: none; 81 | } 82 | 83 | .fn__space--small { 84 | display: none; 85 | } 86 | } 87 | 88 | .color__square { 89 | // width: 20px; 90 | // height: 20px; 91 | box-shadow: 0 0 0 1px inset var(--b3-border-color-trans); 92 | border-radius: 8px; 93 | // line-height: 20px; 94 | // font-size: 14px; 95 | 96 | // &[data-type="backgroundColor"] { 97 | // box-shadow: 0 0 0 1px inset var(--b3-border-color-trans); 98 | // } 99 | 100 | &.color__square--current { 101 | box-shadow: 0 0 0 3px var(--b3-border-color-trans); 102 | } 103 | 104 | &:hover:not(.color__square--current) { 105 | // box-shadow: 0 0 0 1px inset var(--b3-border-color-trans); 106 | transform: scale(1.2); 107 | // font-weight: bold; 108 | } 109 | 110 | &:hover:not(.color__square--list):not(.color__square--current) { 111 | box-shadow: 0 0 0 1px inset var(--b3-border-color-trans); 112 | } 113 | 114 | .b3-menu__label & { 115 | width: 26px; 116 | height: 26px; 117 | font-weight: normal; 118 | 119 | &:hover { 120 | transform: none; 121 | } 122 | } 123 | 124 | .protyle-hint &:hover { 125 | transform: none; 126 | font-weight: normal; 127 | } 128 | } 129 | 130 | //文字格式工具条 131 | .protyle-toolbar { 132 | animation: protyle-toolbar-appear 0.6s var(--asri-ease-spring-3); 133 | border: none; 134 | border-radius: 40px; 135 | padding: 4px; 136 | // transform: translateY(-12px); 137 | background-color: var(--b3-theme-surface); 138 | transform-origin: 50% 150%; 139 | transition: none; 140 | @include menu-shadow($extra-shadow-dark: "0 0 0 1px inset #fff1, 0 1.5px 1px -1px #fff4 inset"); 141 | @include theme-variant-border($border: false); 142 | 143 | &__item { 144 | height: 30px; 145 | width: 30px; 146 | padding-top: 3px; 147 | border-radius: 20px; 148 | 149 | &:first-child, 150 | &:last-child { 151 | border-radius: 20px; 152 | } 153 | 154 | &:hover { 155 | // @include theme-variant-color(background-color, on-background, 0.1); 156 | background-color: rgb(from var(--b3-theme-on-background) r g b / 0.1); 157 | } 158 | 159 | &:not(.protyle-toolbar__item--current) { 160 | color: var(--b3-theme-on-surface); 161 | 162 | &:hover { 163 | color: var(--b3-theme-on-background); 164 | } 165 | } 166 | } 167 | 168 | &__divider { 169 | border-left: 1px solid var(--b3-border-color-trans); 170 | } 171 | 172 | @keyframes protyle-toolbar-appear { 173 | // 避免开始时元素大小计算错误导致定位超出视口 174 | 0%, 175 | 10% { 176 | opacity: 0; 177 | transform: none; 178 | } 179 | 180 | 10% { 181 | transform: scale(0.92); 182 | } 183 | 184 | 90%, 185 | 100% { 186 | opacity: 1; 187 | } 188 | 100% { 189 | transform: none; 190 | } 191 | } 192 | } 193 | 194 | // 块定位滚动条 195 | .protyle-scroll { 196 | opacity: 0; 197 | transform: scale(0.95, 0.9); 198 | transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), transform 0.2s cubic-bezier(0, 0, 0.2, 1); 199 | transition-delay: 1s; 200 | // pointer-events: none; 201 | 202 | // >* { 203 | // pointer-events: all; 204 | // } 205 | 206 | &:hover { 207 | opacity: 1; 208 | transform: none; 209 | transition-delay: 0s; 210 | } 211 | 212 | // 溢出显示 213 | > .protyle-scroll__bar { 214 | overflow: visible; 215 | } 216 | 217 | &__bar { 218 | top: calc(50% - 12px); 219 | } 220 | } 221 | 222 | .protyle-wysiwyg [data-node-id].li > .protyle-attr { 223 | line-height: unset !important; 224 | } 225 | -------------------------------------------------------------------------------- /styles/protyle/index.scss: -------------------------------------------------------------------------------- 1 | @use "editor"; 2 | @use "database"; 3 | @use "pdf-reader"; 4 | -------------------------------------------------------------------------------- /styles/protyle/pdf-reader.scss: -------------------------------------------------------------------------------- 1 | @use "../base" as *; 2 | @use "../components/utils" as *; 3 | 4 | .pdf__outer#outerContainer { 5 | &:not(.pdf__outer--dark) { 6 | @for $i from 1 through 7 { 7 | $pdf-highlight-background: map-get($theme-light, pdf-background#{$i}); 8 | --b3-pdf-background#{$i}: #{$pdf-highlight-background}; 9 | } 10 | } 11 | 12 | &.pdf__outer--dark { 13 | @for $i from 1 through 7 { 14 | $pdf-hightlight-background: map-get($theme-dark, pdf-background#{$i}); 15 | --b3-pdf-background#{$i}: #{$pdf-hightlight-background}; 16 | } 17 | } 18 | 19 | :root[data-theme-mode="light"] &:not(.pdf__outer--dark) .pdfViewer .textLayer { 20 | background-color: var(--b3-theme-background); 21 | } 22 | 23 | :root[data-theme-mode="dark"] &.pdf__outer--dark .pdfViewer .textLayer { 24 | background-color: var(--b3-theme-background); 25 | } 26 | 27 | #sidebarContainer { 28 | top: 42px; 29 | z-index: 1; 30 | background-color: var(--b3-theme-background); 31 | border-right: 1px solid var(--b3-border-color-trans); 32 | 33 | #sidebarResizer { 34 | right: -3px; 35 | 36 | &::after { 37 | background-color: transparent; 38 | } 39 | 40 | &:hover::after { 41 | background-color: var(--b3-theme-primary-light); 42 | } 43 | } 44 | 45 | #sidebarContent { 46 | .treeItem > a { 47 | line-height: 1.5; 48 | } 49 | } 50 | } 51 | 52 | .pdf__toolbar { 53 | #toolbarContainer { 54 | #toolbarViewer { 55 | height: 42px; 56 | align-items: center; 57 | border-bottom: 1px solid var(--b3-border-color-trans); 58 | 59 | .dropdownToolbarButton { 60 | margin: 4px 8px 4px 0; 61 | } 62 | } 63 | } 64 | } 65 | 66 | .findbar { 67 | padding: 4px 8px; 68 | right: 8px; 69 | overflow: visible !important; 70 | background-color: var(--b3-menu-background); 71 | width: fit-content; 72 | @include theme-variant-border; 73 | 74 | & > :is(input, button, label.b3-button) { 75 | margin-top: 4px; 76 | margin-bottom: 4px; 77 | } 78 | 79 | .b3-button { 80 | transition: background-color 0.2s; 81 | 82 | // 选中样式 83 | @include button-action("primary") { 84 | margin: 0; 85 | background-color: transparent; 86 | 87 | &:hover { 88 | box-shadow: none; 89 | } 90 | } 91 | 92 | // 默认样式 93 | &--outline { 94 | @include button-action("normal"); 95 | } 96 | } 97 | 98 | #findResultsCount { 99 | pointer-events: none; 100 | font-weight: 400; 101 | color: var(--b3-theme-on-surface); 102 | } 103 | } 104 | 105 | #viewerContainer { 106 | top: 42px; 107 | transition: none; 108 | 109 | body.body-status-shown & { 110 | padding-bottom: 42px; 111 | } 112 | 113 | // -> js 114 | } 115 | 116 | #dialogContainer { 117 | .dialog { 118 | padding: 16px; 119 | 120 | @include dialog-shadow; 121 | @include theme-variant-border; 122 | outline: 1px solid rgb(map-get($theme-light, on-background), 0.1); 123 | 124 | #documentPropertiesClose { 125 | @include button-action("primary") { 126 | // background-color: transparent; 127 | // transition: 0.2s; 128 | 129 | &:hover, 130 | &:active, 131 | &:focus { 132 | box-shadow: none; 133 | } 134 | } 135 | } 136 | } 137 | } 138 | 139 | .pdf__util { 140 | padding: 6px; 141 | @include theme-variant-border; 142 | 143 | .color__square { 144 | height: 20px; 145 | width: 20px; 146 | margin-right: 6px; 147 | border-radius: 6px; 148 | 149 | &:hover { 150 | box-shadow: 0 0 0 1px inset var(--b3-border-color-trans); 151 | transform: scale(1.2); 152 | } 153 | 154 | &:first-child { 155 | margin-left: 0; 156 | } 157 | 158 | &:last-child { 159 | margin-right: 0; 160 | } 161 | } 162 | 163 | .b3-menu__item { 164 | &:not(:hover) { 165 | background-color: transparent; 166 | } 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Asri", 3 | "author": "mustakshif", 4 | "url": "https://github.com/mustakshif/Asri", 5 | "version": "3.4.3", 6 | "displayName": { 7 | "default": "Asri", 8 | "zh_CN": "Asri", 9 | "en_US": "Asri" 10 | }, 11 | "description": { 12 | "default": "Crafting a space where visual distractions disappear and your thinking takes center stage — immersive, focused, and intuitively guided.", 13 | "zh_CN": "极富现代感的主题,以隐形设计构筑沉浸空间,为你带来专注、优雅、直觉驱动的笔记体验。" 14 | }, 15 | "readme": { 16 | "default": "README.md", 17 | "zh_CN": "README_zh_CN.md" 18 | }, 19 | "funding": { 20 | "openCollective": "", 21 | "patreon": "", 22 | "github": "", 23 | "custom": ["https://d7y10jvubi.feishu.cn/docx/R9AOd6OXSo9JThx2AH6cUo4tntf"] 24 | }, 25 | "modes": ["light", "dark"], 26 | "keywords": ["Asri", "Hadeeth"] 27 | } 28 | -------------------------------------------------------------------------------- /theme.scss: -------------------------------------------------------------------------------- 1 | @use "styles/theme"; 2 | @use "styles/main"; 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "module": "commonjs", 5 | "strict": true, 6 | "outDir": "./dist", 7 | "allowJs": true, 8 | "checkJs": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "typeRoots": ["node_modules/@types"] 13 | }, 14 | "include": ["src/**/*.ts"], 15 | "exclude": ["node_modules", "dist"] 16 | } 17 | -------------------------------------------------------------------------------- /webpack.config.cjs: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const TerserPlugin = require("terser-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: "./src/main.ts", 6 | // devtool: 'source-map', 7 | module: { 8 | rules: [ 9 | { 10 | test: /\.tsx?$/, 11 | use: "ts-loader", 12 | exclude: /\/node_modules/, 13 | }, 14 | // 添加处理.html文件的规则 15 | { 16 | test: /\.html$/, 17 | use: [ 18 | { 19 | loader: "html-loader", 20 | options: { 21 | minimize: true, // 可选,用于压缩HTML 22 | }, 23 | }, 24 | ], 25 | }, 26 | ], 27 | }, 28 | resolve: { 29 | extensions: [".tsx", ".ts", ".js"], 30 | }, 31 | output: { 32 | filename: "theme.js", // 输出文件名 33 | path: path.resolve(__dirname), // 输出目录 34 | }, 35 | mode: "production", 36 | // optimization: { 37 | // minimize: false, // 禁用压缩,调试时使用 38 | // }, 39 | externals: { 40 | "@electron/remote": "commonjs @electron/remote", // 将 @electron/remote 模块作为外部依赖 41 | }, 42 | // watch: true, 43 | watchOptions: { 44 | ignored: /node_modules/, 45 | aggregateTimeout: 500, 46 | poll: 3000, 47 | }, 48 | optimization: { 49 | minimize: true, 50 | minimizer: [ 51 | new TerserPlugin({ 52 | terserOptions: { 53 | compress: { 54 | drop_console: true, // 删除所有console.*函数调用 55 | drop_debugger: true, // 删除所有debugger语句 56 | pure_funcs: ["console.log"], // 删除特定函数调用] 57 | }, 58 | mangle: { 59 | keep_classnames: false, // 保留类名 60 | keep_fnames: false, // 保留函数名 61 | toplevel: true, // 混淆顶级作用域中的变量和函数名 62 | properties: { 63 | // 是否混淆对象属性名 64 | regex: /^(?!_)/, // 混淆不以下划线开头的属性名 65 | keep_quoted: true, // 保留引号中的属性名 66 | reserved: ["getCurrentWindow", "setWindowButtonPosition", "isFullScreen", "getAccentColor", "systemPreferences", "themeDark", "themeLight"], // 保留不混淆的属性名 67 | // regex: /^[a-z]*[A-Z][a-z0-9]*/ 68 | }, 69 | }, 70 | format: { 71 | // 输出选项 72 | comments: false, // 去除所有注释 73 | }, 74 | }, 75 | extractComments: false, 76 | parallel: true, // 启用多进程并行运行以提高构建速度 77 | }), 78 | ], 79 | }, 80 | // ... 81 | }; 82 | --------------------------------------------------------------------------------