├── .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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------