From 43083f199496133be251480cdff724c6165e1d76 Mon Sep 17 00:00:00 2001 From: c01dkit Date: Wed, 27 Nov 2024 21:36:39 +0800 Subject: [PATCH] Deployed f8676a8 with MkDocs version: 1.6.1 --- 404.html | 2 +- IDA/index.html | 36 +- autoconf/index.html | 38 +- c/index.html | 38 +- code-gracely/index.html | 38 +- cpp/index.html | 38 +- crawler/index.html | 38 +- docker/index.html | 38 +- dsa/array/index.html | 36 +- dsa/branch-and-bound-algo/index.html | 36 +- dsa/dynamic-algo/index.html | 36 +- dsa/graph-algo/index.html | 36 +- dsa/graph/index.html | 36 +- dsa/greedy-algo/index.html | 36 +- dsa/linkedlist/index.html | 36 +- dsa/queue/index.html | 36 +- dsa/stack/index.html | 36 +- dsa/tree/index.html | 36 +- envs/index.html | 38 +- fuzzing/index.html | 38 +- git/index.html | 38 +- go/index.html | 38 +- index.html | 2 +- interesting-articles/index.html | 36 +- investigations/index.html | 36 +- java/index.html | 36 +- latex/index.html | 38 +- linux-kernel/index.html | 38 +- linux-server/index.html | 38 +- llvm/index.html | 38 +- openssh/index.html | 38 +- picking-ups/index.html | 36 +- porting/index.html | 38 +- proxy/index.html | 38 +- pwn-college-cse365-spring2023/index.html | 38 +- python/index.html | 38 +- rca/index.html | 36 +- readings/index.html | 36 +- reverse-advanced/index.html | 36 +- reverse-basic/index.html | 38 +- sci-thoughts/index.html | 36 +- sentence-templates/index.html | 36 +- sitemap.xml | 88 +- sitemap.xml.gz | Bin 511 -> 510 bytes stylesheets/_config.scss | 42 + stylesheets/main.scss | 90 +++ stylesheets/main/_colors.scss | 155 ++++ stylesheets/main/_icons.scss | 37 + stylesheets/main/_resets.scss | 118 +++ stylesheets/main/_typeset.scss | 613 ++++++++++++++ stylesheets/main/components/_author.scss | 89 ++ stylesheets/main/components/_banner.scss | 68 ++ stylesheets/main/components/_base.scss | 182 +++++ stylesheets/main/components/_clipboard.scss | 102 +++ stylesheets/main/components/_code.scss | 35 + stylesheets/main/components/_consent.scss | 127 +++ stylesheets/main/components/_content.scss | 97 +++ stylesheets/main/components/_dialog.scss | 65 ++ stylesheets/main/components/_feedback.scss | 114 +++ stylesheets/main/components/_footer.scss | 201 +++++ stylesheets/main/components/_form.scss | 83 ++ stylesheets/main/components/_header.scss | 269 +++++++ stylesheets/main/components/_meta.scss | 67 ++ stylesheets/main/components/_nav.scss | 759 ++++++++++++++++++ stylesheets/main/components/_pagination.scss | 85 ++ stylesheets/main/components/_post.scss | 202 +++++ stylesheets/main/components/_progress.scss | 53 ++ stylesheets/main/components/_search.scss | 707 ++++++++++++++++ stylesheets/main/components/_select.scss | 115 +++ stylesheets/main/components/_sidebar.scss | 209 +++++ stylesheets/main/components/_source.scss | 214 +++++ stylesheets/main/components/_status.scss | 73 ++ stylesheets/main/components/_tabs.scss | 133 +++ stylesheets/main/components/_tag.scss | 105 +++ stylesheets/main/components/_tooltip.scss | 316 ++++++++ stylesheets/main/components/_tooltip2.scss | 210 +++++ stylesheets/main/components/_top.scss | 83 ++ stylesheets/main/components/_version.scss | 156 ++++ .../main/extensions/markdown/_admonition.scss | 195 +++++ .../main/extensions/markdown/_footnotes.scss | 146 ++++ .../main/extensions/markdown/_toc.scss | 92 +++ .../main/extensions/pymdownx/_arithmatex.scss | 62 ++ .../main/extensions/pymdownx/_critic.scss | 76 ++ .../main/extensions/pymdownx/_details.scss | 124 +++ .../main/extensions/pymdownx/_emoji.scss | 75 ++ .../main/extensions/pymdownx/_highlight.scss | 387 +++++++++ .../main/extensions/pymdownx/_keys.scss | 115 +++ .../main/extensions/pymdownx/_tabbed.scss | 417 ++++++++++ .../main/extensions/pymdownx/_tasklist.scss | 78 ++ stylesheets/main/integrations/_giscus.scss | 39 + stylesheets/main/integrations/_mermaid.scss | 67 ++ stylesheets/main/modifiers/_grid.scss | 129 +++ stylesheets/main/modifiers/_inline.scss | 48 ++ stylesheets/mystyle.css | 18 +- stylesheets/palette.scss | 40 + stylesheets/palette/_accent.scss | 61 ++ stylesheets/palette/_primary.scss | 203 +++++ stylesheets/palette/_scheme.scss | 148 ++++ stylesheets/utilities/_break.scss | 219 +++++ stylesheets/utilities/_convert.scss | 80 ++ tech-sslh/index.html | 38 +- try-chatgpt/index.html | 38 +- word-learning/index.html | 36 +- 103 files changed, 10357 insertions(+), 120 deletions(-) create mode 100644 stylesheets/_config.scss create mode 100644 stylesheets/main.scss create mode 100644 stylesheets/main/_colors.scss create mode 100644 stylesheets/main/_icons.scss create mode 100644 stylesheets/main/_resets.scss create mode 100644 stylesheets/main/_typeset.scss create mode 100644 stylesheets/main/components/_author.scss create mode 100644 stylesheets/main/components/_banner.scss create mode 100644 stylesheets/main/components/_base.scss create mode 100644 stylesheets/main/components/_clipboard.scss create mode 100644 stylesheets/main/components/_code.scss create mode 100644 stylesheets/main/components/_consent.scss create mode 100644 stylesheets/main/components/_content.scss create mode 100644 stylesheets/main/components/_dialog.scss create mode 100644 stylesheets/main/components/_feedback.scss create mode 100644 stylesheets/main/components/_footer.scss create mode 100644 stylesheets/main/components/_form.scss create mode 100644 stylesheets/main/components/_header.scss create mode 100644 stylesheets/main/components/_meta.scss create mode 100644 stylesheets/main/components/_nav.scss create mode 100644 stylesheets/main/components/_pagination.scss create mode 100644 stylesheets/main/components/_post.scss create mode 100644 stylesheets/main/components/_progress.scss create mode 100644 stylesheets/main/components/_search.scss create mode 100644 stylesheets/main/components/_select.scss create mode 100644 stylesheets/main/components/_sidebar.scss create mode 100644 stylesheets/main/components/_source.scss create mode 100644 stylesheets/main/components/_status.scss create mode 100644 stylesheets/main/components/_tabs.scss create mode 100644 stylesheets/main/components/_tag.scss create mode 100644 stylesheets/main/components/_tooltip.scss create mode 100644 stylesheets/main/components/_tooltip2.scss create mode 100644 stylesheets/main/components/_top.scss create mode 100644 stylesheets/main/components/_version.scss create mode 100644 stylesheets/main/extensions/markdown/_admonition.scss create mode 100644 stylesheets/main/extensions/markdown/_footnotes.scss create mode 100644 stylesheets/main/extensions/markdown/_toc.scss create mode 100644 stylesheets/main/extensions/pymdownx/_arithmatex.scss create mode 100644 stylesheets/main/extensions/pymdownx/_critic.scss create mode 100644 stylesheets/main/extensions/pymdownx/_details.scss create mode 100644 stylesheets/main/extensions/pymdownx/_emoji.scss create mode 100644 stylesheets/main/extensions/pymdownx/_highlight.scss create mode 100644 stylesheets/main/extensions/pymdownx/_keys.scss create mode 100644 stylesheets/main/extensions/pymdownx/_tabbed.scss create mode 100644 stylesheets/main/extensions/pymdownx/_tasklist.scss create mode 100644 stylesheets/main/integrations/_giscus.scss create mode 100644 stylesheets/main/integrations/_mermaid.scss create mode 100644 stylesheets/main/modifiers/_grid.scss create mode 100644 stylesheets/main/modifiers/_inline.scss create mode 100644 stylesheets/palette.scss create mode 100644 stylesheets/palette/_accent.scss create mode 100644 stylesheets/palette/_primary.scss create mode 100644 stylesheets/palette/_scheme.scss create mode 100644 stylesheets/utilities/_break.scss create mode 100644 stylesheets/utilities/_convert.scss diff --git a/404.html b/404.html index abbcc43..0efa18b 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ - c01dkit's tech blog

404 - Not found

\ No newline at end of file + c01dkit's tech blog

404 - Not found

\ No newline at end of file diff --git a/IDA/index.html b/IDA/index.html index 4f22141..c12c7ee 100644 --- a/IDA/index.html +++ b/IDA/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
跳转至

IDA使用

约 112 个字 预计阅读时间不到 1 分钟

反编译ARM raw binary

加载时选择Processor type,比如ARM Little-endian [ARM],随后根据实际加载情况设置ROM的起始地址和Input file地址。

raw binary的前四字节可能是初始sp值,随后四字节可能是初始pc值。按G并输入pc值,Alt+G设置T寄存器值为1(0表示ARM,1表示Thumb),然后选中pc及之后所有代码,按C进行MakeCode。

跳转至

IDA使用

约 112 个字 预计阅读时间不到 1 分钟

反编译ARM raw binary

加载时选择Processor type,比如ARM Little-endian [ARM],随后根据实际加载情况设置ROM的起始地址和Input file地址。

raw binary的前四字节可能是初始sp值,随后四字节可能是初始pc值。按G并输入pc值,Alt+G设置T寄存器值为1(0表示ARM,1表示Thumb),然后选中pc及之后所有代码,按C进行MakeCode。

\ No newline at end of file diff --git a/autoconf/index.html b/autoconf/index.html index 0fe7826..08d0fbb 100644 --- a/autoconf/index.html +++ b/autoconf/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
跳转至

autoconf学习笔记

约 292 个字 85 行代码 预计阅读时间 9 分钟

自己开发软件时,生成规范的configure等文件。可参考https://www.cnblogs.com/klausage/p/14163844.html

不分目录结构

编写Makefile.am文件,比如:

bin_PROGRAMS=helloworld
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

autoconf学习笔记

约 292 个字 85 行代码 预计阅读时间 9 分钟

自己开发软件时,生成规范的configure等文件。可参考https://www.cnblogs.com/klausage/p/14163844.html

不分目录结构

编写Makefile.am文件,比如:

bin_PROGRAMS=helloworld
 helloworld_SOURCES=helloworld.c
 
  • bin_PROGRAMS用于给项目起名,比如X,那么之后的X_SOURCES则用来指定使用的源文件

执行autoscan,生成configure.scan,并修改其中的AC_INIT、AM_INIT_AUTOMAKE,重命名文件为configure.ac,比如:

#                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
@@ -87,6 +87,40 @@
 AC_CONFIG_FILES([Makefile
                  src/Makefile])
 AC_OUTPUT
-

执行aclocal && autoheader && autoconf,生成aclocal.m4、config.h.in和configure

运行automake --add-missing,会根据Makefile.am生成Makefile.in

运行./configure生成makefile

运行make,基于makefile编译代码

\ No newline at end of file diff --git a/c/index.html b/c/index.html index 9e89f2b..c01d2c3 100644 --- a/c/index.html +++ b/c/index.html @@ -7,8 +7,42 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
跳转至

C语言

约 304 个字 2 行代码 预计阅读时间 1 分钟

根据结构体成员取结构体首地址

member_address - &(((TYPE *)0)->member);
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

C语言

约 304 个字 2 行代码 预计阅读时间 1 分钟

根据结构体成员取结构体首地址

member_address - &(((TYPE *)0)->member);
 

后半部分看似会解引用0地址而crash,但编译器会优化为直接计算member的offset。参见kernel代码常用的container_of。

动态链接库

编译动态链接库本身

使用gcc编译出动态链接库:

gcc <source C file> -shared -fPIC -o lib<source>.so
-

编译原项目时指定动态链接库

使用-l指定加载链接库,注意去掉库文件的lib开头和.so结尾。编译时,注意把库放在整个命令的结尾,否则可能提示库函数未定义。

比如gcc main.c -lcapstone不会报错,gcc -lcapstone main.c会提示报错。(假设这里main.c调用了capstone的库函数)

如果动态链接库不在默认的系统库中,可以添加-L来指定动态链接库的保存位置。

运行项目时加载动态链接库

即便编译成功,运行可能报错。搜索顺序为:

  1. 在编译时添加-Wl,-rpath=xxx来指定运行时所需的动态库文件
  2. 在环境变量LD_LIBRARY_PATH指定的目录中搜索
  3. /etc/ld.so.conf给出的目录中搜索
  4. 在默认的搜索路径/lib/lib64/usrlib/usrlib64等搜索
\ No newline at end of file diff --git a/code-gracely/index.html b/code-gracely/index.html index a89f848..f491702 100644 --- a/code-gracely/index.html +++ b/code-gracely/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
跳转至

优雅编程

约 1450 个字 28 行代码 预计阅读时间 8 分钟

程序变量

  • 最好在声明的同时初始化,尤其是避免仅初始化对象的部分成员
  • 尽可能地缩短变量的生命周期与跨度(即在使用前先初始化、多定义变量)
  • 不要在多个代码片段之间使用temp等不明意义的命名,这样会使不相关的代码看起来相关
  • 警惕隐式含义,比如某变量为正数时为整数类型,负数时表示隐含的“出错”(即隐含布尔类型),改用多个变量
  • 确保所有声明的变量都使用过
  • 变量名称要描述“什么”,而不是“怎么”,要具象
  • 变量名称长度在8-20个字母比较适宜
  • Total、Sum、Max、Record、String、Pointer等等限定词要加到名字最后
  • i、j、k等约定速成的变量名适用于简单的循环,不要用于任何简单循环的下标循环之外的任何场合
  • 多个复杂循环嵌套时,最好不要使用i、j、k
  • 为状态变量起一个比flag更好的名字,比如不使用statusFlag,而是characterType(更加具体描述是什么status)
  • 使用done、error、found、ok等为布尔变量赋值
  • 为布尔变量赋予隐含真假意义的名字,比如sourceFileAvailable、sourceFileFound
  • 使用肯定的布尔变量名,不要包含“not”之类的否定含义
  • 如果枚举类型变量不需要指定域,那么使用类似COLOR_xxx的前缀来指定类别会比较好

程序优化方法

优化需要通过大量测试来验证一致性、性能,因为并非所有优化都是正确或必要的。从重构程序执行流的角度来讲,优化并不是灵丹妙药,并在不同语言、不同编译器、不同环境、不同任务中表现出巨大的差异。以下的优化方法均仅供参考。

利用短路与哨兵

  • 将出现频率高的情况放在优先执行的位置
  • 循环中,搜索到目标后立即退出循环
  • 循环搜索时,也可以将搜索对象放在数组最后(额外空间),最后检查下标。(本质上是保证不会越界搜索,且保证循环一定正确结束)

优化计算效率

  • 程序执行前计算结果,通过常量保存、硬编码、文件保存的方法来避免重复计算
  • 尽量减少循环体内的计算工作,可以在之前计算完毕并保存,之后引用
  • 公共子表达式应当保存在变量里
  • 适当将乘法重写为加法、幂重写为乘法、整数代替浮点数、单精度代替双精度、移位操作代替乘除2、三角恒等式代替三角函数
  • 尽量减少数组维度与数组引用
  • 多重循环时,将循环次数少的放外层

使用低级语言重写代码

  1. 使用高级语言完成程序编写
  2. 进行测试,验证正确性
  3. 进行程序分析,确定热点代码
  4. 对热点代码使用低级语言改写

设计恰当的执行控制流

循环

  • 循环层数最好不要超过三层
  • 短循环可以多使用break、continue等控制,长循环尽量保证唯一出口
  • 循环附近不要写重复的代码(修改需要同步修改多处,不便维护)
  • for适合与“数量”有关的循环,且不要在内部修改下标;while适合与“条件”有关的循环
  • 循环体应当自成子程序,循环条件应当清晰易读
  • 多使用for循环,但不要把与循环无关的语句(比如初始化一个不用于循环的变量)放在循环头
  • 不要写空循环,将空循环改写成while循环
  • 如果一个循环可以做两件事情,把它们拆成两个循环,除非注明在性能上有所提高
  • 不要将循环下标作为结果返回。如果需要使用,可以在循环开始前定义新的变量,然后在循环内部对这一变量进行赋值

建表,以提高代码质量

用查表法替换繁琐的if-else判断

使用大量if-else的坏处:

  • 不易阅读
  • 代码重复度高,无意义
  • 对于复杂情况,容易漏条件
  • 判断逻辑硬编码在代码中,维护不便

使用查表法的好处:

  • 易读
  • 代码简洁且高效
  • 不会漏掉条件
  • 可以将表放在外部文件或者统一放在一起,便于维护;可以在不改变程序的情况下修正运行结果

用法:将要判断的各个参数作为表的维度,将判断结果作为表索引后的结果。

用索引表替换数据表

稀疏的数据表在存储对齐的情况下会浪费大量空间。与之相比,采用索引表可以降低空间浪费量(仍然会产生浪费)。为了进一步减少索引表空间,可以使用阶梯索引表,根据数据的范围(而不是具体的数据值)进行建索引,比如根据百分制成绩计算绩点,建立相应的data-to-key函数,放在数组中。

用结果表替换数学计算结果

考虑到系统函数的精确性,计算速度可能较慢。可以预先手动算出一些数据并建表,计算时直接查表即可,大大提高程序性能。

一些小小的语法特性

C

初始化数组,可以连续赋值

int arr[10] = {
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

优雅编程

约 1450 个字 28 行代码 预计阅读时间 8 分钟

程序变量

  • 最好在声明的同时初始化,尤其是避免仅初始化对象的部分成员
  • 尽可能地缩短变量的生命周期与跨度(即在使用前先初始化、多定义变量)
  • 不要在多个代码片段之间使用temp等不明意义的命名,这样会使不相关的代码看起来相关
  • 警惕隐式含义,比如某变量为正数时为整数类型,负数时表示隐含的“出错”(即隐含布尔类型),改用多个变量
  • 确保所有声明的变量都使用过
  • 变量名称要描述“什么”,而不是“怎么”,要具象
  • 变量名称长度在8-20个字母比较适宜
  • Total、Sum、Max、Record、String、Pointer等等限定词要加到名字最后
  • i、j、k等约定速成的变量名适用于简单的循环,不要用于任何简单循环的下标循环之外的任何场合
  • 多个复杂循环嵌套时,最好不要使用i、j、k
  • 为状态变量起一个比flag更好的名字,比如不使用statusFlag,而是characterType(更加具体描述是什么status)
  • 使用done、error、found、ok等为布尔变量赋值
  • 为布尔变量赋予隐含真假意义的名字,比如sourceFileAvailable、sourceFileFound
  • 使用肯定的布尔变量名,不要包含“not”之类的否定含义
  • 如果枚举类型变量不需要指定域,那么使用类似COLOR_xxx的前缀来指定类别会比较好

程序优化方法

优化需要通过大量测试来验证一致性、性能,因为并非所有优化都是正确或必要的。从重构程序执行流的角度来讲,优化并不是灵丹妙药,并在不同语言、不同编译器、不同环境、不同任务中表现出巨大的差异。以下的优化方法均仅供参考。

利用短路与哨兵

  • 将出现频率高的情况放在优先执行的位置
  • 循环中,搜索到目标后立即退出循环
  • 循环搜索时,也可以将搜索对象放在数组最后(额外空间),最后检查下标。(本质上是保证不会越界搜索,且保证循环一定正确结束)

优化计算效率

  • 程序执行前计算结果,通过常量保存、硬编码、文件保存的方法来避免重复计算
  • 尽量减少循环体内的计算工作,可以在之前计算完毕并保存,之后引用
  • 公共子表达式应当保存在变量里
  • 适当将乘法重写为加法、幂重写为乘法、整数代替浮点数、单精度代替双精度、移位操作代替乘除2、三角恒等式代替三角函数
  • 尽量减少数组维度与数组引用
  • 多重循环时,将循环次数少的放外层

使用低级语言重写代码

  1. 使用高级语言完成程序编写
  2. 进行测试,验证正确性
  3. 进行程序分析,确定热点代码
  4. 对热点代码使用低级语言改写

设计恰当的执行控制流

循环

  • 循环层数最好不要超过三层
  • 短循环可以多使用break、continue等控制,长循环尽量保证唯一出口
  • 循环附近不要写重复的代码(修改需要同步修改多处,不便维护)
  • for适合与“数量”有关的循环,且不要在内部修改下标;while适合与“条件”有关的循环
  • 循环体应当自成子程序,循环条件应当清晰易读
  • 多使用for循环,但不要把与循环无关的语句(比如初始化一个不用于循环的变量)放在循环头
  • 不要写空循环,将空循环改写成while循环
  • 如果一个循环可以做两件事情,把它们拆成两个循环,除非注明在性能上有所提高
  • 不要将循环下标作为结果返回。如果需要使用,可以在循环开始前定义新的变量,然后在循环内部对这一变量进行赋值

建表,以提高代码质量

用查表法替换繁琐的if-else判断

使用大量if-else的坏处:

  • 不易阅读
  • 代码重复度高,无意义
  • 对于复杂情况,容易漏条件
  • 判断逻辑硬编码在代码中,维护不便

使用查表法的好处:

  • 易读
  • 代码简洁且高效
  • 不会漏掉条件
  • 可以将表放在外部文件或者统一放在一起,便于维护;可以在不改变程序的情况下修正运行结果

用法:将要判断的各个参数作为表的维度,将判断结果作为表索引后的结果。

用索引表替换数据表

稀疏的数据表在存储对齐的情况下会浪费大量空间。与之相比,采用索引表可以降低空间浪费量(仍然会产生浪费)。为了进一步减少索引表空间,可以使用阶梯索引表,根据数据的范围(而不是具体的数据值)进行建索引,比如根据百分制成绩计算绩点,建立相应的data-to-key函数,放在数组中。

用结果表替换数学计算结果

考虑到系统函数的精确性,计算速度可能较慢。可以预先手动算出一些数据并建表,计算时直接查表即可,大大提高程序性能。

一些小小的语法特性

C

初始化数组,可以连续赋值

int arr[10] = {
     [0]       = 1,
     [1 ... 4] = 2,
     [5 ... 7] = 4,
@@ -33,6 +33,40 @@
 
     return 0;
 }
-
\ No newline at end of file diff --git a/cpp/index.html b/cpp/index.html index 68487c6..3bca6fe 100644 --- a/cpp/index.html +++ b/cpp/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
跳转至

C++

约 687 个字 136 行代码 预计阅读时间 16 分钟

STL

vector动态数组

vector 动态数组可以随机访问,其大小由系统自动管理。

#include<vector>
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

C++

约 687 个字 136 行代码 预计阅读时间 16 分钟

STL

vector动态数组

vector 动态数组可以随机访问,其大小由系统自动管理。

#include<vector>
 
 // 声明与初始化
 std::vector<int> vec1;
@@ -142,6 +142,40 @@
     Sample sample3(sample1);
     Sample sample4 = sample3;
 }
-

创建类的对象时,可以直接以类名 对象名的形式构建一个默认对象,或者类名 对象名(参数列表)构建一个带参数的对象,或者类名 对象名=已有对象类名 对象名(已有对象)来用拷贝构造函数。注意不要直接调用构造函数本身,它没有返回值。

封装

继承

多态

运算符重载

静态成员变量与静态成员函数

常量成员函数

this指针

对象的深拷贝与浅拷贝

模板编程

智能指针

C++11新特性

C++14新特性

C++17新特性

C++20新特性

\ No newline at end of file diff --git a/crawler/index.html b/crawler/index.html index 8a209d4..20d952b 100644 --- a/crawler/index.html +++ b/crawler/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

爬虫模板

约 142 个字 156 行代码 预计阅读时间 16 分钟

Scrapy

也可以看这里的介绍

加国内代理

针对个别网站锁ip,可以考虑整个代理

import base64
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

爬虫模板

约 142 个字 156 行代码 预计阅读时间 16 分钟

Scrapy

也可以看这里的介绍

加国内代理

针对个别网站锁ip,可以考虑整个代理

import base64
 username = 'xxxxx'
 passwd = 'xxxxx'
 proxy_ip = 'xxxx.kdltps.com'
@@ -159,6 +159,40 @@
     if p.poll() == 0:
         break
     p.wait()
-
\ No newline at end of file diff --git a/docker/index.html b/docker/index.html index 4b29d1f..fa0c923 100644 --- a/docker/index.html +++ b/docker/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Docker使用笔记

约 722 个字 11 行代码 预计阅读时间 4 分钟

安装docker

按照https://docs.docker.com/engine/install/ubuntu/的说明安装即可

也可以按curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh来安装。

设置docker使用镜像仓库

docker默认从官网拉取镜像,可能由于墙而拉不到。可以考虑使用阿里提供的镜像服务,参考https://zhuanlan.zhihu.com/p/347643668

考虑到国内似乎把docker镜像下架了,还是直接修改docker代理吧。

先创建目录mkdir /etc/systemd/system/docker.service.d,再创建文件/etc/systemd/system/docker.service.d/http-proxy.conf,再往里面添加代理:

[Service]
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

Docker使用笔记

约 722 个字 11 行代码 预计阅读时间 4 分钟

安装docker

按照https://docs.docker.com/engine/install/ubuntu/的说明安装即可

也可以按curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh来安装。

设置docker使用镜像仓库

docker默认从官网拉取镜像,可能由于墙而拉不到。可以考虑使用阿里提供的镜像服务,参考https://zhuanlan.zhihu.com/p/347643668

考虑到国内似乎把docker镜像下架了,还是直接修改docker代理吧。

先创建目录mkdir /etc/systemd/system/docker.service.d,再创建文件/etc/systemd/system/docker.service.d/http-proxy.conf,再往里面添加代理:

[Service]
 Environment="HTTP_PROXY=http://proxy.example.com:80/"
 Environment="HTTPS_PROXY=http://proxy.example.com:80/"
 Environment="NO_PROXY=localhost,127.0.0.0/8,docker-registry.somecorporation.com" #可选。如果使用本地镜像仓库。
@@ -18,6 +18,40 @@
 sudo systemctl restart docker
 

还有一种做法,适用于已经使用过一段时间的docker,关闭docker后mv原来的/var/lib/docker到新目录(比如/data/docker)然后再ln -s /data/docker /var/lib/docker建立软链接。

从镜像创建容器并挂载目录

会在容器中创建目录,映射宿主机目录。宿主机的目录和容器目录内容是一样的,修改一方,另一方随之改变

docker run -it --name=<container_name> --user=<user_id>:<group_id> --hostname=xxxx --workdir=xxxx  -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro --mount type=bind,source=<宿主机目录>,target=<容器目录> <镜像名>:<tag> /bin/bash
 

以上命令可以完成对指定镜像创建一个比较完备的容器,指定了容器名称、用户名称和组别、主机名、用户工作目录,并挂载了主机的一些目录。指定passwd和group文件的只读挂载可以避免–user使用用户(组)id进行新建容器时引发的找不到用户名和组名的问题。并且避免了默认root用户导致的主机端无法访问容器新建文件的问题。

注意这样创建的用户没有root权限。如果需要,则不使用user参数,但存在容器创建文件是root,宿主机无法修改的问题。

一个不太聪明的解决方法是user_id设成root的0,group_id设成普通用户,然后在容器里给root的.bashrc加一行umask 0002。就是说让用户组也能修改文件了。

一些其他的办法:docker exec -u好像可以指定启动容器时的用户,不知道有什么用,可以试试;或者root进去以后把普通用户加到sudoers里

新容器初始化

apt-get update更新一下list,然后才能使用apt-get下载其他包。一些常用的包:apt-get install build-essential

退出初次创建的容器

连按Ctrl+PCtrl+Q退出容器。否则简单退出后容器就stop了,下次exec的时候还要restart,甚至还会出现restart自动又stop的情况

进入已有的容器

docker exec -it <容器id> /bin/bash
-

可以Ctrl+D退出

\ No newline at end of file diff --git a/dsa/array/index.html b/dsa/array/index.html index 5472b8f..b25d761 100644 --- a/dsa/array/index.html +++ b/dsa/array/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

数组

约 2 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/branch-and-bound-algo/index.html b/dsa/branch-and-bound-algo/index.html index ad1c737..fafd667 100644 --- a/dsa/branch-and-bound-algo/index.html +++ b/dsa/branch-and-bound-algo/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

分支定界算法

约 6 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/dynamic-algo/index.html b/dsa/dynamic-algo/index.html index 5c9db50..2d9f5f2 100644 --- a/dsa/dynamic-algo/index.html +++ b/dsa/dynamic-algo/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

动态规划算法

约 6 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/graph-algo/index.html b/dsa/graph-algo/index.html index e750659..8907e10 100644 --- a/dsa/graph-algo/index.html +++ b/dsa/graph-algo/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

图算法

约 3 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/graph/index.html b/dsa/graph/index.html index 60a7bf5..54d96a2 100644 --- a/dsa/graph/index.html +++ b/dsa/graph/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

约 1 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/greedy-algo/index.html b/dsa/greedy-algo/index.html index 00a78d7..636feb7 100644 --- a/dsa/greedy-algo/index.html +++ b/dsa/greedy-algo/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

贪心算法

约 4 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/linkedlist/index.html b/dsa/linkedlist/index.html index 5b546e3..e12a84b 100644 --- a/dsa/linkedlist/index.html +++ b/dsa/linkedlist/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

链表

约 2 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/queue/index.html b/dsa/queue/index.html index 754518d..17e4c11 100644 --- a/dsa/queue/index.html +++ b/dsa/queue/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

队列

约 2 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/stack/index.html b/dsa/stack/index.html index 4c9737d..de80620 100644 --- a/dsa/stack/index.html +++ b/dsa/stack/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

约 1 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/dsa/tree/index.html b/dsa/tree/index.html index a6be6bd..14741a0 100644 --- a/dsa/tree/index.html +++ b/dsa/tree/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

约 1 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/envs/index.html b/envs/index.html index 86e1508..1bcef3e 100644 --- a/envs/index.html +++ b/envs/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

环境配置

约 593 个字 49 行代码 预计阅读时间 7 分钟

经常遇到新系统快速配置的环境(wsl、新服务器),特此总结一下

Ubuntu更新基本环境

sudo apt update
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

环境配置

约 593 个字 49 行代码 预计阅读时间 7 分钟

经常遇到新系统快速配置的环境(wsl、新服务器),特此总结一下

Ubuntu更新基本环境

sudo apt update
 sudo apt install curl build-essential gcc make -y
 

安装docker

按照https://docs.docker.com/engine/install/ubuntu/的说明安装即可

也可以按curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh来安装。

rust安装与更新

curl --proto '=https' --tlsv1.3 -sSf https://sh.rustup.rs | sh
 
rustup update
@@ -55,6 +55,40 @@
 apt install fonts-wqy-microhei # 安装一个就行
 fc-cache # 刷新缓存
 fc-list # 检查列表
-

参考文章

\ No newline at end of file diff --git a/fuzzing/index.html b/fuzzing/index.html index 1582673..4134087 100644 --- a/fuzzing/index.html +++ b/fuzzing/index.html @@ -7,8 +7,42 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

模糊测试基本介绍

约 1699 个字 2 行代码 预计阅读时间 6 分钟

覆盖率指引的模糊测试方法获得覆盖率的四种追踪方式1

  1. 使用编译器向基本块边缘插桩,可以准确地插桩并易于优化,但需要源码已知。
  2. 静态二进制重写,不需要源码,仍在研究,因为静态代码插桩准确性难以保证,并且优化能力有限。这些限制条件会影响代码率信息的质量与准确性,以及二进制重写的表现。
  3. 动态二进制插桩,不需要源码,可以容易、准确插入代码,但是动态翻译二进制的开销可能大到不能接受。
  4. 硬件辅助追踪,不需要源码,利用内置的硬件追踪扩展,在运行时直接获取控制执行流信息。

侵入式与非侵入式追踪2

Traces can be generated by trace code that is executed within tasks and/or interrupt service routines, just like application code that is executed on the same CPU. This is the most flexible approach, as both the content and the amount of trace information output can be defined in software. However, this tracing method comes with a significant drawback: It uses resources that are shared with the application software, hence tracing may significantly reduce the amount of memory available for the applications, increase the gross execution times of the applications and, in the case of real-time systems, impair functionality. This is why it is called intrusive tracing.

The most common case is that adding trace code is detrimental to the functionality of the applications in real-time systems because the resource requirements for intrusive tracing have been underestimated in the early stages of the project, such that tracing would eventually eat up resources that are required by the application. Therefore, the resource requirements for tracing must be properly considered throughout the whole development lifecycle. Removing trace code from real-time systems may also cause functional issues, typically just before the final production software release. This is the worst case, as trace information is no longer available in this scenario.

Non-intrusive tracing does not change the intrinsic timing behavior of the system under test. This approach simplifies the software development process a lot and requires dedicated hardware support for tracing. External trace probes connected to the target system, in conjunction with on-chip debug modules, capture code execution on instruction level, memory accesses and other events on the target processor. This approach is the best option when it comes to debugging the code execution down to the instruction level. The PCB design of the device under test must provide the connectors required by the external probe.

Another option for non-intrusive tracing is on-chip tracing, where most of the trace hardware is packed into the same chip that also contains the CPU that executes the application code. Non-intrusive tracing can, however, be restricted by limitations of the respective trace module or probe, such as buffer sizes, bus bandwidth or the size of an external probe.

Due to cost savings (no expensive third-party trace hardware required), reduced footprint (very small connectors instead of larger probe connectors), and limited trace bandwidth requirements, the on-chip tracing method is the preferred approach for generating the trace data required for in-depth timing analysis on task, runnable and ISR level. On-chip tracing is a suitable tracing method for devices under test with form factors very close to the final volume production devices.

针对网络协议的模糊测试

网络协议的特点是一般有明确的状态信息,相同的input在不同的状态可能得到不同的output。针对网络协议的模糊测试一般具有stateful的特点。这类模糊测试有几个难点: 1. 生成格式正确的信息,满足对特定状态的fuzz 2. 扩展到不同的协议中 3. 测试样例有效性,需要通过格式校验比如长度、协议认证、校验和等

AFLNET

首次提出针对有状态协议的灰盒模糊测试。AFLNET从响应信息中提取响应码来表示状态信息,并用响应码序列来推断协议实现的状态模型,并进一步使用这一模型来指导fuzz。

一些不足: 1. 状态表示能力:AFLNET要求响应信息中包含状态码,这并不是协议必须实现的。而且状态码表示能力有限,且可能产生冗余状态。 2. 测试效率:没有明确的信号反映待测程序是否处理完消息,因此设置固定的计时器来控制消息发送,时间窗口可能过小或过大。

STATEAFL

使用程序内存状态来表示服务状态,通过对被测程序插桩来收集状态信息并推测状态模型。在每一轮网络交互中,STATEAFL将程序变量值转储给分析队列,并进行post-execution的分析,来更新状态模型。

一些不足: 1. 面对和AFLNET相同的测试效率问题,而且因为后执行分析,产生额外的开销,会降低测试吞吐量。

NSFuzz

使用基于变量的状态表示方法推断状态模型来指导模糊测试,使用基于网络事件循环的同步机制来提高吞吐量。

启发式的变量判断方法:静态分析中只在事件循环代码中分辨状态变量,且关注被读与写、被赋予枚举类型的数据或是数据结构体里的整型成员。

表示状态的方法:使用两条语句维护shared_state数组,当状态变量值被更新时同步更新shared_state;当fuzzer在通信管道收到消息处理结果时,对这个数组进行hash,作为当前程序所处的state。

shared_state[hash(var_id) ^ cur_store_val] = 1;
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

模糊测试基本介绍

约 1699 个字 2 行代码 预计阅读时间 6 分钟

覆盖率指引的模糊测试方法获得覆盖率的四种追踪方式1

  1. 使用编译器向基本块边缘插桩,可以准确地插桩并易于优化,但需要源码已知。
  2. 静态二进制重写,不需要源码,仍在研究,因为静态代码插桩准确性难以保证,并且优化能力有限。这些限制条件会影响代码率信息的质量与准确性,以及二进制重写的表现。
  3. 动态二进制插桩,不需要源码,可以容易、准确插入代码,但是动态翻译二进制的开销可能大到不能接受。
  4. 硬件辅助追踪,不需要源码,利用内置的硬件追踪扩展,在运行时直接获取控制执行流信息。

侵入式与非侵入式追踪2

Traces can be generated by trace code that is executed within tasks and/or interrupt service routines, just like application code that is executed on the same CPU. This is the most flexible approach, as both the content and the amount of trace information output can be defined in software. However, this tracing method comes with a significant drawback: It uses resources that are shared with the application software, hence tracing may significantly reduce the amount of memory available for the applications, increase the gross execution times of the applications and, in the case of real-time systems, impair functionality. This is why it is called intrusive tracing.

The most common case is that adding trace code is detrimental to the functionality of the applications in real-time systems because the resource requirements for intrusive tracing have been underestimated in the early stages of the project, such that tracing would eventually eat up resources that are required by the application. Therefore, the resource requirements for tracing must be properly considered throughout the whole development lifecycle. Removing trace code from real-time systems may also cause functional issues, typically just before the final production software release. This is the worst case, as trace information is no longer available in this scenario.

Non-intrusive tracing does not change the intrinsic timing behavior of the system under test. This approach simplifies the software development process a lot and requires dedicated hardware support for tracing. External trace probes connected to the target system, in conjunction with on-chip debug modules, capture code execution on instruction level, memory accesses and other events on the target processor. This approach is the best option when it comes to debugging the code execution down to the instruction level. The PCB design of the device under test must provide the connectors required by the external probe.

Another option for non-intrusive tracing is on-chip tracing, where most of the trace hardware is packed into the same chip that also contains the CPU that executes the application code. Non-intrusive tracing can, however, be restricted by limitations of the respective trace module or probe, such as buffer sizes, bus bandwidth or the size of an external probe.

Due to cost savings (no expensive third-party trace hardware required), reduced footprint (very small connectors instead of larger probe connectors), and limited trace bandwidth requirements, the on-chip tracing method is the preferred approach for generating the trace data required for in-depth timing analysis on task, runnable and ISR level. On-chip tracing is a suitable tracing method for devices under test with form factors very close to the final volume production devices.

针对网络协议的模糊测试

网络协议的特点是一般有明确的状态信息,相同的input在不同的状态可能得到不同的output。针对网络协议的模糊测试一般具有stateful的特点。这类模糊测试有几个难点: 1. 生成格式正确的信息,满足对特定状态的fuzz 2. 扩展到不同的协议中 3. 测试样例有效性,需要通过格式校验比如长度、协议认证、校验和等

AFLNET

首次提出针对有状态协议的灰盒模糊测试。AFLNET从响应信息中提取响应码来表示状态信息,并用响应码序列来推断协议实现的状态模型,并进一步使用这一模型来指导fuzz。

一些不足: 1. 状态表示能力:AFLNET要求响应信息中包含状态码,这并不是协议必须实现的。而且状态码表示能力有限,且可能产生冗余状态。 2. 测试效率:没有明确的信号反映待测程序是否处理完消息,因此设置固定的计时器来控制消息发送,时间窗口可能过小或过大。

STATEAFL

使用程序内存状态来表示服务状态,通过对被测程序插桩来收集状态信息并推测状态模型。在每一轮网络交互中,STATEAFL将程序变量值转储给分析队列,并进行post-execution的分析,来更新状态模型。

一些不足: 1. 面对和AFLNET相同的测试效率问题,而且因为后执行分析,产生额外的开销,会降低测试吞吐量。

NSFuzz

使用基于变量的状态表示方法推断状态模型来指导模糊测试,使用基于网络事件循环的同步机制来提高吞吐量。

启发式的变量判断方法:静态分析中只在事件循环代码中分辨状态变量,且关注被读与写、被赋予枚举类型的数据或是数据结构体里的整型成员。

表示状态的方法:使用两条语句维护shared_state数组,当状态变量值被更新时同步更新shared_state;当fuzzer在通信管道收到消息处理结果时,对这个数组进行hash,作为当前程序所处的state。

shared_state[hash(var_id) ^ cur_store_val] = 1;
 shared_state[hash(var_id) ^ pre_store_val] = 0;
-

IoTHunter

提出多阶段信息生成方法来对IoT固件中的有状态网络协议进行fuzz。分为对已知状态的模糊测试与未知状态的探索。基于整数变异的方法改变包类型,并对包格式(比如长度、校验和)做检查等。

数据流指导的模糊测试

控制流指导的模糊测试侧重程序操作的执行顺序(比如分支与循环),数据流指导的模糊测试侧重变量如何定义与使用。变量的定义与使用位置可以不存在控制上的依赖关系。在模糊测试中,数据流主要使用动态污点分析(DTA)技术,即将目标程序的输入数据在定义处视为污点,并在运行时追踪它是如何被访问与使用的。

在实践中,难以做到准确的DTA,开销会很大。并且部分真实程序无法在应用DTA技术的情况下成功编译。因此大部分灰盒模糊测试不使用DTA,以期获得更高的吞吐量。

有一些轻量级的DTA代替方案(比如REDQUEUE、GREYONE),而基于控制流与数据流的模糊测试器的覆盖率指标还没有被完全探索。

DATAFLOW

源码

在程序执行时并行使用数据流分析来指导模糊测试,使用不精确的推断来降低开销并提高吞吐量。对数据流有效性进行了简单的评估,认为对大部分测试目标而言,数据流并不比控制流优越,但是在部分特定场景(比如控制流和语义解耦,如parser)下,数据流可能会有用。


\ No newline at end of file diff --git a/git/index.html b/git/index.html index 145b4a7..22967e7 100644 --- a/git/index.html +++ b/git/index.html @@ -7,9 +7,43 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Git学习笔记

约 1937 个字 3 行代码 预计阅读时间 7 分钟

将本地已有仓库推送至Github的新建仓库中

默认以下条件均成立:

  • 已在github上创建同名空仓库(不同名也行)
  • 已配置好ssh密钥
  • 已建立好本地仓库(git init +git add . +git commit -m "comments")
  • 本地仓库为clean状态(使用git status查看)
  1. 进入本地git仓库,使用git remote add origin git@github.com:xxx(仓库网站比如github提供的ssh地址)
  2. 使用git push -u origin master向远程仓库提交代码(后来听说github默认名改成main了?)

强制推送可以再加个--force参数

添加.gitignore文件以不追踪文件

初次向github提交代码前,在本地工作目录下创建.gitignore文件,里面直接写上不想追踪的文件名和文件夹名即可。(文件名不需要补全路径)

撤回add

使用git add .可以直接把当前目录都add进暂存区,对于不慎添加的内容可以使用git rm --cached <file>来撤回add。可以使用git rm -r --cached .来撤回git add . 。(使用git status可以查看暂存区,里面也有提示怎么撤回)

配置git账号并加入github项目

  1. 使用git config --global user.name "<yourname>"设置用户名
  2. 使用git config --global user.email "<email>"设置邮箱
  3. 使用ssh-keygen -t rsa -C "<comments>"生成密钥对,然后一路回车直到生成结束(也可以提示添加passwd phrase,这样的话如果使用ssh-add添加时会要求输入这个密码防止被别人滥用。注意相同的passwd phrase不会生成相同的密钥对)
  4. 在上一步过程中默认的路径(比如~/.ssh)找到id_rsa.pub文件,拷贝其全部内容
  5. 打开github,右上角头像,settings,左侧的SSH and GPG keys,然后给SSH添加这个公钥即可

ed25519似乎比默认的rsa更安全、计算更快、密钥更短,可以使用

有时需要指定密钥,比如不使用默认的密钥文件名。此时可以先eval $(ssh-agent -s)启用agent,然后ssh-add <private keyfile> 来添加密钥。ssh-add -l可以查看添加的密钥。

或者可以把密钥在~/.ssh/config文件里指定一下,就可以省去ssh-agent的操作,比如

Host github.com
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

Git学习笔记

约 1937 个字 3 行代码 预计阅读时间 7 分钟

将本地已有仓库推送至Github的新建仓库中

默认以下条件均成立:

  • 已在github上创建同名空仓库(不同名也行)
  • 已配置好ssh密钥
  • 已建立好本地仓库(git init +git add . +git commit -m "comments")
  • 本地仓库为clean状态(使用git status查看)
  1. 进入本地git仓库,使用git remote add origin git@github.com:xxx(仓库网站比如github提供的ssh地址)
  2. 使用git push -u origin master向远程仓库提交代码(后来听说github默认名改成main了?)

强制推送可以再加个--force参数

添加.gitignore文件以不追踪文件

初次向github提交代码前,在本地工作目录下创建.gitignore文件,里面直接写上不想追踪的文件名和文件夹名即可。(文件名不需要补全路径)

撤回add

使用git add .可以直接把当前目录都add进暂存区,对于不慎添加的内容可以使用git rm --cached <file>来撤回add。可以使用git rm -r --cached .来撤回git add . 。(使用git status可以查看暂存区,里面也有提示怎么撤回)

配置git账号并加入github项目

  1. 使用git config --global user.name "<yourname>"设置用户名
  2. 使用git config --global user.email "<email>"设置邮箱
  3. 使用ssh-keygen -t rsa -C "<comments>"生成密钥对,然后一路回车直到生成结束(也可以提示添加passwd phrase,这样的话如果使用ssh-add添加时会要求输入这个密码防止被别人滥用。注意相同的passwd phrase不会生成相同的密钥对)
  4. 在上一步过程中默认的路径(比如~/.ssh)找到id_rsa.pub文件,拷贝其全部内容
  5. 打开github,右上角头像,settings,左侧的SSH and GPG keys,然后给SSH添加这个公钥即可

ed25519似乎比默认的rsa更安全、计算更快、密钥更短,可以使用

有时需要指定密钥,比如不使用默认的密钥文件名。此时可以先eval $(ssh-agent -s)启用agent,然后ssh-add <private keyfile> 来添加密钥。ssh-add -l可以查看添加的密钥。

或者可以把密钥在~/.ssh/config文件里指定一下,就可以省去ssh-agent的操作,比如

Host github.com
     HostName github.com
     IdentityFile ~/.ssh/id_ed25519_user_github
-

有的时候git进行push到私仓时会出现卡机的问题,不确定是什么原因,如果remote repo使用的是git@xxx的url的话,可以试试改成https的链接;还不行的话可以试试git config的proxy,设置或清空。

放弃对文件的跟踪

与他人合作项目时,有时需要做一些本地适配,但是不想妨碍其他人,可以添加到.gitignore。但对于已经处于跟踪状态的文件来说后添进.gitignore是无效的。因此可以先将文件移出跟踪态,然后再加进.gitignore里。如下:git rm -r --cached <file/dir>其中-r表示递归。也可以加-n表示伪放弃跟踪(用于预览会放弃对哪些文件的追踪)

更换远程仓库

有的时候从官方仓库git clone下代码,本地拷贝一份、各种魔改并上传到自己的私仓。又由于windows、linux环境不同,想把原来的代码更新成自己的私仓,所以需要换一下远程仓库。

  1. 首先取消原来的远程分支跟踪git remote rm <remote repo name>
  2. 然后添加自己的仓库作为远程git remote add <remote repo name> <repo url>

好像也可以直接更换远程仓库:git remote set-url <remote repro name> <repo url>

这里的<remote repo name>是自己取的仓库名,之后的操作可以用它来指定对象。可以随便取,比如常见的origin。

子模块的下载

有的时候一个代码仓库拿其他仓库来当做子模块,在github上这些模块是图中的表示形式。git仓库里也会有.gitmodules文件来说明这些子模块。当clone主仓库时,这些子模块不会跟着下载下来。

初次部署时,在主仓库目录下里使用git submodule update --init --recursive来从.gitmodules字clone子模块。

如果子模块被别的开发者更新了,可以进到子模块中然后git pull

如果希望添加某个仓库作为子模块,使用git submodule add <repo url>来下载子模块并更新.gitmodules文件

自己的项目需要对其他项目进行修改

如果自己的项目用到别的项目,需要对其中一些代码进行修改,而不需要把在上传github时把整个项目全部放到自己的项目下,可以先用submodule添加子模块,然后直接修改代码,并在其项目下用git diff <commit id> > <file.patch>生成一个diff文件。把diff文件放到自己的项目里,再上传到github上。其中commit id是第三方项目的commit,也就是这个submodule下载时的commit id,可以通过git log找到。

如果直接用git diff > <file.patch>,会输出未加入暂存的修改和最近一次暂存/commit的diff文件。

其他人使用时,就先把第三方项目获取下来,然后git apply <file.patch>即可。撤回补丁使用git apply -R <file.patch>

不同版本多人合作与分支使用

最近在跑fuzzer,合作时有时需要切换不同的测试目标,每个测试目标都有自己的一大堆配套设置。大家都在主分支删改太麻烦而且很乱,所以需要针对每个测试目标设置不同的branch。

可以使用git branch -a查看所有分支。其中前面带*的是当前branch。

新建分支时使用 git checkout -b <branch name> 相当于先git branch <branch name> 创建了一个新的分支,然后git checkout <branch name>切换到那个分支。

在新的分支commit后,使用git push -u <remote repo name> <local branch name>:<remote branch name>可以将自己的这个分支推送到远程仓库。其中:

  • -u表示记住当前设定,之后在这一分支上push时,简单使用git push就会推送,不需要再敲这么长了。
  • origin 是之前git remote add origin 设定的远程主机名称,需要和实际设定一样。因为大家使用origin是在太普遍了,所以这里没有用<remote host name>来表示,意会即可。
  • local branch name和remote branch name一般情况是相同的。会在远程新建remote branch name

如果需要删除远程分支,可以简单地推送空分支:git push origin :<remote branch name>。这里本地分支名留空了。也可以使用专门的删除方式:git push origin --delete <remote branch name>

如果需要删除本地分支,使用git branch -d <local branch name>

合并分支时,先切换到需要接收改动的分支上,然后git merge <new branch name>,即可将new branch的改动更新到当前分支上。new branch的内容是不变的。

拉取远程分支到本地,而不影响本地分支:git fetch <remote repo name> <remote branch name>:<local branch name>会将远程仓库的分支保存在本地对应分支下。

可以用git fetch --all拉取所有远程分支,如果没有效果,注意检查remote.origin.fetch的设置:git config --get remote.origin.fetch,如果是+refs/heads/master:refs/remotes/origin/master,则表示只拉master分支。可以修改成拉取所有分支:git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

Github debug合集

某种东西真的神烦,科研需要下载的仓库代码经常莫名其妙下载不了,写的代码上传补上去,build个docker慢的要死,第三方包拉取不到……浪费很多时间在因为网络连接不了导致的各种bug上,有效科研时间白白被消耗,真的很xx。

Git clone报错gnutls_handshake() failed: The TLS connection was non-properly terminated.

一种做法是设置或者取消设置http.proxy和https.proxy

另一种做法是直接取消SSL校验,虽然粗暴了点:git config http.sslVerify false

\ No newline at end of file diff --git a/go/index.html b/go/index.html index 4af5112..486dd50 100644 --- a/go/index.html +++ b/go/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

go

约 66 个字 14 行代码 预计阅读时间 2 分钟

go环境配置

  1. https://go.dev/dl/下载Archive的包,解压缩(比如到~/.local),添加其中的bin目录到PATH路径
  2. 国内使用时设置代理
go env -w GO111MODULE=on
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

go

约 66 个字 14 行代码 预计阅读时间 2 分钟

go环境配置

  1. https://go.dev/dl/下载Archive的包,解压缩(比如到~/.local),添加其中的bin目录到PATH路径
  2. 国内使用时设置代理
go env -w GO111MODULE=on
 go env -w  GOPROXY=https://goproxy.cn
 

创建工程

工程保存在xxx/go/src/xxx下,并将GOPATH=xxx/go加到环境变量中

快速入门

package main
 import (
@@ -20,6 +20,40 @@
         fmt.Println(i)
     }
 }
-
\ No newline at end of file diff --git a/index.html b/index.html index 5427ac6..b01e169 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,6 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

首页

约 13 个字 预计阅读时间不到 1 分钟

欢迎,这里是 c01dkit 的技术笔记

\ No newline at end of file diff --git a/interesting-articles/index.html b/interesting-articles/index.html index 1419dca..741aef1 100644 --- a/interesting-articles/index.html +++ b/interesting-articles/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

有趣文章

约 179 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2021] Understanding and Detecting Disordered Error Handling with Precise Function Pairing 不正确的错误处理函数本身可能也会带来新的错误,尤其是在做一些前期清理工作时,执行顺序不正确会带来提权、崩溃与DoS。本文希望推断出预期的清理函数。
  2. [Usenix Security 2020] Actions Speak Louder than Words: Entity-Sensitive Privacy Policy and Data Flow Analysis with PoliCheck 考虑到数据流向的实体,对应用程序的隐私规范进行研究建模。
  3. [NDSS 2019] https://www.youtube.com/watch?v=dMndb0Xmr4k&t=1s&list=PLfUWWM-POgQs9SPvg-UA-TNG7UVEcdz8l&index=5 GitHub上由于一些不当操作可能会导致API密钥泄露。本文研究表明这种泄露非常猖獗,并且远没有解决问题。

有趣文章

约 179 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2021] Understanding and Detecting Disordered Error Handling with Precise Function Pairing 不正确的错误处理函数本身可能也会带来新的错误,尤其是在做一些前期清理工作时,执行顺序不正确会带来提权、崩溃与DoS。本文希望推断出预期的清理函数。
  2. [Usenix Security 2020] Actions Speak Louder than Words: Entity-Sensitive Privacy Policy and Data Flow Analysis with PoliCheck 考虑到数据流向的实体,对应用程序的隐私规范进行研究建模。
  3. [NDSS 2019] https://www.youtube.com/watch?v=dMndb0Xmr4k&t=1s&list=PLfUWWM-POgQs9SPvg-UA-TNG7UVEcdz8l&index=5 GitHub上由于一些不当操作可能会导致API密钥泄露。本文研究表明这种泄露非常猖獗,并且远没有解决问题。
\ No newline at end of file diff --git a/investigations/index.html b/investigations/index.html index e00193e..caa2ef8 100644 --- a/investigations/index.html +++ b/investigations/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

四大调查

约 311 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2022] “I feel invaded, annoyed, anxious and I may protect myself”: Individuals’ Feelings about Online Tracking and their Protective Behaviour across Gender and Country
  2. [Usenix Security 2022] “Like Lesbians Walking the Perimeter”: Experiences of U.S. LGBTQ+ Folks With Online Security, Safety, and Privacy Advice
  3. [Usenix Security 2022] How and Why People Use Virtual Private Networks
  4. [Usenix Security 2021] “It’s the Company, the Government, You and I”: User Perceptions of Responsibility for Smart Home Privacy and Security
  5. [Usenix Security 2021] “Shhh…be quiet!” Reducing the Unwanted Interruptions of Notification Permission Prompts on Chrome
  6. [Usenix Security 2021] Effect of Mood, Location, Trust, and Presence of Others on Video-Based Social Authentication
  7. [Usenix Security 2021] ‘Passwords Keep Me Safe’ – Understanding What Children Think about Passwords
  8. [Usenix Security 2021] “It’s stressful having all these phones”: Investigating Sex Workers’ Safety Goals, Risks, and Practices Online
  9. [Usenix Security 2021] “Now I’m a bit angry:” Individuals’ Awareness, Perception, and Responses to Data Breaches that Affected Them
  10. [Usenix Security 2020] “I am uncomfortable sharing what I can’t see”: Privacy Concerns of the Visually Impaired with Camera Based Assistive Applications
  11. [Usenix Security 2020 | Distingguished Paper Award] Understanding security mistakes developers make: Qualitative analysis from Build It, Break It, Fix It
  12. [Usenix Security 2020] An Observational Investigation of Reverse Engineers’ Processes
  13. [Usenix Security 2020] That Was Then, This Is Now: A Security Evaluation of Password Generation, Storage, and Autofill in Browser-Based Password Managers
  14. [NDSS 2022] An In-depth Analysis of Duplicated Linux Kernel Bug Reports
  15. [NDSS 2020] Are You Going to Answer That? Measuring User Responses to Anti-Robocall Application Indicators
  16. [NDSS 2019] Time Does Not Heal All Wounds: A Longitudinal Analysis of Security-Mechanism Support in Mobile Browsers
  17. [NDSS 2019] A First Look into the Facebook Advertising Ecosystem

四大调查

约 311 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2022] “I feel invaded, annoyed, anxious and I may protect myself”: Individuals’ Feelings about Online Tracking and their Protective Behaviour across Gender and Country
  2. [Usenix Security 2022] “Like Lesbians Walking the Perimeter”: Experiences of U.S. LGBTQ+ Folks With Online Security, Safety, and Privacy Advice
  3. [Usenix Security 2022] How and Why People Use Virtual Private Networks
  4. [Usenix Security 2021] “It’s the Company, the Government, You and I”: User Perceptions of Responsibility for Smart Home Privacy and Security
  5. [Usenix Security 2021] “Shhh…be quiet!” Reducing the Unwanted Interruptions of Notification Permission Prompts on Chrome
  6. [Usenix Security 2021] Effect of Mood, Location, Trust, and Presence of Others on Video-Based Social Authentication
  7. [Usenix Security 2021] ‘Passwords Keep Me Safe’ – Understanding What Children Think about Passwords
  8. [Usenix Security 2021] “It’s stressful having all these phones”: Investigating Sex Workers’ Safety Goals, Risks, and Practices Online
  9. [Usenix Security 2021] “Now I’m a bit angry:” Individuals’ Awareness, Perception, and Responses to Data Breaches that Affected Them
  10. [Usenix Security 2020] “I am uncomfortable sharing what I can’t see”: Privacy Concerns of the Visually Impaired with Camera Based Assistive Applications
  11. [Usenix Security 2020 | Distingguished Paper Award] Understanding security mistakes developers make: Qualitative analysis from Build It, Break It, Fix It
  12. [Usenix Security 2020] An Observational Investigation of Reverse Engineers’ Processes
  13. [Usenix Security 2020] That Was Then, This Is Now: A Security Evaluation of Password Generation, Storage, and Autofill in Browser-Based Password Managers
  14. [NDSS 2022] An In-depth Analysis of Duplicated Linux Kernel Bug Reports
  15. [NDSS 2020] Are You Going to Answer That? Measuring User Responses to Anti-Robocall Application Indicators
  16. [NDSS 2019] Time Does Not Heal All Wounds: A Longitudinal Analysis of Security-Mechanism Support in Mobile Browsers
  17. [NDSS 2019] A First Look into the Facebook Advertising Ecosystem
\ No newline at end of file diff --git a/java/index.html b/java/index.html index 25382b1..ef0c941 100644 --- a/java/index.html +++ b/java/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Java

约 108 个字 预计阅读时间不到 1 分钟

Java环境配置

https://www.oracle.com/java/technologies/downloads/下载对应系统的包。Linux选择Compressed Archive,解压缩以后配置下path;Windows可以用MSI Installer。对应的源码在lib/src.zip中。

Java源码架构理解

核心代码、主要功能在java.base/java目录下,其中包含了io、lang、util等多个关键模块。

Java里有哪些数据结构类型?如何实现的?

Java中常见的数据类型比如Set、Array、

Java

约 108 个字 预计阅读时间不到 1 分钟

Java环境配置

https://www.oracle.com/java/technologies/downloads/下载对应系统的包。Linux选择Compressed Archive,解压缩以后配置下path;Windows可以用MSI Installer。对应的源码在lib/src.zip中。

Java源码架构理解

核心代码、主要功能在java.base/java目录下,其中包含了io、lang、util等多个关键模块。

Java里有哪些数据结构类型?如何实现的?

Java中常见的数据类型比如Set、Array、

\ No newline at end of file diff --git a/latex/index.html b/latex/index.html index 00a9a44..9c9cc17 100644 --- a/latex/index.html +++ b/latex/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

latex基础

约 21 个字 190 行代码 预计阅读时间 19 分钟

推荐工具

使用Table Generator绘制表格

英文latex

\documentclass[conference,11pt]{IEEEtran}
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

latex基础

约 21 个字 190 行代码 预计阅读时间 19 分钟

推荐工具

使用Table Generator绘制表格

英文latex

\documentclass[conference,11pt]{IEEEtran}
 \IEEEoverridecommandlockouts
 % The preceding line is only needed to identify funding in the first footnote. If that is unneeded, please comment it out.
 \usepackage{cite}
@@ -196,6 +196,40 @@
 
 \end{sloppypar}
 \end{document}
-
\ No newline at end of file diff --git a/linux-kernel/index.html b/linux-kernel/index.html index 90134dc..eb90eb6 100644 --- a/linux-kernel/index.html +++ b/linux-kernel/index.html @@ -7,11 +7,45 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

linux内核学习

约 164 个字 2 行代码 预计阅读时间 1 分钟

编译

下载源码,可以从清华源pull一个:git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git。随后编译源码,参考CSDN教程。核心逻辑是下载好必要的依赖包(比如apt install build-essential flex bison libssl-dev libelf-dev)之后,在根目录运行make menuconfig,然后Exit保存文件,最后直接多线程编译make -j8

随后是漫长的编译过程。以Linux 6.12-rc6为例可能出现的报错:

证书问题:

make[3]: *** No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'.  Stop.
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

linux内核学习

约 164 个字 2 行代码 预计阅读时间 1 分钟

编译

下载源码,可以从清华源pull一个:git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git。随后编译源码,参考CSDN教程。核心逻辑是下载好必要的依赖包(比如apt install build-essential flex bison libssl-dev libelf-dev)之后,在根目录运行make menuconfig,然后Exit保存文件,最后直接多线程编译make -j8

随后是漫长的编译过程。以Linux 6.12-rc6为例可能出现的报错:

证书问题:

make[3]: *** No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'.  Stop.
 make[2]: *** [scripts/Makefile.build:478: certs] Error 2
 make[2]: *** Waiting for unfinished jobs....
 
参考StackOverflow上的解答,可以修改conf文件,也可以简单地运行

scripts/config --disable SYSTEM_TRUSTED_KEYS
 scripts/config --disable SYSTEM_REVOCATION_KEYS
-
重新make后一路回车。

\ No newline at end of file diff --git a/linux-server/index.html b/linux-server/index.html index e5dfd28..ad9804d 100644 --- a/linux-server/index.html +++ b/linux-server/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Ubuntu服务器运维

约 1216 个字 14 行代码 预计阅读时间 5 分钟

根据pid查询细节

sudo ls -lah /proc/<pid>
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

Ubuntu服务器运维

约 1216 个字 14 行代码 预计阅读时间 5 分钟

根据pid查询细节

sudo ls -lah /proc/<pid>
 
然后根据其中的cwd找到运行目录,exe找到运行程序

在终端向程序输入字节

# 输入raw bytes
 echo -e '\x31\x32' | program
 
@@ -75,6 +75,40 @@
 # multi-user.target组中的服务都将开机启动
 # 常用Target,1. multi-user.target-多用户命令行;2. graphical.target-图形界面模式
 WantedBy=[表示该服务所在的Target]
-
  • 启动systemctl start **
  • 关闭systemctl stop **
  • 重启systemctl restart **
  • 查看运行状态systemctl status **
    • Loaded行:配置文件的位置,是否设为开机启动;
    • Active行:表示正在运行;
    • Main行:主进程PID;
    • Status行:由应用本身提供的软件当前状态;
    • CGroup行:应用的所有子进程
    • 日志块:应用的日志
  • 设置开机自启systemctl enable ** enable命令相当于在目录里添加了一个符号链接。开机时,Systemd会执行/etc/systemd/system/目录里面的配置文件
  • 结束服务进程systemctl kill **
  • 查看配置文件systemctl cat **
  • 查看multi-user.target 包含的所有服务systemctl list-dependencies multi-user.target
  • 切换到另一个 target systemctl isolate graphical.target
  • 重新加载配置文件systemctl daemon-reload

定时服务

定时程序执行失败的原因是多样的,可能是因为定时服务没启动,需要systemctl restart cron.service,或者是cron服务坏掉了,先apt install cron --reinstall强制重新安装下,再重启服务,或者是安装了别的依赖库但是没有重启cron导致运行失败,试试/etc/init.d/cron restart

打开文件数

https://www.baeldung.com/linux/list-open-file-descriptors

Linux默认最多同时打开1024个文件,可以通过ulimit -n查看。fuzzing等要注意关闭文件描述符,否则可能导致服务器故障(比如ssh连不上)。/proc//fd里列出了pid锁打开的文件。

参考资料

  1. systemd相关资料
\ No newline at end of file diff --git a/llvm/index.html b/llvm/index.html index 03c7522..78fa2bd 100644 --- a/llvm/index.html +++ b/llvm/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

LLVM 学习

约 373 个字 44 行代码 预计阅读时间 6 分钟

环境配置

源码编译

首先在https://github.com/llvm/llvm-project/releases/ 下载心仪的llvm-project-xx.x.x.src.tar.xz,然后tar -xf llvm*解压缩后按如下进行编译:

cd llvm-project-*
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

LLVM 学习

约 373 个字 44 行代码 预计阅读时间 6 分钟

环境配置

源码编译

首先在https://github.com/llvm/llvm-project/releases/ 下载心仪的llvm-project-xx.x.x.src.tar.xz,然后tar -xf llvm*解压缩后按如下进行编译:

cd llvm-project-*
 mkdir build && cd build
 cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=On -DLLVM_TARGETS_TO_BUILD=host ../llvm
 cmake --build . -j8 # make -j8  根据实际情况选择多线程编译
@@ -218,6 +218,40 @@
 };
 
 #endif // PRINT_FUNCTION_NAMES_PASS_HPP
-
\ No newline at end of file diff --git a/openssh/index.html b/openssh/index.html index 9d7750e..ab4e382 100644 --- a/openssh/index.html +++ b/openssh/index.html @@ -7,11 +7,45 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

OpenSSH阅读笔记

约 164 个字 5 行代码 预计阅读时间 1 分钟

准备工作

(以下均在wsl的root用户) ubuntu系统,先预装下环境:

apt install build-essential autoconf zlib1g-dev libssl-dev
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

OpenSSH阅读笔记

约 164 个字 5 行代码 预计阅读时间 1 分钟

准备工作

(以下均在wsl的root用户) ubuntu系统,先预装下环境:

apt install build-essential autoconf zlib1g-dev libssl-dev
 

下载源码,直接从Github链接下载zip到本地解压,也可以用git clone:

git clone --depth 1 https://github.com/openssh/openssh-portable.git
 

为了防止之后make install出的文件覆盖系统自己的ssh,这里指定configure将之后编译出的文件放到项目的/output文件夹下。按readme的Building from git的方法,进入openssh所在目录后,运行:

autoreconf
 ./configure --prefix=`pwd`/output
 make
-

此时相关可执行文件已经编译完毕。为了进一步清晰显示,可以运行make install,则在当前目录的output文件夹下会生成对应的结构。

\ No newline at end of file diff --git a/picking-ups/index.html b/picking-ups/index.html index 0370b22..e064aa2 100644 --- a/picking-ups/index.html +++ b/picking-ups/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

文句摘录

约 1043 个字 预计阅读时间 3 分钟

Alligator in Vest: A Practical Failure-Diagnosis Framework via Arm Hardware Features (ISSTA 2023)

  • In light of these limitations, we propose Investigator, a practical failure diagnosis framework on Arm to fulfill the three requirements.

RR: A Fault Model for Efficient TEE Replication (NDSS 2023)

  • The correctness of replication protocols hinges on the property of quorum intersection.
  • In quorum-based protocols, this property is enforced by ensuring that any pair of quorums intersects in at least one replica that does not deviate from its prescribed behavior.

No Grammar, No Problem: Towards Fuzzing the Linux Kernel without System-Call Descriptions (NDSS 2023)

  • However, the process of manually collecting system-call traces, or writing descriptions is prone to human-error: the immediate coverage gains from descriptions and traces risk obscuring parts of the code that the fuzzer can no longer exercise meaningfully.

FUZZUSB: Hybrid Stateful Fuzzing of USB Gadget Stacks (Oakland 2022)

  • While the prevalence and versatility of USB have made our daily life convenient, it has also attracted attackers seeking to exploit vulnerabilities within the USB ecosystem.

Registered Report: DATAFLOW Towards a Data-Flow-Guided Fuzzer

  • Unfortunately, these more accurate analyses incur a high run-time penalty, impeding fuzzer throughput.
  • Unlike DTA, which strives for accuracy, we take inspiration from popular greybox fuzzers (e.g., AFL) and embrace some imprecision in an effort to reduce overhead and thus maximize fuzzing throughput.

A Survey on Adversarial Attacks for Malware Analysis

  • Adversarial attacks has now emerged as a serious concern, threatening to dismantle and undermine all the progress made in the machine learning domain.
  • The fear of evolving adversarial attack is growing among the cyber security research community and has provoked the everlasting war between adversarial attackers and defenders.

Survivalism: Systematic Analysis of Windows Malware Living-Off-The-Land (Oakland 2021)

  • Orthogonal to our research is the analysis and deobfuscation of script-based malware.

A Systematical and longitudinal study of evasive behaviors in windows malware (Computers & Security 2021)

  • Using our framework and taxonomy, we study the evasive behaviors adopted by 45,375 malware samples observed in the wild between 2010 and 201*
  • We harvest papers, reports, and blog posts from the security community estimating the influence of the public disclosure of evasive techniques on their adoption in the wild.

Structural Attack against Graph Based Android Malware Detection (CCS 2021)

  • Graph-based detection methods extract features from graphs and use these features to train classifiers for malware detection. By contrast, structural attacks directly modify the graph features and thus they are more intrinsic and effective.

Deep Learning for Android Malware Defenses: a Systematic Literature Review (ACM Survey 2021)

  • In front of the increasing difficulties of Android malware detection, it is non-trivial to build a robust and transparent detecting model or system only by traditional machine learning techniques.

Intriguing Properties of Adversarial ML Attacks in the Problem Space (Oakland 2020)

  • We shed light on the relationship between feature space and problem space, and we introduce the concept of side-effect features as the byproduct of the inverse feature-mapping problem. This enables us to define and prove necessary and sufficient conditions for the existence of problem-space attacks.

P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling (USENIX SECURITY 2020)

  • The inapplicability of fuzzers on MCU boils down to the lack of a platform where firmware can execute while taking inputs from fuzzers.
  • Although the register access patterns and the type identification method are purely empirical, we find that in practice they work fairly reliably and accurately across a wide range of peripheral devices. We attribute this practical and promising results to two factors.
  • The instantiation is on-demand and interleaved with the firmware fuzzing/testing process.

Toward the Analysis of Embedded Firmware through Automated Re-hosting (RAID 2019)

  • Unfortunately for security researchers, in stark contrast to the desktop and mobile ecosystems, market forces have not created any de facto standard for components, protocols, or software, hampering existing program analysis approaches, and making the understanding of each new device an independent, mostly manual, time-consuming effort.
  • In this work, we develop an approach to re-hosting that achieves all of them, and propose a proof-of-concept system, called PRETENDER, which is able to observe hardware-firmware interactions and create models of hardware peripherals automatically.
  • To deal with the plethora of software applications that need to be analyzed on desktop and mobile platforms, the security community has developed many techniques for enabling the scalable analysis of programs to find bugs and detect malice.
  • Dynamic approaches typically rely on virtualization to enable parallel, scalable analyses, while symbolic approaches rely on function summarization of the underlying operating system to minimize the code that they need to execute. In order to use any of these tools, the analyst must take the program out of its original execution environment, and provide a suitable analysis environment able to execute it. This is a process referred to as re-hosting.

REPT: Reverse Debugging of Failures in Deployed Software (USENIX SECURITY 2018)

  • Moreover, even though root cause diagnosis can help a developer determine the reasons behind a failure, developers often require a deeper understanding of the conditions and the state leading to a failure to fix a bug, which these systems do not provide.

What You Corrupt Is Not What You Crash: Challenges in Fuzzing Embedded Devices (NDSS 2018)

  • As a result, silent memory corruptions occur more frequently on embedded devices than on traditional computer systems, creating a significant challenge for conducting fuzzing sessions on embedded systems software.

Postmortem Program Analysis with Hardware-Enhanced Post-Crash Artifacts (USENIX SECURITY 2017)

  • As such, it is tedious and arduous for a software developer to plow through an execution trace to diagnose the root cause of a software failure.
  • Given that backward taint analysis mimics how a software developer (or security analyst) typically diagnoses the root cause of a program failure, this observation indicates that POMP has a great potential to reduce manual efforts in failure diagnosis.

POMP++: Facilitating Postmortem Program Diagnosis with Value-Set Analysis

  • Briefly speaking, postmortem program diagnosis is to identify the program statements pertaining to the crash, analyze these statements, and eventually figure out why a bad value was passed to the crash site.

A Survey on Software Fault Localization (TSE 2016)

  • Furthermore, manual fault localization relies heavily on the software developer’s experience, judgment, and intuition to identify and prioritize code that is likely to be faulty.

文句摘录

约 1043 个字 预计阅读时间 3 分钟

Alligator in Vest: A Practical Failure-Diagnosis Framework via Arm Hardware Features (ISSTA 2023)

  • In light of these limitations, we propose Investigator, a practical failure diagnosis framework on Arm to fulfill the three requirements.

RR: A Fault Model for Efficient TEE Replication (NDSS 2023)

  • The correctness of replication protocols hinges on the property of quorum intersection.
  • In quorum-based protocols, this property is enforced by ensuring that any pair of quorums intersects in at least one replica that does not deviate from its prescribed behavior.

No Grammar, No Problem: Towards Fuzzing the Linux Kernel without System-Call Descriptions (NDSS 2023)

  • However, the process of manually collecting system-call traces, or writing descriptions is prone to human-error: the immediate coverage gains from descriptions and traces risk obscuring parts of the code that the fuzzer can no longer exercise meaningfully.

FUZZUSB: Hybrid Stateful Fuzzing of USB Gadget Stacks (Oakland 2022)

  • While the prevalence and versatility of USB have made our daily life convenient, it has also attracted attackers seeking to exploit vulnerabilities within the USB ecosystem.

Registered Report: DATAFLOW Towards a Data-Flow-Guided Fuzzer

  • Unfortunately, these more accurate analyses incur a high run-time penalty, impeding fuzzer throughput.
  • Unlike DTA, which strives for accuracy, we take inspiration from popular greybox fuzzers (e.g., AFL) and embrace some imprecision in an effort to reduce overhead and thus maximize fuzzing throughput.

A Survey on Adversarial Attacks for Malware Analysis

  • Adversarial attacks has now emerged as a serious concern, threatening to dismantle and undermine all the progress made in the machine learning domain.
  • The fear of evolving adversarial attack is growing among the cyber security research community and has provoked the everlasting war between adversarial attackers and defenders.

Survivalism: Systematic Analysis of Windows Malware Living-Off-The-Land (Oakland 2021)

  • Orthogonal to our research is the analysis and deobfuscation of script-based malware.

A Systematical and longitudinal study of evasive behaviors in windows malware (Computers & Security 2021)

  • Using our framework and taxonomy, we study the evasive behaviors adopted by 45,375 malware samples observed in the wild between 2010 and 201*
  • We harvest papers, reports, and blog posts from the security community estimating the influence of the public disclosure of evasive techniques on their adoption in the wild.

Structural Attack against Graph Based Android Malware Detection (CCS 2021)

  • Graph-based detection methods extract features from graphs and use these features to train classifiers for malware detection. By contrast, structural attacks directly modify the graph features and thus they are more intrinsic and effective.

Deep Learning for Android Malware Defenses: a Systematic Literature Review (ACM Survey 2021)

  • In front of the increasing difficulties of Android malware detection, it is non-trivial to build a robust and transparent detecting model or system only by traditional machine learning techniques.

Intriguing Properties of Adversarial ML Attacks in the Problem Space (Oakland 2020)

  • We shed light on the relationship between feature space and problem space, and we introduce the concept of side-effect features as the byproduct of the inverse feature-mapping problem. This enables us to define and prove necessary and sufficient conditions for the existence of problem-space attacks.

P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling (USENIX SECURITY 2020)

  • The inapplicability of fuzzers on MCU boils down to the lack of a platform where firmware can execute while taking inputs from fuzzers.
  • Although the register access patterns and the type identification method are purely empirical, we find that in practice they work fairly reliably and accurately across a wide range of peripheral devices. We attribute this practical and promising results to two factors.
  • The instantiation is on-demand and interleaved with the firmware fuzzing/testing process.

Toward the Analysis of Embedded Firmware through Automated Re-hosting (RAID 2019)

  • Unfortunately for security researchers, in stark contrast to the desktop and mobile ecosystems, market forces have not created any de facto standard for components, protocols, or software, hampering existing program analysis approaches, and making the understanding of each new device an independent, mostly manual, time-consuming effort.
  • In this work, we develop an approach to re-hosting that achieves all of them, and propose a proof-of-concept system, called PRETENDER, which is able to observe hardware-firmware interactions and create models of hardware peripherals automatically.
  • To deal with the plethora of software applications that need to be analyzed on desktop and mobile platforms, the security community has developed many techniques for enabling the scalable analysis of programs to find bugs and detect malice.
  • Dynamic approaches typically rely on virtualization to enable parallel, scalable analyses, while symbolic approaches rely on function summarization of the underlying operating system to minimize the code that they need to execute. In order to use any of these tools, the analyst must take the program out of its original execution environment, and provide a suitable analysis environment able to execute it. This is a process referred to as re-hosting.

REPT: Reverse Debugging of Failures in Deployed Software (USENIX SECURITY 2018)

  • Moreover, even though root cause diagnosis can help a developer determine the reasons behind a failure, developers often require a deeper understanding of the conditions and the state leading to a failure to fix a bug, which these systems do not provide.

What You Corrupt Is Not What You Crash: Challenges in Fuzzing Embedded Devices (NDSS 2018)

  • As a result, silent memory corruptions occur more frequently on embedded devices than on traditional computer systems, creating a significant challenge for conducting fuzzing sessions on embedded systems software.

Postmortem Program Analysis with Hardware-Enhanced Post-Crash Artifacts (USENIX SECURITY 2017)

  • As such, it is tedious and arduous for a software developer to plow through an execution trace to diagnose the root cause of a software failure.
  • Given that backward taint analysis mimics how a software developer (or security analyst) typically diagnoses the root cause of a program failure, this observation indicates that POMP has a great potential to reduce manual efforts in failure diagnosis.

POMP++: Facilitating Postmortem Program Diagnosis with Value-Set Analysis

  • Briefly speaking, postmortem program diagnosis is to identify the program statements pertaining to the crash, analyze these statements, and eventually figure out why a bad value was passed to the crash site.

A Survey on Software Fault Localization (TSE 2016)

  • Furthermore, manual fault localization relies heavily on the software developer’s experience, judgment, and intuition to identify and prioritize code that is likely to be faulty.
\ No newline at end of file diff --git a/porting/index.html b/porting/index.html index b129692..75c6ed7 100644 --- a/porting/index.html +++ b/porting/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

折腾网站

约 1481 个字 49 行代码 预计阅读时间 10 分钟

端口复用方法

由于服务器安全设定,只对外开放一个22端口提供ssh连接。那么在此基础上如何提供http、https等多种服务?搜索了下可以根据流量特征用sslh简单转发一下数据包到不同的内部端口。

sslh:根据流量特征转发数据包

在root下apt install sslh后修改配置文件/etc/default/sslh

# Default options for sslh initscript
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

折腾网站

约 1481 个字 49 行代码 预计阅读时间 10 分钟

端口复用方法

由于服务器安全设定,只对外开放一个22端口提供ssh连接。那么在此基础上如何提供http、https等多种服务?搜索了下可以根据流量特征用sslh简单转发一下数据包到不同的内部端口。

sslh:根据流量特征转发数据包

在root下apt install sslh后修改配置文件/etc/default/sslh

# Default options for sslh initscript
 # sourced by /etc/init.d/sslh
 
 # binary to use: forked (sslh) or single-thread (sslh-select) version
@@ -116,6 +116,40 @@
 echo ${CERTBOT_DOMAIN} >> xxx.txt
 sleep 120
 exit 0
-

然后在两分钟之内,把xxx.txt里CERTBOT_VALIDATION对应的哈希值手动更新在DNS记录里即可。

此外,新找到一个可以方便地在web端配置新证书的网站:https://xiangyuecn.github.io/ACME-HTML-Web-Browser-Client/ACME-HTML-Web-Browser-Client.html

\ No newline at end of file diff --git a/proxy/index.html b/proxy/index.html index cf4f1a3..174c900 100644 --- a/proxy/index.html +++ b/proxy/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

代理转发

约 452 个字 9 行代码 预计阅读时间 2 分钟

多台电脑组局域网

可以使用zerotier,登录以后创建一个网络。然后需要组局域网的设备下载zerotier以后join上就行了。

可以参考这里这里,或者这里的一键脚本的链接配置私有planet,既能提高安全性,又能加快连接速度。简单来说,需要用ZeroTier官方代码编译自己的planet文件并替换掉zerotier客户端使用的planet,然后用ztncui这个后台管理界面配置zerotier的许可。

内网穿透

需要公网服务器,可以在阿里云租一个

一种方法是frp

另一种方法是ssh正向连接配合反向连接:

首先内网服务器开个screen运行ssh -R 127.0.0.1:1234:127.0.0.1:22 user@ip -p port连接到云服务器上。这样的话云服务器访问127.0.0.1:1234就相当于访问内网的127.0.0.1:22。然后需要连接内网的主机也开个screen运行ssh -L 127.0.0.1:2345:127.0.0.1:1234 user@ip -p port,这样的话该主机访问自己127.0.0.1:2345就相当于访问云服务器的127.0.0.1:1234。然后该主机再开一个终端,ssh user@127.0.0.1 -p 2345即可。

方便起见也可以在.ssh/config文件里用RemoteForward ip1:port1 ip2:port2LocalForward ip1:port1 ip2:port2来简化每次ssh连接都这么搞。

子网转发

希望将某端口收到的消息转发到其他主机的某一端口,可以试试socat,比如socat TCP4-LISTEN:4320,fork TCP4:10.244.55.25:80,可以把4320端口收到的TCP4数据包转发到子网10.244.55.25的80端口,配合zerotier可以实现内网对外开放端口。

即,vi /etc/systemd/system/socat.service编辑如下的socat,并systemctl enable socat.service启用开机启动,然后systemctl start socat.service。为了支持https连接,使用TCP-LISTEN/TCP。需要目标主机那边配置好ssl证书。

[Unit]
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

代理转发

约 452 个字 9 行代码 预计阅读时间 2 分钟

多台电脑组局域网

可以使用zerotier,登录以后创建一个网络。然后需要组局域网的设备下载zerotier以后join上就行了。

可以参考这里这里,或者这里的一键脚本的链接配置私有planet,既能提高安全性,又能加快连接速度。简单来说,需要用ZeroTier官方代码编译自己的planet文件并替换掉zerotier客户端使用的planet,然后用ztncui这个后台管理界面配置zerotier的许可。

内网穿透

需要公网服务器,可以在阿里云租一个

一种方法是frp

另一种方法是ssh正向连接配合反向连接:

首先内网服务器开个screen运行ssh -R 127.0.0.1:1234:127.0.0.1:22 user@ip -p port连接到云服务器上。这样的话云服务器访问127.0.0.1:1234就相当于访问内网的127.0.0.1:22。然后需要连接内网的主机也开个screen运行ssh -L 127.0.0.1:2345:127.0.0.1:1234 user@ip -p port,这样的话该主机访问自己127.0.0.1:2345就相当于访问云服务器的127.0.0.1:1234。然后该主机再开一个终端,ssh user@127.0.0.1 -p 2345即可。

方便起见也可以在.ssh/config文件里用RemoteForward ip1:port1 ip2:port2LocalForward ip1:port1 ip2:port2来简化每次ssh连接都这么搞。

子网转发

希望将某端口收到的消息转发到其他主机的某一端口,可以试试socat,比如socat TCP4-LISTEN:4320,fork TCP4:10.244.55.25:80,可以把4320端口收到的TCP4数据包转发到子网10.244.55.25的80端口,配合zerotier可以实现内网对外开放端口。

即,vi /etc/systemd/system/socat.service编辑如下的socat,并systemctl enable socat.service启用开机启动,然后systemctl start socat.service。为了支持https连接,使用TCP-LISTEN/TCP。需要目标主机那边配置好ssl证书。

[Unit]
 Description=port forward 4320
 
 [Service]
@@ -16,6 +16,40 @@
 
 [Install]
 WantedBy=multi-user.target
-
\ No newline at end of file diff --git a/pwn-college-cse365-spring2023/index.html b/pwn-college-cse365-spring2023/index.html index 54baf85..f4da974 100644 --- a/pwn-college-cse365-spring2023/index.html +++ b/pwn-college-cse365-spring2023/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

CSE 365 - Spring 2023

约 4823 个字 1287 行代码 预计阅读时间 145 分钟

在终端连接pwn-college时,先在网页端配置下公钥,然后ssh -i 私钥 hacker@dojo.pwn.college即可。网页端启动一个实例后,远程也会自动启动对应的环境。问题一般放在根目录的challenge文件夹下

Talking Web 学习笔记

请求第一行Request line:请求方法 URI 协议版本 CRLF

响应第一行Status line:协议版本 状态码 解释 CRLF

常见的请求方法:

  • GET:获取信息,如果URI是处理程序,则获取程序运行后的结果(而不是源码)
  • HEAD:和GET类似,但是response不返回body,一般用于测试资源是否存在、修改时间,获取资源元数据等
  • POST:提交额外的信息用于服务端处理

HTTP URL Scheme:scheme://host:port/path?query#fragment

  • scheme 访问资源的协议,比如http
  • host 持有资源的主机
  • port 提供服务的程序使用的端口
  • path 确定特定资源
  • query 资源可以利用的额外信息
  • fragment 客户端有关这一资源的信息(不会传给服务器?)

请求的资源含有一些特殊符号比如?,/,&,#等等时,使用%xx进行编码,其中xx是ASCII码。这种做法称为urlencoding

POST请求时,需要带上Content-Type

  • Content-Type: application/x-www-form-urlencoded
  • Content-Type: application/json

前者body里写a=xx,后者写{“a”:”xx”}。json可以构造更复杂的blob

RFC 1945 HTTP协议是无状态的,但是网络应用是有状态的。使用cookie来保持状态。

Assembly Crash Course 学习笔记

Building a Web Server 学习笔记

使用socket创建一个A-B的网络文件,然后使用bind将socket与具体的ip绑定。使用listen来被动侦听sockfd。使用accept接受外部连接。

使用TCP/IP进行网络通讯,服务器端的例子如:

// int socket(int domain, int type, int protocol)
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

CSE 365 - Spring 2023

约 4823 个字 1287 行代码 预计阅读时间 145 分钟

在终端连接pwn-college时,先在网页端配置下公钥,然后ssh -i 私钥 hacker@dojo.pwn.college即可。网页端启动一个实例后,远程也会自动启动对应的环境。问题一般放在根目录的challenge文件夹下

Talking Web 学习笔记

请求第一行Request line:请求方法 URI 协议版本 CRLF

响应第一行Status line:协议版本 状态码 解释 CRLF

常见的请求方法:

  • GET:获取信息,如果URI是处理程序,则获取程序运行后的结果(而不是源码)
  • HEAD:和GET类似,但是response不返回body,一般用于测试资源是否存在、修改时间,获取资源元数据等
  • POST:提交额外的信息用于服务端处理

HTTP URL Scheme:scheme://host:port/path?query#fragment

  • scheme 访问资源的协议,比如http
  • host 持有资源的主机
  • port 提供服务的程序使用的端口
  • path 确定特定资源
  • query 资源可以利用的额外信息
  • fragment 客户端有关这一资源的信息(不会传给服务器?)

请求的资源含有一些特殊符号比如?,/,&,#等等时,使用%xx进行编码,其中xx是ASCII码。这种做法称为urlencoding

POST请求时,需要带上Content-Type

  • Content-Type: application/x-www-form-urlencoded
  • Content-Type: application/json

前者body里写a=xx,后者写{“a”:”xx”}。json可以构造更复杂的blob

RFC 1945 HTTP协议是无状态的,但是网络应用是有状态的。使用cookie来保持状态。

Assembly Crash Course 学习笔记

Building a Web Server 学习笔记

使用socket创建一个A-B的网络文件,然后使用bind将socket与具体的ip绑定。使用listen来被动侦听sockfd。使用accept接受外部连接。

使用TCP/IP进行网络通讯,服务器端的例子如:

// int socket(int domain, int type, int protocol)
 socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)
 
 // int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen)
@@ -1353,6 +1353,40 @@
 #ªt®s­yºe»a½i¶hµ°o°b¾aºz¦r¬p®
 #然后把两个结果中字母排起来
 #utqsryeedabiihjooobaaezyrspq
-

总结

CSE 365还是属于比较入门的类型,打好基础!

\ No newline at end of file diff --git a/python/index.html b/python/index.html index d2400b0..84bea6e 100644 --- a/python/index.html +++ b/python/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

Python

约 786 个字 242 行代码 预计阅读时间 27 分钟

一些小点

  • 对字符串去除空白符时,用split()不加参数。注意split(’ ‘)按空格分隔时,如果存在连续的空格,那么结果里会有空字符串’‘。

获取未知对象的所有属性

obj.__dir__() 或者dir(obj)

  • 解析命令行参数:argparse
  • 日志输出:logging
  • 处理配置文件:yaml、json
  • 进度条输出:tqdm
  • python调用C库:ctypes.cdll.LoadLibrary
  • 设定计时信号:signal.alarm

参数解析:argparse

根据用户传参而执行不同的功能,又分多个层次。比如pip3命令,可以有pip3 install和pip3 freeze等等,对于每一个子解析又有进一步的参数,比如pip3 install –upgrade, pip3 install –force-reinstall等等。

import argparse
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

Python

约 786 个字 242 行代码 预计阅读时间 27 分钟

一些小点

  • 对字符串去除空白符时,用split()不加参数。注意split(’ ‘)按空格分隔时,如果存在连续的空格,那么结果里会有空字符串’‘。

获取未知对象的所有属性

obj.__dir__() 或者dir(obj)

  • 解析命令行参数:argparse
  • 日志输出:logging
  • 处理配置文件:yaml、json
  • 进度条输出:tqdm
  • python调用C库:ctypes.cdll.LoadLibrary
  • 设定计时信号:signal.alarm

参数解析:argparse

根据用户传参而执行不同的功能,又分多个层次。比如pip3命令,可以有pip3 install和pip3 freeze等等,对于每一个子解析又有进一步的参数,比如pip3 install –upgrade, pip3 install –force-reinstall等等。

import argparse
 
 def populate_parser(parser):
     parser.add_argument('input_file', type=str, help="Path to the file containing the mutated input to load")
@@ -239,6 +239,40 @@
 # 输出还原后的data字典
 print(restored_data)
 # {536879104: b'\x04\x05\x06\x07', 805306368: b'\x00\x01\x02\x03\x04'}
-

参考资料

\ No newline at end of file diff --git a/rca/index.html b/rca/index.html index 0bbf92d..db9f072 100644 --- a/rca/index.html +++ b/rca/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

根因分析

约 2291 个字 预计阅读时间 8 分钟

什么是根因分析? 根因分析(Root Cause Analysis)或者说缺陷定位(Fault Localization)是程序开发人员或安全分析人员在确认程序存在异常行为后,通过手动或自动的方法来定位异常行为的根本原因的过程。根因分析是程序安全分析流程中比较重要的一环。

为什么需要设计一些根因分析方法? 在当下各类自动化漏洞挖掘工具(比如各类fuzzer)的辅助下,每日发现的bug数量已经远超开发人员确认并修复的数量。设计一种自动化发现漏洞的工具并不难,难在如何根据这些工具报出的crash信息来准确地分析出漏洞的根本原因。对于大型程序而言,崩溃测试样例(crashing testcase)执行下来可能经历了几百万条汇编指令,手工确认稍微有点不现实了。因此需要设计一些(自动化)的根因分析工具。

怎么进行根因分析?目前有哪些工作? 最朴素而直观的思想就是消耗安全分析人员的精力,从程序的入口点(entry)或者崩溃点(crash site)出发,看看程序是怎么执行的,哪些元素(program entity)会导致最后的crash,然后再进行对应的修复。根据定位元素的粒度不同,根因分析可以定位到函数级(function level)、语句级(statement level)、汇编指令级(instruction level)。由于在汇编指令上进行分析可以更普适地适应多种编程语言、不需要获取源码,所以下文的讨论都是围绕汇编指令级展开。

目前一些自动化根因分析研究思路有:

  1. 基于程序谱的分析方法(Spectrum-based)。大概思路是不需要考虑汇编指令的语义信息,利用一些统计学的方法来分析哪些指令有问题。这类方法基于这样一个场景:假设我们有一大批相似的测试样例,其中有些会导致程序崩溃,有些不会,那么这两类测试样例的执行路径可能有不同的偏好。那么那些更倾向于在崩溃测试样例中执行的指令更有可能是root cause。
  2. 事后分析方法(Postmortem-based)。直译尸检分析,形象理解为从程序崩溃后留下的“尸体”开始分析。它假定程序崩溃后会产生一个coredump(核心转储)文件,包含了崩溃点的内存快照(memory snapshot),以及这个测试样例的执行路径(execution trace)。前者用于提供数据流信息(比如内存值、寄存器值),后者用于提供控制流信息(汇编指令执行与跳转)。在此基础上,结合一些逆向执行(reverse execution)和后向污点分析(backward taint analysis)的方法,定位可能的root cause。
  3. 基于模型的分析方法(Model-based)。这一类方法是近些年提出的,它通过定义语义相关的模型,利用机器学习或深度学习的思想,找到语义上导致崩溃的root cause。

这些研究思路都解决了什么问题?有什么独特的优点?存在哪些独有的不足? 基于程序谱的分析方法直观上似乎有点道理。它仅考虑汇编指令本身,而但仅仅从统计结果上去分析,可能并不能准确分析出逻辑上的root cause。这类方法一般会设计一种排名策略(ranking),对选择出的可疑指令进行top1-topn的排名,来试图提高准确性。这类方法一般需要根据一个崩溃样例以及和它相似的崩溃样例和非崩溃样例进行分析,因此时空开销都比较大。

事后分析方法相比程序谱分析方法考虑了指令语义,比如在逆向执行的时候会设计一些汇编指令handler,对于内存的分析也会更精确些。但污点分析方法毕竟存在过度污染(over-tainting)的问题,导致结果冗余比较严重。

基于模型的分析方法利用AI的优势,可以给出更有语义信息的root cause,在一定程度上帮助开发人员去分析。不过模型的训练依赖训练集的质量,并且受程序语义影响很大。在不同领域之间可能迁移性不是很好,比如没法处理一些特定的密码学函数。且为待测程序建立模型来描述其结构与行为是非常复杂、耗时的事情

现有的这些方法有没有什么普遍存在的问题? 在最后评估阶段(evaluation),一般先通过手工分析确定哪些汇编指令,如果方法输出的汇编指令集合里包含这些指令,那么就认为是发现了root cause。但自动化方法毕竟缺少人工参与,给出的结果一定是不准确的。现有的工作的一个主流思想在于“方法给出的集合可以包含无关指令,但不能缺少相关指令”,旨在提高召回率(recall)。因此往往给出与root cause不相关的指令。但实际上,在最后的修复端,如果给出不相关指令过多,那么仍然需要开发者去分析,依旧耗时耗力。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),9.43%希望root cause在分析结果的Top1,73.58%容许在Top5,15.09%容许在Top10。所以约98%的情况下需要在Top10内给出结果。就分析准确度与开发人员满意度而言,如果RCA工具准确度达90%,满意度几乎达到100%了。准确度低于20%时只有12%接受,如果满意度达50%、75%、90%,准确度需要分别达到50%、75%、85%(但是原文说90%)。

目前的绝大部分RCA分析的工作的输出是两类:ranked list和suspicious set。但两者都存在的问题是仅仅高亮了可能存在bug的元素,而缺乏一些rational的分析。

不同的分析粒度的优势

基于文件粒度的RCA工作(比如Scaffle)希望找到包含百万级同质代码库中哪些文件和crash有关。在此基础上让对应的工程师团队去处理bug,有利于大型组织管理。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),开发者对粒度的top3期望依次是方法级别、语句级别、基本块级别,不过对这三种粒度的倾向之间没有明显差异。而当时比较多的方法是语句级别的

分析时间开销

根据采用的策略不同,RCA之间的时间开销差异可能达两个数量级。(秒级-分钟级-小时级)。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),90%开发者接受1min以内的分析,不到9%开发者接受超过1h的分析。50%开发者大概在30min以内。

一些想法

  1. 什么是漏洞的根本原因?假如函数A内创建临时变量x并调用函数B(x),在B内引发crash,那么应该归咎为A没有处理x呢,还是B没有检查x呢?这是API实现的问题,还是API误用的问题?(开发者or用户)
  2. 对于某一个crash,如果开发人员进行了修复,那么这个修复能拿来当root cause吗?不同开发人员修复的风格可能不一样,修复也未必是完全的,root cause就是一个主观的问题了。

相关论文的一些发现(疑问)

  • “传统的SFL方法效果在Defects4J等部分数据集可能远优于DLFL方法,可能是基准实验的过拟合问题。”传统方法的过拟合指的是什么?DLFL为什么在基准测试集取得和别的数据集一样好的效果?传统方法在不同测试集的表现差异是方法的问题还是测试集的问题?(A Universal Data Augmentation Approach for Fault Localization, ICSE 2022)
  • 不同种类的FL方法在时间开销上数量级是不同的。测试的时候如果集成上较低数量级开销的方法,不会对运行时间有很大影响,但可以提升效率。不同种类FL方法相关性不高,可以考虑结合使用。(An Empirical Study of Fault Localization Families and Their Combinations, TSE 2021)
  • 调用栈做FL分析时,如果根因在栈上的话,40%是第一个栈帧,90%在前10个栈帧里。(Do stack traces help developers fix bugs? Mining Softw. Repositories, 2010)

参考文献

  • Scaffle: Bug Localization on Millions of Files, ISSTA 2020
  • Probabilistic reasoning in diagnosing causes of program failures, STVR 2016
  • Practitioners’ expectations on automated fault localization, ISSTA 2016

以上内容仅代表个人观点,不定期更新,欢迎讨论

根因分析

约 2291 个字 预计阅读时间 8 分钟

什么是根因分析? 根因分析(Root Cause Analysis)或者说缺陷定位(Fault Localization)是程序开发人员或安全分析人员在确认程序存在异常行为后,通过手动或自动的方法来定位异常行为的根本原因的过程。根因分析是程序安全分析流程中比较重要的一环。

为什么需要设计一些根因分析方法? 在当下各类自动化漏洞挖掘工具(比如各类fuzzer)的辅助下,每日发现的bug数量已经远超开发人员确认并修复的数量。设计一种自动化发现漏洞的工具并不难,难在如何根据这些工具报出的crash信息来准确地分析出漏洞的根本原因。对于大型程序而言,崩溃测试样例(crashing testcase)执行下来可能经历了几百万条汇编指令,手工确认稍微有点不现实了。因此需要设计一些(自动化)的根因分析工具。

怎么进行根因分析?目前有哪些工作? 最朴素而直观的思想就是消耗安全分析人员的精力,从程序的入口点(entry)或者崩溃点(crash site)出发,看看程序是怎么执行的,哪些元素(program entity)会导致最后的crash,然后再进行对应的修复。根据定位元素的粒度不同,根因分析可以定位到函数级(function level)、语句级(statement level)、汇编指令级(instruction level)。由于在汇编指令上进行分析可以更普适地适应多种编程语言、不需要获取源码,所以下文的讨论都是围绕汇编指令级展开。

目前一些自动化根因分析研究思路有:

  1. 基于程序谱的分析方法(Spectrum-based)。大概思路是不需要考虑汇编指令的语义信息,利用一些统计学的方法来分析哪些指令有问题。这类方法基于这样一个场景:假设我们有一大批相似的测试样例,其中有些会导致程序崩溃,有些不会,那么这两类测试样例的执行路径可能有不同的偏好。那么那些更倾向于在崩溃测试样例中执行的指令更有可能是root cause。
  2. 事后分析方法(Postmortem-based)。直译尸检分析,形象理解为从程序崩溃后留下的“尸体”开始分析。它假定程序崩溃后会产生一个coredump(核心转储)文件,包含了崩溃点的内存快照(memory snapshot),以及这个测试样例的执行路径(execution trace)。前者用于提供数据流信息(比如内存值、寄存器值),后者用于提供控制流信息(汇编指令执行与跳转)。在此基础上,结合一些逆向执行(reverse execution)和后向污点分析(backward taint analysis)的方法,定位可能的root cause。
  3. 基于模型的分析方法(Model-based)。这一类方法是近些年提出的,它通过定义语义相关的模型,利用机器学习或深度学习的思想,找到语义上导致崩溃的root cause。

这些研究思路都解决了什么问题?有什么独特的优点?存在哪些独有的不足? 基于程序谱的分析方法直观上似乎有点道理。它仅考虑汇编指令本身,而但仅仅从统计结果上去分析,可能并不能准确分析出逻辑上的root cause。这类方法一般会设计一种排名策略(ranking),对选择出的可疑指令进行top1-topn的排名,来试图提高准确性。这类方法一般需要根据一个崩溃样例以及和它相似的崩溃样例和非崩溃样例进行分析,因此时空开销都比较大。

事后分析方法相比程序谱分析方法考虑了指令语义,比如在逆向执行的时候会设计一些汇编指令handler,对于内存的分析也会更精确些。但污点分析方法毕竟存在过度污染(over-tainting)的问题,导致结果冗余比较严重。

基于模型的分析方法利用AI的优势,可以给出更有语义信息的root cause,在一定程度上帮助开发人员去分析。不过模型的训练依赖训练集的质量,并且受程序语义影响很大。在不同领域之间可能迁移性不是很好,比如没法处理一些特定的密码学函数。且为待测程序建立模型来描述其结构与行为是非常复杂、耗时的事情

现有的这些方法有没有什么普遍存在的问题? 在最后评估阶段(evaluation),一般先通过手工分析确定哪些汇编指令,如果方法输出的汇编指令集合里包含这些指令,那么就认为是发现了root cause。但自动化方法毕竟缺少人工参与,给出的结果一定是不准确的。现有的工作的一个主流思想在于“方法给出的集合可以包含无关指令,但不能缺少相关指令”,旨在提高召回率(recall)。因此往往给出与root cause不相关的指令。但实际上,在最后的修复端,如果给出不相关指令过多,那么仍然需要开发者去分析,依旧耗时耗力。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),9.43%希望root cause在分析结果的Top1,73.58%容许在Top5,15.09%容许在Top10。所以约98%的情况下需要在Top10内给出结果。就分析准确度与开发人员满意度而言,如果RCA工具准确度达90%,满意度几乎达到100%了。准确度低于20%时只有12%接受,如果满意度达50%、75%、90%,准确度需要分别达到50%、75%、85%(但是原文说90%)。

目前的绝大部分RCA分析的工作的输出是两类:ranked list和suspicious set。但两者都存在的问题是仅仅高亮了可能存在bug的元素,而缺乏一些rational的分析。

不同的分析粒度的优势

基于文件粒度的RCA工作(比如Scaffle)希望找到包含百万级同质代码库中哪些文件和crash有关。在此基础上让对应的工程师团队去处理bug,有利于大型组织管理。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),开发者对粒度的top3期望依次是方法级别、语句级别、基本块级别,不过对这三种粒度的倾向之间没有明显差异。而当时比较多的方法是语句级别的

分析时间开销

根据采用的策略不同,RCA之间的时间开销差异可能达两个数量级。(秒级-分钟级-小时级)。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),90%开发者接受1min以内的分析,不到9%开发者接受超过1h的分析。50%开发者大概在30min以内。

一些想法

  1. 什么是漏洞的根本原因?假如函数A内创建临时变量x并调用函数B(x),在B内引发crash,那么应该归咎为A没有处理x呢,还是B没有检查x呢?这是API实现的问题,还是API误用的问题?(开发者or用户)
  2. 对于某一个crash,如果开发人员进行了修复,那么这个修复能拿来当root cause吗?不同开发人员修复的风格可能不一样,修复也未必是完全的,root cause就是一个主观的问题了。

相关论文的一些发现(疑问)

  • “传统的SFL方法效果在Defects4J等部分数据集可能远优于DLFL方法,可能是基准实验的过拟合问题。”传统方法的过拟合指的是什么?DLFL为什么在基准测试集取得和别的数据集一样好的效果?传统方法在不同测试集的表现差异是方法的问题还是测试集的问题?(A Universal Data Augmentation Approach for Fault Localization, ICSE 2022)
  • 不同种类的FL方法在时间开销上数量级是不同的。测试的时候如果集成上较低数量级开销的方法,不会对运行时间有很大影响,但可以提升效率。不同种类FL方法相关性不高,可以考虑结合使用。(An Empirical Study of Fault Localization Families and Their Combinations, TSE 2021)
  • 调用栈做FL分析时,如果根因在栈上的话,40%是第一个栈帧,90%在前10个栈帧里。(Do stack traces help developers fix bugs? Mining Softw. Repositories, 2010)

参考文献

  • Scaffle: Bug Localization on Millions of Files, ISSTA 2020
  • Probabilistic reasoning in diagnosing causes of program failures, STVR 2016
  • Practitioners’ expectations on automated fault localization, ISSTA 2016

以上内容仅代表个人观点,不定期更新,欢迎讨论

\ No newline at end of file diff --git a/readings/index.html b/readings/index.html index 4e1114c..2c776bb 100644 --- a/readings/index.html +++ b/readings/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

文章阅读

约 156 个字 预计阅读时间 1 分钟

综合性知识学习

会议总结

软件供应链

大模型

Google

编程语言

磨刀不误砍柴工

\ No newline at end of file diff --git a/reverse-advanced/index.html b/reverse-advanced/index.html index a3458e3..bf99195 100644 --- a/reverse-advanced/index.html +++ b/reverse-advanced/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

逆向高阶

约 59 个字 预计阅读时间不到 1 分钟

Windows逆向技术概念

DLL注入,Windows消息钩取,DLL卸载,代码注入,API钩取,进程隐藏,IE连接控制,TLS回调函数,TEB,PEB,SEH,IA-32,反调试(静态、动态),PE镜像,Debug Blocker

逆向高阶

约 59 个字 预计阅读时间不到 1 分钟

Windows逆向技术概念

DLL注入,Windows消息钩取,DLL卸载,代码注入,API钩取,进程隐藏,IE连接控制,TLS回调函数,TEB,PEB,SEH,IA-32,反调试(静态、动态),PE镜像,Debug Blocker

\ No newline at end of file diff --git a/reverse-basic/index.html b/reverse-basic/index.html index bdd4a61..79719c6 100644 --- a/reverse-basic/index.html +++ b/reverse-basic/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

逆向基础

约 1078 个字 10 行代码 预计阅读时间 5 分钟

逆向函数时,要提前预测下函数实现机制,以节省时间。要明白哪些部分属于程序特有的实现,哪些部分属于第三方的库,不要随便进到第三方库或者底层API里面分析。

调用约定

cdecl(C默认)由caller负责清理栈上传入参数。

stdcall由callee负责清理栈上传入参数(Win32API),被调函数返回时使用RETN X来退出,相当于RETN、POP X。比如退两个参数,就RETN 8。

fastcall为了提高速度,分别使用ECX、EDX传递前两个参数,更多参数还是使用内存。 传参时都是从右向左以此压入栈中。

一些常见汇编操作符

call 包括保存返回地址、IP跳转

retnpop EIP

test 相当于AND,但是不改变普通寄存器的值,只修改EFLAGS寄存器

NOP指令的用途

NOP指令通常用于控制时序的目的,强制内存对齐,防止流水线灾难,占据分支指令延迟,或是作为占位符以供程序的改善(或替代被移除的指令)。

函数执行栈帧推断

函数内部一般先会执行以下两条指令:

push ebp
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

逆向基础

约 1078 个字 10 行代码 预计阅读时间 5 分钟

逆向函数时,要提前预测下函数实现机制,以节省时间。要明白哪些部分属于程序特有的实现,哪些部分属于第三方的库,不要随便进到第三方库或者底层API里面分析。

调用约定

cdecl(C默认)由caller负责清理栈上传入参数。

stdcall由callee负责清理栈上传入参数(Win32API),被调函数返回时使用RETN X来退出,相当于RETN、POP X。比如退两个参数,就RETN 8。

fastcall为了提高速度,分别使用ECX、EDX传递前两个参数,更多参数还是使用内存。 传参时都是从右向左以此压入栈中。

一些常见汇编操作符

call 包括保存返回地址、IP跳转

retnpop EIP

test 相当于AND,但是不改变普通寄存器的值,只修改EFLAGS寄存器

NOP指令的用途

NOP指令通常用于控制时序的目的,强制内存对齐,防止流水线灾难,占据分支指令延迟,或是作为占位符以供程序的改善(或替代被移除的指令)。

函数执行栈帧推断

函数内部一般先会执行以下两条指令:

push ebp
 mov ebp,esp
 

可以观察ebp和esp的修改情况推断函数栈帧

名称修饰

名称修饰(name mangling,name decoration),用来解决标志符的唯一命名问题。比如在不同的命名空间实现相同名称的函数,这个函数在怎么表示呢?名称修饰技术用来生成唯一的标志符,保留命名空间、函数名、结构体名、类名以及参数类型等等信息。名称修饰和调用约定、编译器有关,应用最广泛的是C++的代码(尤其是混合C编译时)。比如_ZN9wikipedia7article6formatEv可以用来表示:

namespace wikipedia
 {
@@ -17,6 +17,40 @@
         std::string format();
     }
 }
-

其中_Z是开头(下划线+大写字母在C中是保留的标志符,避免冲突),N表示是嵌套有命名空间和类名,随后的数字+字母中,数字表示长度,字母表示名称,并以E结束。之后的参数表示函数的参数类型,v为void。

PE文件

PE(Portable Execution)文件是Windows系统使用的可执行文件格式。

  • 可执行PE文件扩展名一般为exe,src
  • 库文件扩展名一般为dll,ocx,cpl,drv
  • 驱动程序文件扩展名一般为sys,vxd
  • 对象文件扩展名一般为obj

PE文件的数据节

  • .text 代码节,存放二进制机器码
  • .data 初始化数据节,如宏定义、全局变量、静态变量
  • .idata 可执行文件使用的动态链接库等外部函数与文件,即输入表
  • .rsrc 程序资源节,包括图标、菜单等

#pragma data_seg()可以将代码任意部分编译到PE文件任意节,节名也可以自定义。

静态链接库与动态链接库

静态库的拓展名为.a.lib;动态库的拓展名一般为.so.dll

静态库编译时直接整合到目标程序中,编译成功后的可执行文件可以独立运行;动态库编译时可执行程序无法独立运行

静态库更新后需要更新整个目标程序;动态库更新后只需更换新的动态库即可

静态库编译命令:gcc -c xx.c -o xx.oar crs libxx.a xx.o;动态库编译命令:gcc xx.c -o libxx.so -shared -fPIC其中-fPIC表示使用相对位置

gdb

添加多个符号表add-symbol-file xxx addr其中addr是代码段起始地址,xxx可以为sym文件,或elf文件等。变异时需要加上-g保留符号表(指定具体格式如-g2 -gdwarf-2),可以逐个使用add-symbol-file,都添加进去。

使用ulimit -c unlimited设置不限制coredump文件大小,然后root用户echo "core-%e-%p" > /proc/sys/kernel/core_pattern设置保留程序名、pid,则对于编译时添加了-g选项的程序,其崩溃产生的coredump文件可以使用gdb <程序名> <coredump文件名>来寻找root cause。gdb内用where查看调用栈。

推荐阅读

Linux 静态库 编译和使用 Linux 动态库 编译和使用 Makefile入门 Makefile官方文档 coredump文件基础用法

\ No newline at end of file diff --git a/sci-thoughts/index.html b/sci-thoughts/index.html index 3b2af56..37361b4 100644 --- a/sci-thoughts/index.html +++ b/sci-thoughts/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

科研心得

约 508 个字 预计阅读时间 2 分钟

养成习惯

时间过得总是非常快的。忙着做一个课题,可能每天感觉不到有什么进展呢,半年一年就过去了。如果有这种想法,多半是没做好规划,像个无头苍蝇一样东闯西撞。

感觉有两个习惯是必须养成的,一是读论文要思考问题与意义:看到题目和摘要,思考这篇文章希望解决什么问题、这个问题有什么价值、解决这个问题有什么思路、会遇到哪些普遍与特殊的挑战,以及文章基于哪些假设并且会试图避而不谈的缺陷;二是每天进行总结与归纳,思考一天到底有什么进展,凝练总结成文字或ppt讲稿。每天光看不总结,等于白看!平时对各种问题就要有所准备与思考,不要别人问起的时候就敷衍地给一个回答,没有意义。

早上写todo list,晚上写done list,看看这一天进展如何。是否有没做完的事情,是否有分心做了别的事情,明天如何规划时间……对自己每天、每周、每月能做的事情有清楚的认识,不盲目自大也不妄自菲薄。

做任何事都要给一个清晰的ddl,督促尽快完成不要拖沓。另一方面是为了限制思考,要集中、快速,不要漫无目的地发散。比如读论文前思考这篇文章需要解决的挑战时,限定在3min之内,超时以后无论是否想到多少都要停下来。也可以有效避免分心。

科研写作

科研写作需要系统的训练。每天愉快地读、写一小时,长期坚持,叫做“read and write”。

写文章要弄清楚读者都是同专业的人,因此要体现出专业性与科学性、精确性、简洁性、逻辑性。

科研心得

约 508 个字 预计阅读时间 2 分钟

养成习惯

时间过得总是非常快的。忙着做一个课题,可能每天感觉不到有什么进展呢,半年一年就过去了。如果有这种想法,多半是没做好规划,像个无头苍蝇一样东闯西撞。

感觉有两个习惯是必须养成的,一是读论文要思考问题与意义:看到题目和摘要,思考这篇文章希望解决什么问题、这个问题有什么价值、解决这个问题有什么思路、会遇到哪些普遍与特殊的挑战,以及文章基于哪些假设并且会试图避而不谈的缺陷;二是每天进行总结与归纳,思考一天到底有什么进展,凝练总结成文字或ppt讲稿。每天光看不总结,等于白看!平时对各种问题就要有所准备与思考,不要别人问起的时候就敷衍地给一个回答,没有意义。

早上写todo list,晚上写done list,看看这一天进展如何。是否有没做完的事情,是否有分心做了别的事情,明天如何规划时间……对自己每天、每周、每月能做的事情有清楚的认识,不盲目自大也不妄自菲薄。

做任何事都要给一个清晰的ddl,督促尽快完成不要拖沓。另一方面是为了限制思考,要集中、快速,不要漫无目的地发散。比如读论文前思考这篇文章需要解决的挑战时,限定在3min之内,超时以后无论是否想到多少都要停下来。也可以有效避免分心。

科研写作

科研写作需要系统的训练。每天愉快地读、写一小时,长期坚持,叫做“read and write”。

写文章要弄清楚读者都是同专业的人,因此要体现出专业性与科学性、精确性、简洁性、逻辑性。

\ No newline at end of file diff --git a/sentence-templates/index.html b/sentence-templates/index.html index fa7f900..a03bca4 100644 --- a/sentence-templates/index.html +++ b/sentence-templates/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

情景模板

约 468 个字 预计阅读时间 2 分钟

提出本文工作:

  • In this paper, we propose a novel approach to fault localization, SmartFL, that considers the four factors via efficient probabilistic modeling of the program semantics.
  • In this work, we propose POMP++, a system to address the above limitations in analyzing a post-crash artifact and pinpointing statements pertaining to the crash.
  • In this paper, we present REPT, a practical system that enables reverse debugging of software failures in deployed systems.

介绍某一流程在整体系统中的作用:

  • During program debugging, fault localization is the activity of identifying the exact locations of program faults.

说明某一步骤并非简单的:

  • However, identifying the bug-inducing commit precisely for a bug-revealing test can be non-trivial due to the following reasons.

凝练本文实验效果:

  • We design and implement REPT, deploy it on Microsoft Windows, and integrate it into WinDbg. We evaluate REPT on 16 real-world bugs and show that it can recover data values accurately (92% on average) and efficiently (in less than 20 seconds) for these bugs. We also show that it enables effective reverse debugging for 14 bugs.

提出本文novelty:

  • The novelty of this work lies in two aspects. First, we propose a new VSA-based approach for memory alias verification. xxx. Second, we develop new schemes to incorporate our customized VSA to POMP. xxx.

提出本文insight:

  • Our core insight is that the probability of a fault in the current program element leads to the current test results can be efficiently estimated by analyzing the following:

准备开始介绍技术细节:

  • In this section, we elaborate on the technical details of our xxx approach. First, we describe how to xxx. Second, we discuss how to xxx. Finally, we discuss how to xxx.
  • As we elaborate below, the reasons behind this are two folds.

说目前的工作研究的主要内容受限、别的方法存在问题:

  • However, it inevitably detours the fuzzing program away from the critical objects.
  • Existing approaches either consider the full semantics of the program (e.g., mutation-based fault localization and angelic debugging), leading to scalability issues, or ignore the semantics of the program (e.g., spectrum-based fault localization), leading to imprecise localization results.
  • However, all existing approaches only consider whether a program entity exists in samples but neglect the execution times of the entities in a certain sample and the sequence of their executions. As demonstrated in Section 5, without such sequence information, program spectrum-based fault localization would inevitably introduce imprecision.

一些工作细节:

  • In our work, we manually annotate all these sinks based on their naming patterns.

情景模板

约 468 个字 预计阅读时间 2 分钟

提出本文工作:

  • In this paper, we propose a novel approach to fault localization, SmartFL, that considers the four factors via efficient probabilistic modeling of the program semantics.
  • In this work, we propose POMP++, a system to address the above limitations in analyzing a post-crash artifact and pinpointing statements pertaining to the crash.
  • In this paper, we present REPT, a practical system that enables reverse debugging of software failures in deployed systems.

介绍某一流程在整体系统中的作用:

  • During program debugging, fault localization is the activity of identifying the exact locations of program faults.

说明某一步骤并非简单的:

  • However, identifying the bug-inducing commit precisely for a bug-revealing test can be non-trivial due to the following reasons.

凝练本文实验效果:

  • We design and implement REPT, deploy it on Microsoft Windows, and integrate it into WinDbg. We evaluate REPT on 16 real-world bugs and show that it can recover data values accurately (92% on average) and efficiently (in less than 20 seconds) for these bugs. We also show that it enables effective reverse debugging for 14 bugs.

提出本文novelty:

  • The novelty of this work lies in two aspects. First, we propose a new VSA-based approach for memory alias verification. xxx. Second, we develop new schemes to incorporate our customized VSA to POMP. xxx.

提出本文insight:

  • Our core insight is that the probability of a fault in the current program element leads to the current test results can be efficiently estimated by analyzing the following:

准备开始介绍技术细节:

  • In this section, we elaborate on the technical details of our xxx approach. First, we describe how to xxx. Second, we discuss how to xxx. Finally, we discuss how to xxx.
  • As we elaborate below, the reasons behind this are two folds.

说目前的工作研究的主要内容受限、别的方法存在问题:

  • However, it inevitably detours the fuzzing program away from the critical objects.
  • Existing approaches either consider the full semantics of the program (e.g., mutation-based fault localization and angelic debugging), leading to scalability issues, or ignore the semantics of the program (e.g., spectrum-based fault localization), leading to imprecise localization results.
  • However, all existing approaches only consider whether a program entity exists in samples but neglect the execution times of the entities in a certain sample and the sequence of their executions. As demonstrated in Section 5, without such sequence information, program spectrum-based fault localization would inevitably introduce imprecision.

一些工作细节:

  • In our work, we manually annotate all these sinks based on their naming patterns.
\ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index c65b745..5962446 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,178 +2,178 @@ https://tech.c01dkit.com/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/IDA/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/autoconf/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/c/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/code-gracely/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/cpp/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/crawler/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/docker/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/envs/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/fuzzing/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/git/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/go/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/interesting-articles/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/investigations/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/java/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/latex/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/linux-kernel/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/linux-server/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/llvm/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/openssh/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/picking-ups/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/porting/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/proxy/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/pwn-college-cse365-spring2023/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/python/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/rca/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/readings/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/reverse-advanced/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/reverse-basic/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/sci-thoughts/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/sentence-templates/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/tech-sslh/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/try-chatgpt/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/word-learning/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/array/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/branch-and-bound-algo/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/dynamic-algo/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/graph-algo/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/graph/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/greedy-algo/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/linkedlist/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/queue/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/stack/ - 2024-11-26 + 2024-11-27 https://tech.c01dkit.com/dsa/tree/ - 2024-11-26 + 2024-11-27 \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 3618ee65d6994692e938fa88af44866ea5c143ce..1f1620d7d8659e863bab2865a8141a7bcf12fcb6 100644 GIT binary patch literal 510 zcmVH|8r?{Wo=<_E_iKh0L9nMj+-zL0O0#RMa12ZWc#m#Ri&y@ z@9hIj>{)Ozw(A)n?9+GHT~)odhY5#3j5QxP@pycCxQ<~rVxkPdkNqCiT_X1 zw=bU+HJCWr6dx5yt7#>NrYm4EteR}jnp%M+U{MrZvV$s!aVACXae8`^Y@;Z4o;9_k zi22A^kXQ!PKw)nKk}5xMcn2)Yi6;CLW>Dk;FkUr1AE&F4G!QYUvxH?cnngg$ z7>RmCF?%~~Gjz(Db0nw2x`{TIbk!^c@)C_rAz+8b65hXiYbY0aXOZqTpJU}dMMbb! z&FohYw*3LAlG`2y4Y(PiMRx=G0^~KzX|mqP-)QQ3)*NXMa12ZWZP9+C9En{ zm3nVKU^1Qs7h}7g0m6QL&F-q|wLMHY1Y)dt;Kbwc>G3-H-AtKX4Cm@l@2edJjMjzj zT>bd|)qJQP+q=`0J(KK8=fLNx7fGL*W?7b+ozMu0>zKQSu`ge^d24L;^~b8c+m&Mr z@Ot%foP5M~i^3(05cW0h4|Z@;V;q}Pv)%r?H?WM+w#WVPojDxL@u75iYkLjf{E7ch z(zh?46*ZV7Vhm4;Bx+jGlIb!a`BjrmNmI+Pc*=^RjX0=+6lPZBo~GyLl5G^l&WWZL z6)_itGO?5aHIT)jCsyU>4evn8a-s?Ugc%e$4?&xPq~N*V~{)mf%It0o}tXU!rY zCJM~GqL>^G+YFtO<{U{ei*BM#IbJnOfwTmJ(R=F1Ak+QBd&4Q0cP`Ss=5wsl$Djyi z)XaXFVA~(CD!J`Z$bg+8AlVzx7htDZPBS`F{zg;Ri{?l(l@g*1u_;@)w5@ZR_|{;U zy=F3&yc+C5x};eZE-_o<33AX)$(EskoMBZqFS*Ry-axSC5~uPBUbQgZp24mGMu)ec z%eFZ6H-ptpBD>z=ZA-yAkoAs58U8iVM9L-$;Gk?u`Dy>3d^s^m`x~nHPG5Hv003QK B16u$9 diff --git a/stylesheets/_config.scss b/stylesheets/_config.scss new file mode 100644 index 0000000..9165715 --- /dev/null +++ b/stylesheets/_config.scss @@ -0,0 +1,42 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Variables: breakpoints +// ---------------------------------------------------------------------------- + +// Device-specific breakpoints +$break-devices: ( + mobile: ( + portrait: px2em(220px) px2em(479.75px), + landscape: px2em(480px) px2em(719.75px) + ), + tablet: ( + portrait: px2em(720px) px2em(959.75px), + landscape: px2em(960px) px2em(1219.75px) + ), + screen: ( + small: px2em(1220px) px2em(1599.75px), + medium: px2em(1600px) px2em(1999.75px), + large: px2em(2000px) + ) +); diff --git a/stylesheets/main.scss b/stylesheets/main.scss new file mode 100644 index 0000000..88ac2d9 --- /dev/null +++ b/stylesheets/main.scss @@ -0,0 +1,90 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Dependencies +// ---------------------------------------------------------------------------- + +@import "material-color"; +@import "material-shadows"; + +// ---------------------------------------------------------------------------- +// Local imports +// ---------------------------------------------------------------------------- + +@import "utilities/break"; +@import "utilities/convert"; + +@import "config"; + +@import "main/resets"; +@import "main/colors"; +@import "main/icons"; +@import "main/typeset"; + +@import "main/components/author"; +@import "main/components/banner"; +@import "main/components/base"; +@import "main/components/clipboard"; +@import "main/components/code"; +@import "main/components/consent"; +@import "main/components/content"; +@import "main/components/dialog"; +@import "main/components/feedback"; +@import "main/components/footer"; +@import "main/components/form"; +@import "main/components/header"; +@import "main/components/meta"; +@import "main/components/nav"; +@import "main/components/pagination"; +@import "main/components/post"; +@import "main/components/progress"; +@import "main/components/search"; +@import "main/components/select"; +@import "main/components/sidebar"; +@import "main/components/source"; +@import "main/components/status"; +@import "main/components/tabs"; +@import "main/components/tag"; +@import "main/components/tooltip"; +@import "main/components/tooltip2"; +@import "main/components/top"; +@import "main/components/version"; + +@import "main/extensions/markdown/admonition"; +@import "main/extensions/markdown/footnotes"; +@import "main/extensions/markdown/toc"; + +@import "main/extensions/pymdownx/arithmatex"; +@import "main/extensions/pymdownx/critic"; +@import "main/extensions/pymdownx/details"; +@import "main/extensions/pymdownx/emoji"; +@import "main/extensions/pymdownx/highlight"; +@import "main/extensions/pymdownx/keys"; +@import "main/extensions/pymdownx/tabbed"; +@import "main/extensions/pymdownx/tasklist"; + +@import "main/integrations/giscus"; +@import "main/integrations/mermaid"; + +@import "main/modifiers/grid"; +@import "main/modifiers/inline"; diff --git a/stylesheets/main/_colors.scss b/stylesheets/main/_colors.scss new file mode 100644 index 0000000..43e2bd7 --- /dev/null +++ b/stylesheets/main/_colors.scss @@ -0,0 +1,155 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Color variables +:root { + @extend %root; + + // Primary color shades + --md-primary-fg-color: hsla(#{hex2hsl($clr-indigo-500)}, 1); + --md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-400)}, 1); + --md-primary-fg-color--dark: hsla(#{hex2hsl($clr-indigo-700)}, 1); + --md-primary-bg-color: hsla(0, 0%, 100%, 1); + --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); + + // Accent color shades + --md-accent-fg-color: hsla(#{hex2hsl($clr-indigo-a200)}, 1); + --md-accent-fg-color--transparent: hsla(#{hex2hsl($clr-indigo-a200)}, 0.1); + --md-accent-bg-color: hsla(0, 0%, 100%, 1); + --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7); +} + +// ---------------------------------------------------------------------------- + +// Allow to explicitly use color schemes in nested content +[data-md-color-scheme="default"] { + @extend %root; + + // Indicate that the site is rendered with a light color scheme + color-scheme: light; + + // Hide images for dark mode + img[src$="#only-dark"], + img[src$="#gh-dark-mode-only"] { + display: none; + } +} + +// ---------------------------------------------------------------------------- +// Placeholders +// ---------------------------------------------------------------------------- + +// Default theme, i.e. light mode +%root { + + // Color hue in the range [0,360] - change this variable to alter the tone + // of the theme, e.g. to make it more redish or greenish + --md-hue: 225deg; + + // Default color shades + --md-default-fg-color: hsla(0, 0%, 0%, 0.87); + --md-default-fg-color--light: hsla(0, 0%, 0%, 0.54); + --md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32); + --md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07); + --md-default-bg-color: hsla(0, 0%, 100%, 1); + --md-default-bg-color--light: hsla(0, 0%, 100%, 0.7); + --md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.3); + --md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.12); + + // Code color shades + --md-code-fg-color: hsla(200, 18%, 26%, 1); + --md-code-bg-color: hsla(200, 0%, 96%, 1); + + // Code highlighting color shades + --md-code-hl-color: hsla(#{hex2hsl($clr-blue-a200)}, 1); + --md-code-hl-color--light: hsla(#{hex2hsl($clr-blue-a200)}, 0.1); + + // Code highlighting syntax color shades + --md-code-hl-number-color: hsla(0, 67%, 50%, 1); + --md-code-hl-special-color: hsla(340, 83%, 47%, 1); + --md-code-hl-function-color: hsla(291, 45%, 50%, 1); + --md-code-hl-constant-color: hsla(250, 63%, 60%, 1); + --md-code-hl-keyword-color: hsla(219, 54%, 51%, 1); + --md-code-hl-string-color: hsla(150, 63%, 30%, 1); + --md-code-hl-name-color: var(--md-code-fg-color); + --md-code-hl-operator-color: var(--md-default-fg-color--light); + --md-code-hl-punctuation-color: var(--md-default-fg-color--light); + --md-code-hl-comment-color: var(--md-default-fg-color--light); + --md-code-hl-generic-color: var(--md-default-fg-color--light); + --md-code-hl-variable-color: var(--md-default-fg-color--light); + + // Typeset color shades + --md-typeset-color: var(--md-default-fg-color); + + // Typeset `a` color shades + --md-typeset-a-color: var(--md-primary-fg-color); + + // Typeset `del` and `ins` color shades + --md-typeset-del-color: hsla(6, 90%, 60%, 0.15); + --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15); + + // Typeset `kbd` color shades + --md-typeset-kbd-color: hsla(0, 0%, 98%, 1); + --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1); + --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1); + + // Typeset `mark` color shades + --md-typeset-mark-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5); + + // Typeset `table` color shades + --md-typeset-table-color: hsla(0, 0%, 0%, 0.12); + --md-typeset-table-color--light: hsla(0, 0%, 0%, 0.035); + + // Admonition color shades + --md-admonition-fg-color: var(--md-default-fg-color); + --md-admonition-bg-color: var(--md-default-bg-color); + + // Warning color shades + --md-warning-fg-color: hsla(0, 0%, 0%, 0.87); + --md-warning-bg-color: hsla(60, 100%, 80%, 1); + + // Footer color shades + --md-footer-fg-color: hsla(0, 0%, 100%, 1); + --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7); + --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.45); + --md-footer-bg-color: hsla(0, 0%, 0%, 0.87); + --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32); + + // Shadow depth 1 + --md-shadow-z1: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.05), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.1); + + // Shadow depth 2 + --md-shadow-z2: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.1), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.25); + + // Shadow depth 3 + --md-shadow-z3: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.2), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.35); +} diff --git a/stylesheets/main/_icons.scss b/stylesheets/main/_icons.scss new file mode 100644 index 0000000..59c6a39 --- /dev/null +++ b/stylesheets/main/_icons.scss @@ -0,0 +1,37 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Icon +.md-icon { + + // SVG defaults + svg { + display: block; + width: px2rem(24px); + height: px2rem(24px); + fill: currentcolor; + } +} diff --git a/stylesheets/main/_resets.scss b/stylesheets/main/_resets.scss new file mode 100644 index 0000000..4cb188d --- /dev/null +++ b/stylesheets/main/_resets.scss @@ -0,0 +1,118 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Enforce correct box model and prevent adjustments of font size after +// orientation changes in IE and iOS +html { + box-sizing: border-box; + text-size-adjust: none; +} + +// All elements shall inherit the document default +*, +*::before, +*::after { + box-sizing: inherit; + + // [reduced motion]: Disable all transitions + @media (prefers-reduced-motion) { + transition: none !important; // stylelint-disable-line + } +} + +// Remove margin in all browsers +body { + margin: 0; +} + +// Reset tap outlines on iOS and Android +a, +button, +label, +input { + -webkit-tap-highlight-color: transparent; +} + +// Reset link styles +a { + color: inherit; + text-decoration: none; +} + +// Normalize horizontal separator styles +hr { + box-sizing: content-box; + display: block; + height: px2rem(1px); + padding: 0; + overflow: visible; + border: 0; +} + +// Normalize font-size in all browsers +small { + font-size: 80%; +} + +// Prevent subscript and superscript from affecting line-height +sub, +sup { + line-height: 1em; +} + +// Remove border on image +img { + border-style: none; +} + +// Reset table styles +table { + border-spacing: 0; + border-collapse: separate; +} + +// Reset table cell styles +td, +th { + font-weight: 400; + vertical-align: top; +} + +// Reset button styles +button { + padding: 0; + margin: 0; + font-family: inherit; + font-size: inherit; + background: transparent; + border: 0; +} + +// Reset input styles +input { + border: 0; + outline: none; +} diff --git a/stylesheets/main/_typeset.scss b/stylesheets/main/_typeset.scss new file mode 100644 index 0000000..8d18f53 --- /dev/null +++ b/stylesheets/main/_typeset.scss @@ -0,0 +1,613 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules: font definitions +// ---------------------------------------------------------------------------- + +// Enable font-smoothing in Webkit and FF +body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + // Font with fallback for body copy + --md-text-font-family: + var(--md-text-font, _), + -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif; + + // Font with fallback for code + --md-code-font-family: + var(--md-code-font, _), + SFMono-Regular, Consolas, Menlo, monospace; +} + +// Define default fonts +body, +input, +aside { + font-family: var(--md-text-font-family); + font-feature-settings: "kern", "liga"; + color: var(--md-typeset-color); +} + +// Define monospaced fonts +code, +pre, +kbd { + font-family: var(--md-code-font-family); + font-feature-settings: "kern"; +} + +// ---------------------------------------------------------------------------- +// Rules: typesetted content +// ---------------------------------------------------------------------------- + +// General variables +:root { + --md-typeset-table-sort-icon: svg-load("material/sort.svg"); + --md-typeset-table-sort-icon--asc: svg-load("material/sort-ascending.svg"); + --md-typeset-table-sort-icon--desc: svg-load("material/sort-descending.svg"); +} + +// ---------------------------------------------------------------------------- + +// Content that is typeset - if possible, all margins, paddings and font sizes +// should be set in ems, so nested blocks (e.g. admonitions) render correctly. +.md-typeset { + font-size: px2rem(16px); + line-height: 1.6; + color-adjust: exact; + + // [print]: We'll use a smaller `font-size` for printing, so code examples + // don't break too early, and `16px` looks too big anyway. + @media print { + font-size: px2rem(13.6px); + } + + // Default spacing + ul, + ol, + dl, + figure, + blockquote, + pre { + margin-block: 1em; + } + + // Headline on level 1 + h1 { + margin: 0 0 px2em(40px, 32px); + font-size: px2em(32px); + font-weight: 300; + line-height: 1.3; + color: var(--md-default-fg-color--light); + letter-spacing: -0.01em; + } + + // Headline on level 2 + h2 { + margin: px2em(40px, 25px) 0 px2em(16px, 25px); + font-size: px2em(25px); + font-weight: 300; + line-height: 1.4; + letter-spacing: -0.01em; + } + + // Headline on level 3 + h3 { + margin: px2em(32px, 20px) 0 px2em(16px, 20px); + font-size: px2em(20px); + font-weight: 400; + line-height: 1.5; + letter-spacing: -0.01em; + } + + // Headline on level 3 following level 2 + h2 + h3 { + margin-top: px2em(16px, 20px); + } + + // Headline on level 4 + h4 { + margin: px2em(16px) 0; + font-weight: 700; + letter-spacing: -0.01em; + } + + // Headline on level 5-6 + h5, + h6 { + margin: px2em(16px, 12.8px) 0; + font-size: px2em(12.8px); + font-weight: 700; + color: var(--md-default-fg-color--light); + letter-spacing: -0.01em; + } + + // Headline on level 5 + h5 { + text-transform: uppercase; + + // Don't uppercase code blocks + code { + text-transform: none; + } + } + + // Horizontal separator + hr { + display: flow-root; + margin: 1.5em 0; + border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest); + } + + // Text link + a { + color: var(--md-typeset-a-color); + word-break: break-word; + + // Also enable color transition on pseudo elements + &, + &::before { + transition: color 125ms; + } + + // Text link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + + // Inline code block + code { + background-color: var(--md-accent-fg-color--transparent); + } + } + + // Inline code block + code { + color: currentcolor; + transition: background-color 125ms; + } + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + } + + // Code block + code, + pre, + kbd { + font-variant-ligatures: none; + color: var(--md-code-fg-color); + direction: ltr; + + // [print]: Wrap text and hide scollbars + @media print { + white-space: pre-wrap; + } + } + + // Inline code block + code { + padding: 0 px2em(4px, 13.6px); + font-size: px2em(13.6px); + word-break: break-word; + background-color: var(--md-code-bg-color); + border-radius: px2rem(2px); + box-decoration-break: clone; + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + } + + // Unformatted content + pre { + position: relative; + display: flow-root; + line-height: 1.4; + + // Code block + > code { + display: block; + padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px); + margin: 0; + overflow: auto; + word-break: normal; + touch-action: auto; + scrollbar-color: var(--md-default-fg-color--lighter) transparent; + scrollbar-width: thin; + outline-color: var(--md-accent-fg-color); + box-shadow: none; + box-decoration-break: slice; + + // Code block on hover + &:hover { + scrollbar-color: var(--md-accent-fg-color) transparent; + } + + // Webkit scrollbar + &::-webkit-scrollbar { + width: px2rem(4px); + height: px2rem(4px); + } + + // Webkit scrollbar thumb + &::-webkit-scrollbar-thumb { + background-color: var(--md-default-fg-color--lighter); + + // Webkit scrollbar thumb on hover + &:hover { + background-color: var(--md-accent-fg-color); + } + } + } + } + + // Keyboard key + kbd { + display: inline-block; + padding: 0 px2em(8px, 12px); + font-size: px2em(12px); + color: var(--md-default-fg-color); + word-break: break-word; + vertical-align: text-top; + background-color: var(--md-typeset-kbd-color); + border-radius: px2rem(2px); + box-shadow: + 0 px2rem(2px) 0 px2rem(1px) var(--md-typeset-kbd-border-color), + 0 px2rem(2px) 0 var(--md-typeset-kbd-border-color), + 0 px2rem(-2px) px2rem(4px) var(--md-typeset-kbd-accent-color) inset; + } + + // Text highlighting marker + mark { + color: inherit; + word-break: break-word; + background-color: var(--md-typeset-mark-color); + box-decoration-break: clone; + } + + // Abbreviation + abbr { + text-decoration: none; + cursor: help; + border-bottom: px2rem(1px) dotted var(--md-default-fg-color--light); + } + + // Small text + small { + opacity: 0.75; + } + + // Superscript and subscript + sup, + sub { + margin-inline-start: px2em(1px, 12.8px); + } + + // Blockquotes, possibly nested + blockquote { + padding-inline-start: px2rem(12px); + margin-inline: 0; + color: var(--md-default-fg-color--light); + border-inline-start: px2rem(4px) solid var(--md-default-fg-color--lighter); + } + + // Unordered list + ul { + list-style-type: disc; + + // Hack: allow to override `list-style-type` via `type`, without breaking + // compatibility for explicitly setting it in CSS - see https://t.ly/izJyH + &[type] { + list-style-type: revert-layer; + } + } + + // Unordered and ordered list + ul, + ol { + padding: 0; + margin-inline-start: px2em(10px); + + // Adjust display mode if not hidden + &:not([hidden]) { + display: flow-root; + } + + // 2nd layer nested ordered list + ol { + list-style-type: lower-alpha; + + // 3rd layer nested ordered list + ol { + list-style-type: lower-roman; + + // 4th layer nested ordered list + ol { + list-style-type: upper-alpha; + + // 5th layer nested ordered list + ol { + list-style-type: upper-roman; + } + } + } + } + + // Hack: allow to override `list-style-type` via `type`, without breaking + // compatibility for explicitly setting it in CSS - see https://t.ly/izJyH + &[type] { + list-style-type: revert-layer; + } + + // List element + li { + margin-inline-start: px2em(20px); + margin-bottom: 0.5em; + + // Adjust spacing + p, + blockquote { + margin: 0.5em 0; + } + + // Adjust spacing on last child + &:last-child { + margin-bottom: 0; + } + + // Nested list + :is(ul, ol) { + margin-block: 0.5em; + margin-inline-start: px2em(10px); + } + } + } + + // Definition list + dd { + margin-block: 1em 1.5em; + margin-inline-start: px2em(30px); + } + + // Image or video + img, + svg, + video { + max-width: 100%; + height: auto; + } + + // Image + img { + + // Adjust spacing when left-aligned + &[align="left"] { + margin: 1em; + margin-left: 0; + } + + // Adjust spacing when right-aligned + &[align="right"] { + margin: 1em; + margin-right: 0; + } + + // Adjust spacing when sole children + &[align]:only-child { + margin-top: 0; + } + } + + // Figure + figure { + display: flow-root; + width: fit-content; + max-width: 100%; + margin: 1em auto; + text-align: center; + + // Figure images + img { + display: block; + margin: 0 auto; + } + } + + // Figure caption + figcaption { + max-width: px2rem(480px); + margin: 1em auto; + font-style: italic; + } + + // Limit width to container + iframe { + max-width: 100%; + } + + // Data table + table:not([class]) { + display: inline-block; + max-width: 100%; + overflow: auto; + font-size: px2rem(12.8px); + touch-action: auto; + background-color: var(--md-default-bg-color); + border: px2rem(1px) solid var(--md-typeset-table-color); + border-radius: px2rem(2px); + + // [print]: Reset display mode so table header wraps when printing + @media print { + display: table; + } + + // Due to margin collapse because of the necessary inline-block hack, we + // cannot increase the bottom margin on the table, so we just increase the + // top margin on the following element + + * { + margin-top: 1.5em; + } + + // Elements in table heading and cell + :is(th, td) > * { + + // Adjust spacing on first child + &:first-child { + margin-top: 0; + } + + // Adjust spacing on last child + &:last-child { + margin-bottom: 0; + } + } + + // Table heading and cell + :is(th, td):not([align]) { + text-align: left; + + // Adjust for right-to-left languages + [dir="rtl"] & { + text-align: right; + } + } + + // Table heading + th { + min-width: px2rem(100px); + padding: px2em(12px, 12.8px) px2em(16px, 12.8px); + font-weight: 700; + vertical-align: top; + } + + // Table cell + td { + padding: px2em(12px, 12.8px) px2em(16px, 12.8px); + vertical-align: top; + border-top: px2rem(1px) solid var(--md-typeset-table-color); + } + + // Table body row + tbody tr { + transition: background-color 125ms; + + // Table row on hover + &:hover { + background-color: var(--md-typeset-table-color--light); + box-shadow: 0 px2rem(1px) 0 var(--md-default-bg-color) inset; + } + } + + // Text link in table + a { + word-break: normal; + } + } + + // Sortable table + table th[role="columnheader"] { + cursor: pointer; + + // Sort icon + &::after { + display: inline-block; + width: 1.2em; + height: 1.2em; + margin-inline-start: 0.5em; + vertical-align: text-bottom; + content: ""; + mask-image: var(--md-typeset-table-sort-icon); + mask-repeat: no-repeat; + mask-size: contain; + transition: background-color 125ms; + } + + // Show sort icon on hover + &:hover::after { + background-color: var(--md-default-fg-color--lighter); + } + + // Sort ascending icon + &[aria-sort="ascending"]::after { + background-color: var(--md-default-fg-color--light); + mask-image: var(--md-typeset-table-sort-icon--asc); + } + + // Sort descending icon + &[aria-sort="descending"]::after { + background-color: var(--md-default-fg-color--light); + mask-image: var(--md-typeset-table-sort-icon--desc); + } + } + + // Data table scroll wrapper + &__scrollwrap { + margin: 1em px2rem(-16px); + overflow-x: auto; + touch-action: auto; + } + + // Data table wrapper + &__table { + display: inline-block; + padding: 0 px2rem(16px); + margin-bottom: 0.5em; + + // [print]: Reset display mode so table header wraps when printing + @media print { + display: block; + } + + // Data table + html & table { + display: table; + width: 100%; + margin: 0; + overflow: hidden; + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: top-level +// ---------------------------------------------------------------------------- + +// [mobile -]: Align with body copy +@include break-to-device(mobile) { + + // Top-level unformatted content + .md-content__inner > pre { + margin: 1em px2rem(-16px); + + // Code block + code { + border-radius: 0; + } + } +} diff --git a/stylesheets/main/components/_author.scss b/stylesheets/main/components/_author.scss new file mode 100644 index 0000000..0e529a8 --- /dev/null +++ b/stylesheets/main/components/_author.scss @@ -0,0 +1,89 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Author, i.e., GitHub user + .md-author { + position: relative; + display: block; + flex-shrink: 0; + width: px2rem(32px); + height: px2rem(32px); + overflow: hidden; + border-radius: 100%; + transition: + color 125ms, + transform 125ms; + + // Author image + img { + display: block; + } + + // More authors + &--more { + font-size: px2rem(12px); + font-weight: 700; + line-height: px2rem(32px); + color: var(--md-default-fg-color--lighter); + text-align: center; + background: var(--md-default-fg-color--lightest); + } + + // Enlarge image + &--long { + width: px2rem(48px); + height: px2rem(48px); + } + } + + // Author link + a.md-author { + transform: scale(1); + + // Author image + img { + filter: grayscale(100%) opacity(75%); + // Hack: also apply this here, in order to mitigate browser glitches in + // Chrome and Edge when hovering the avatar - see https://t.ly/Q3ECC + border-radius: 100%; + transition: filter 125ms; + } + + // Author on focus/hover + &:is(:focus, :hover) { + z-index: 1; + transform: scale(1.1); + + // Author image + img { + filter: grayscale(0%); + } + } + } +} diff --git a/stylesheets/main/components/_banner.scss b/stylesheets/main/components/_banner.scss new file mode 100644 index 0000000..e019f7c --- /dev/null +++ b/stylesheets/main/components/_banner.scss @@ -0,0 +1,68 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Banner for announcements and warnings +.md-banner { + overflow: auto; + color: var(--md-footer-fg-color); + background-color: var(--md-footer-bg-color); + + // [print]: Hide banner + @media print { + display: none; + } + + // Banner with warning + &--warning { + color: var(--md-warning-fg-color); + background-color: var(--md-warning-bg-color); + } + + // Banner wrapper + &__inner { + padding: 0 px2rem(16px); + margin: px2rem(12px) auto; + font-size: px2rem(14px); + } + + // Banner button + &__button { + float: inline-end; + color: inherit; + cursor: pointer; + transition: opacity 250ms; + + // [no-js]: Hide button + .no-js & { + display: none; + } + + // Button on hover + &:hover { + opacity: 0.7; + } + } +} diff --git a/stylesheets/main/components/_base.scss b/stylesheets/main/components/_base.scss new file mode 100644 index 0000000..73c249f --- /dev/null +++ b/stylesheets/main/components/_base.scss @@ -0,0 +1,182 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules: base grid and containers +// ---------------------------------------------------------------------------- + +// Stretch container to viewport and set base `font-size` +html { + height: 100%; + overflow-x: hidden; + // Hack: normally, we would set the base `font-size` to `62.5%`, so we can + // base all calculations on `10px`, but Chromium and Chrome define a minimal + // `font-size` of `12px` if the system language is set to Chinese. For this + // reason we just double the `font-size` and set it to `20px`. + // + // See https://github.com/squidfunk/mkdocs-material/issues/911 + font-size: 125%; + + // [screen medium +]: Set base `font-size` to `11px` + @include break-from-device(screen medium) { + font-size: 137.5%; + } + + // [screen large +]: Set base `font-size` to `12px` + @include break-from-device(screen large) { + font-size: 150%; + } +} + +// Stretch body to container - flexbox is used, so the footer will always be +// aligned to the bottom of the viewport +body { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + min-height: 100%; + // Hack: reset `font-size` to `10px`, so the spacing for all inline elements + // is correct again. Otherwise the spacing would be based on `20px`. + font-size: px2rem(10px); + background-color: var(--md-default-bg-color); + + // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m) + @media print { + display: block; + } + + // Body in locked state + &[data-md-scrolllock] { + + // [tablet portrait -]: Omit scroll bubbling + @include break-to-device(tablet portrait) { + position: fixed; + } + } +} + +// ---------------------------------------------------------------------------- + +// Grid container - this class is applied to wrapper elements within the +// header, content area and footer, and makes sure that their width is limited +// to `1220px`, and they are rendered centered if the screen is larger. +.md-grid { + max-width: px2rem(1220px); + margin-inline: auto; +} + +// Main container +.md-container { + display: flex; + flex-grow: 1; + flex-direction: column; + + // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m) + @media print { + display: block; + } +} + +// Main area - stretch to remaining space of container +.md-main { + flex-grow: 1; + + // Main area wrapper + &__inner { + display: flex; + height: 100%; + margin-top: px2rem(24px + 6px); + } +} + +// Add ellipsis in case of overflowing text +.md-ellipsis { + overflow: hidden; + text-overflow: ellipsis; +} + +// ---------------------------------------------------------------------------- +// Rules: navigational elements +// ---------------------------------------------------------------------------- + +// Toggle - this class is applied to checkbox elements, which are used to +// implement the CSS-only drawer and navigation, as well as the search +.md-toggle { + display: none; +} + +// Option - this class is applied to radio elements, which are used to +// implement the color palette toggle +.md-option { + position: absolute; + width: 0; + height: 0; + opacity: 0; + + // Option label for checked radio button + &:checked + label:not([hidden]) { + display: block; + } + + // Show outline for keyboard devices + &.focus-visible + label { + outline-style: auto; + outline-color: var(--md-accent-fg-color); + } +} + +// Skip link +.md-skip { + position: fixed; + // Hack: if we don't set the negative `z-index`, the skip link will force the + // creation of new layers when code blocks are near the header on scrolling + z-index: -1; + padding: px2rem(6px) px2rem(10px); + margin: px2rem(10px); + font-size: px2rem(12.8px); + color: var(--md-default-bg-color); + background-color: var(--md-default-fg-color); + border-radius: px2rem(2px); + outline-color: var(--md-accent-fg-color); + opacity: 0; + transform: translateY(px2rem(8px)); + + // Show skip link on focus + &:focus { + z-index: 10; + opacity: 1; + transition: + transform 250ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 175ms 75ms; + transform: translateY(0); + } +} + +// ---------------------------------------------------------------------------- +// Rules: print styles +// ---------------------------------------------------------------------------- + +// Add margins to page +@page { + margin: 25mm; +} diff --git a/stylesheets/main/components/_clipboard.scss b/stylesheets/main/components/_clipboard.scss new file mode 100644 index 0000000..1d64879 --- /dev/null +++ b/stylesheets/main/components/_clipboard.scss @@ -0,0 +1,102 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Clipboard button variables +:root { + --md-clipboard-icon: svg-load("material/content-copy.svg"); +} + +// ---------------------------------------------------------------------------- + +// Clipboard button +.md-clipboard { + position: absolute; + top: px2em(8px); + right: px2em(8px); + z-index: 1; + width: px2em(24px); + height: px2em(24px); + color: var(--md-default-fg-color--lightest); + cursor: pointer; + border-radius: px2rem(2px); + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(2px); + transition: color 250ms; + + // [print]: Hide button + @media print { + display: none; + } + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Darken color on code block hover + :hover > & { + color: var(--md-default-fg-color--light); + } + + // Button on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Button icon - the width and height are defined in `em`, so the size is + // automatically adjusted for nested code blocks (e.g. in admonitions) + &::after { + display: block; + width: px2em(18px); + height: px2em(18px); + margin: 0 auto; + content: ""; + background-color: currentcolor; + mask-image: var(--md-clipboard-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + // Inline clipboard button + &--inline { + cursor: pointer; + + // Code block + code { + transition: + color 250ms, + background-color 250ms; + } + + // Code block on focus/hover + &:is(:focus, :hover) code { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + } + } +} diff --git a/stylesheets/main/components/_code.scss b/stylesheets/main/components/_code.scss new file mode 100644 index 0000000..78fd71d --- /dev/null +++ b/stylesheets/main/components/_code.scss @@ -0,0 +1,35 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Code blocks +.md-code { + + // Code block content - when line spans are enabled, we can opt into using + // grid-based rendering, which makes highlighted lines stretch. + .md-typeset &__content { + display: grid; + } +} diff --git a/stylesheets/main/components/_consent.scss b/stylesheets/main/components/_consent.scss new file mode 100644 index 0000000..e060746 --- /dev/null +++ b/stylesheets/main/components/_consent.scss @@ -0,0 +1,127 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// Show consent +@keyframes consent { + 0% { + opacity: 0; + transform: translateY(100%); + } + + 100% { + opacity: 1; + transform: translateY(0); + } +} + +// Show consent overlay +@keyframes overlay { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Consent +.md-consent { + + // Consent overlay + &__overlay { + position: fixed; + top: 0; + z-index: 5; + width: 100%; + height: 100%; + background-color: hsla(0, 0%, 0%, 0.54); + backdrop-filter: blur(px2rem(2px)); + opacity: 1; + animation: overlay 250ms both; + } + + // Consent wrapper + &__inner { + position: fixed; + bottom: 0; + z-index: 5; + width: 100%; + max-height: 100%; + padding: 0; + overflow: auto; + background-color: var(--md-default-bg-color); + border: 0; + border-radius: px2rem(2px); + box-shadow: + 0 0 px2rem(4px) rgba(0, 0, 0, 0.1), + 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0.2); + animation: consent 500ms cubic-bezier(0.1, 0.7, 0.1, 1) both; + } + + // Consent form + &__form { + padding: px2rem(16px); + } + + // Consent settings + &__settings { + display: none; + margin: 1em 0; + + // Show settings + input:checked + & { + display: block; + } + } + + // Consent controls + &__controls { + margin-bottom: px2rem(16px); + + // Consent control button + .md-typeset & .md-button { + display: inline; + + // [tablet +]: Align buttons horizontally + @include break-to-device(mobile) { + display: block; + width: 100%; + margin-top: px2rem(8px); + text-align: center; + } + } + } + + // Ensure users realize that labels are clickaböe + label { + cursor: pointer; + } +} diff --git a/stylesheets/main/components/_content.scss b/stylesheets/main/components/_content.scss new file mode 100644 index 0000000..774e726 --- /dev/null +++ b/stylesheets/main/components/_content.scss @@ -0,0 +1,97 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Content area +.md-content { + flex-grow: 1; + // Hack: we must use `min-width: 0`, so the content area is capped by the + // dimensions of its parent. Otherwise, long code blocks might lead to a + // wider content area which will overflow. See https://bit.ly/3bP3f8k + min-width: 0; + + // Content wrapper + &__inner { + padding-top: px2rem(12px); + margin: 0 px2rem(16px) px2rem(24px); + + // [screen +]: Adjust spacing between content area and sidebars + @include break-from-device(screen) { + + // Sidebar with navigation is visible + .md-sidebar--primary:not([hidden]) ~ .md-content > & { + margin-inline-start: px2rem(24px); + } + + // Sidebar with table of contents is visible + .md-sidebar--secondary:not([hidden]) ~ .md-content > & { + margin-inline-end: px2rem(24px); + } + } + + // Hack: add pseudo element for spacing, as the overflow of the content + // container may not be hidden due to an imminent offset error on targets + &::before { + display: block; + height: px2rem(8px); + content: ""; + } + + // Adjust spacing on last child + > :last-child { + margin-bottom: 0; + } + } + + // Button inside of the content area - these buttons are meant for actions on + // a document-level, i.e. linking to related source code files, printing etc. + &__button { + float: inline-end; + padding: 0; + margin: px2rem(8px) 0; + margin-inline-start: px2rem(8px); + + // [print]: Hide buttons + @media print { + display: none; + } + + // Adjust default link color for icons + .md-typeset & { + color: var(--md-default-fg-color--lighter); + } + + // Align with body copy located next to icon + svg { + display: inline; + vertical-align: top; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: scaleX(-1); + } + } + } +} diff --git a/stylesheets/main/components/_dialog.scss b/stylesheets/main/components/_dialog.scss new file mode 100644 index 0000000..cb1b055 --- /dev/null +++ b/stylesheets/main/components/_dialog.scss @@ -0,0 +1,65 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Dialog +.md-dialog { + position: fixed; + inset-inline-end: px2rem(16px); + bottom: px2rem(16px); + z-index: 4; + min-width: px2rem(222px); + padding: px2rem(8px) px2rem(12px); + pointer-events: none; + background-color: var(--md-default-fg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z3); + opacity: 0; + transition: + transform 0ms 400ms, + opacity 400ms; + transform: translateY(100%); + + // [print]: Hide dialog + @media print { + display: none; + } + + // Active dialog + &--active { + pointer-events: initial; + opacity: 1; + transition: + transform 400ms cubic-bezier(0.075, 0.85, 0.175, 1), + opacity 400ms; + transform: translateY(0); + } + + // Dialog wrapper + &__inner { + font-size: px2rem(14px); + color: var(--md-default-bg-color); + } +} diff --git a/stylesheets/main/components/_feedback.scss b/stylesheets/main/components/_feedback.scss new file mode 100644 index 0000000..a2cb533 --- /dev/null +++ b/stylesheets/main/components/_feedback.scss @@ -0,0 +1,114 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Was this page helpful? +.md-feedback { + margin: 2em 0 1em; + text-align: center; + + // Feedback fieldset + fieldset { + padding: 0; + margin: 0; + border: none; + } + + // Feedback title + &__title { + margin: 1em auto; + font-weight: 700; + } + + // Feedback wrapper + &__inner { + position: relative; + } + + // Feedback list + &__list { + position: relative; + display: flex; + flex-wrap: wrap; + place-content: baseline center; + + // Feedback icon on hover + &:hover .md-icon:not(:disabled) { + color: var(--md-default-fg-color--lighter); + } + + // Adjust height after submission + :disabled & { + min-height: px2rem(36px); + } + } + + // Feedback icon + &__icon { + flex-shrink: 0; + margin: 0 px2rem(2px); + color: var(--md-default-fg-color--light); + cursor: pointer; + transition: color 125ms; + + // Feedback icon on hover + &:not(:disabled).md-icon:hover { + color: var(--md-accent-fg-color); + } + + // Feedback icon after submit + &:disabled { + color: var(--md-default-fg-color--lightest); + pointer-events: none; + } + } + + // Feedback note + &__note { + position: relative; + opacity: 0; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + transform: translateY(px2rem(8px)); + + // Feedback note value + > * { + max-width: px2rem(320px); + margin: 0 auto; + } + + // Show after submission + :disabled & { + opacity: 1; + transform: translateY(0); + } + } + + // [print]: Hide feedback + @media print { + display: none; + } +} diff --git a/stylesheets/main/components/_footer.scss b/stylesheets/main/components/_footer.scss new file mode 100644 index 0000000..e3e51b9 --- /dev/null +++ b/stylesheets/main/components/_footer.scss @@ -0,0 +1,201 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Footer +.md-footer { + color: var(--md-footer-fg-color); + background-color: var(--md-footer-bg-color); + + // [print]: Hide footer + @media print { + display: none; + } + + // Footer wrapper + &__inner { + justify-content: space-between; + padding: px2rem(4px); + overflow: auto; + + // Footer is visible + &:not([hidden]) { + display: flex; + } + } + + // Footer link to previous and next page + &__link { + display: flex; + // Hack: some browsers induce ellipsis on flex children that are set to + // `overflow: hidden` and `text-overflow: ellipsis`. Enforcing growth by + // a tiny factor seems to get rid of the ellipsis and renders the text as + // it should - see https://bit.ly/2ZUCXQ8 + flex-grow: 0.01; + align-items: end; + max-width: 100%; + margin-block: px2rem(20px) px2rem(8px); + overflow: hidden; + outline-color: var(--md-accent-fg-color); + transition: opacity 250ms; + + // Footer link on focus/hover + &:is(:focus, :hover) { + opacity: 0.7; + } + + // Adjust for right-to-left languages + [dir="rtl"] & svg { + transform: scaleX(-1); + } + + // [mobile -]: Adjust width to 25/75 and hide title + @include break-to-device(mobile) { + + // Footer link to previous page + &--prev { + flex-shrink: 0; + + // Hide footer title + .md-footer__title { + display: none; + } + } + } + + // Footer link to next page + &--next { + margin-inline-start: auto; + text-align: right; + + // Adjust for right-to-left languages + [dir="rtl"] & { + text-align: left; + } + } + } + + // Footer title + &__title { + flex-grow: 1; + max-width: calc(100% - #{px2rem(48px)}); + padding: 0 px2rem(20px); + margin-bottom: px2rem(14px); + font-size: px2rem(18px); + white-space: nowrap; + } + + // Footer link button + &__button { + padding: px2rem(8px); + margin: px2rem(4px); + } + + // Footer link direction (i.e. prev and next) + &__direction { + font-size: px2rem(12.8px); + opacity: 0.7; + } +} + +// Footer metadata +.md-footer-meta { + background-color: var(--md-footer-bg-color--dark); + + // Footer metadata wrapper + &__inner { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + padding: px2rem(4px); + } + + // Lighten color for non-hovered text links + html &.md-typeset a { + color: var(--md-footer-fg-color--light); + + // Text link on focus/hover + &:is(:focus, :hover) { + color: var(--md-footer-fg-color); + } + } +} + +// ---------------------------------------------------------------------------- + +// Copyright and theme information +.md-copyright { + width: 100%; + padding: px2rem(8px) 0; + margin: auto px2rem(12px); + font-size: px2rem(12.8px); + color: var(--md-footer-fg-color--lighter); + + // [tablet portrait +]: Show copyright and social links in one line + @include break-from-device(tablet portrait) { + width: auto; + } + + // Footer copyright highlight - this is the upper part of the copyright and + // theme information, which will include a darker color than the theme link + &__highlight { + color: var(--md-footer-fg-color--light); + } +} + +// ---------------------------------------------------------------------------- + +// Social links +.md-social { + display: inline-flex; + gap: px2rem(4px); + padding: px2rem(4px) 0 px2rem(12px); + margin: 0 px2rem(8px); + + // [tablet portrait +]: Show copyright and social links in one line + @include break-from-device(tablet portrait) { + padding: px2rem(12px) 0; + } + + // Footer social link + &__link { + display: inline-block; + width: px2rem(32px); + height: px2rem(32px); + text-align: center; + + // Adjust line-height to match height for correct alignment + &::before { + line-height: 1.9; + } + + // Fill icon with current color + svg { + max-height: px2rem(16px); + vertical-align: -25%; + fill: currentcolor; + } + } +} diff --git a/stylesheets/main/components/_form.scss b/stylesheets/main/components/_form.scss new file mode 100644 index 0000000..92449d7 --- /dev/null +++ b/stylesheets/main/components/_form.scss @@ -0,0 +1,83 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Form button + .md-button { + display: inline-block; + padding: px2em(10px) px2em(32px); + font-weight: 700; + color: var(--md-primary-fg-color); + cursor: pointer; + border: px2rem(2px) solid currentcolor; + border-radius: px2rem(2px); + transition: + color 125ms, + background-color 125ms, + border-color 125ms; + + // Primary button + &--primary { + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + border-color: var(--md-primary-fg-color); + } + + // Button on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-bg-color); + background-color: var(--md-accent-fg-color); + border-color: var(--md-accent-fg-color); + } + } + + // Form input + .md-input { + height: px2rem(36px); + padding: 0 px2rem(12px); + font-size: px2rem(16px); + border-bottom: px2rem(2px) solid var(--md-default-fg-color--lighter); + border-start-start-radius: px2rem(2px); + border-start-end-radius: px2rem(2px); + box-shadow: var(--md-shadow-z1); + transition: + border 250ms, + box-shadow 250ms; + + // Input on focus/hover + &:is(:focus, :hover) { + border-bottom-color: var(--md-accent-fg-color); + box-shadow: var(--md-shadow-z2); + } + + // Stretch to full width + &--stretch { + width: 100%; + } + } +} diff --git a/stylesheets/main/components/_header.scss b/stylesheets/main/components/_header.scss new file mode 100644 index 0000000..13a5e76 --- /dev/null +++ b/stylesheets/main/components/_header.scss @@ -0,0 +1,269 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Header - by default, the header will be sticky and stay always on top of the +// viewport. If this behavior is not desired, just set `position: static`. +.md-header { + position: sticky; + inset-inline: 0; + top: 0; + z-index: 4; + display: block; + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + // Hack: reduce jitter by adding a transparent box shadow of the same size + // so the size of the layer doesn't change during animation + box-shadow: + 0 0 px2rem(4px) rgba(0, 0, 0, 0), + 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0); + + // [print]: Hide header + @media print { + display: none; + } + + // Header is hidden + &[hidden] { + transition: + transform 250ms cubic-bezier(0.8, 0, 0.6, 1), + box-shadow 250ms; + transform: translateY(-100%); + } + + // Header in shadow state, i.e. shadow is visible + &--shadow { + box-shadow: + 0 0 px2rem(4px) rgba(0, 0, 0, 0.1), + 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0.2); + transition: + transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), + box-shadow 250ms; + } + + // Header wrapper + &__inner { + display: flex; + align-items: center; + padding: 0 px2rem(4px); + } + + // Header button + &__button { + position: relative; + z-index: 1; + padding: px2rem(8px); + margin: px2rem(4px); + color: currentcolor; + vertical-align: middle; + cursor: pointer; + outline-color: var(--md-accent-fg-color); + transition: opacity 250ms; + + // Button on hover + &:hover { + opacity: 0.7; + } + + // Header button is visible + &:not([hidden]) { + display: inline-block; + } + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Button with logo, pointing to `config.site_url` + &.md-logo { + padding: px2rem(8px); + margin: px2rem(4px); + + // [tablet -]: Hide button + @include break-to-device(tablet) { + display: none; + } + + // Image or icon + :is(img, svg) { + display: block; + width: auto; + height: px2rem(24px); + fill: currentcolor; + } + } + + // Button for search + &[for="__search"] { + + // [tablet landscape +]: Hide button + @include break-from-device(tablet landscape) { + display: none; + } + + // [no-js]: Hide button + .no-js & { + display: none; + } + + // Adjust for right-to-left languages + [dir="rtl"] & svg { + transform: scaleX(-1); + } + } + + // Button for drawer + &[for="__drawer"] { + + // [screen +]: Hide button + @include break-from-device(screen) { + display: none; + } + } + } + + // Header topic + &__topic { + position: absolute; + display: flex; + max-width: 100%; + white-space: nowrap; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + + // Second header topic - title of the current page + & + & { + z-index: -1; + pointer-events: none; + opacity: 0; + transition: + transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), + opacity 150ms; + transform: translateX(px2rem(25px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(-25px)); + } + } + + // Adjust font weight of site title + &:first-child { + font-weight: 700; + } + } + + // Header title + &__title { + flex-grow: 1; + height: px2rem(48px); + margin-inline: px2rem(20px) px2rem(8px); + font-size: px2rem(18px); + line-height: px2rem(48px); + + // Header title in active state, i.e. page title is visible + &--active .md-header__topic { + z-index: -1; + pointer-events: none; + opacity: 0; + transition: + transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), + opacity 150ms; + transform: translateX(px2rem(-25px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(25px)); + } + + // Second header topic - title of the current page + + .md-header__topic { + z-index: 0; + pointer-events: initial; + opacity: 1; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + transform: translateX(0); + } + } + + // Add ellipsis in case of overflowing text + > .md-header__ellipsis { + position: relative; + width: 100%; + height: 100%; + } + } + + // Header option + &__option { + display: flex; + flex-shrink: 0; + max-width: 100%; + white-space: nowrap; + transition: + max-width 0ms 250ms, + opacity 250ms 250ms; + + // Hide toggle when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + max-width: 0; + opacity: 0; + transition: + max-width 0ms, + opacity 0ms; + } + + // Hack: Firefox 117 introduces a bug where the browser scrolls the page by + // a small amount to the top every time the header button is focused. After + // investigating, we're confident that it seems to be caused by the input + // field being too close to the border - see https://t.ly/APO8l + > input { + bottom: 0; + } + } + + // Repository information container + &__source { + display: none; + + // [tablet landscape +]: Show repository information + @include break-from-device(tablet landscape) { + display: block; + width: px2rem(234px); + max-width: px2rem(234px); + margin-inline-start: px2rem(20px); + } + + // [screen +]: Adjust spacing of search bar + @include break-from-device(screen) { + margin-inline-start: px2rem(28px); + } + } +} diff --git a/stylesheets/main/components/_meta.scss b/stylesheets/main/components/_meta.scss new file mode 100644 index 0000000..4848a26 --- /dev/null +++ b/stylesheets/main/components/_meta.scss @@ -0,0 +1,67 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Metadata +.md-meta { + font-size: px2rem(14px); + line-height: 1.3; + color: var(--md-default-fg-color--light); + + // Metadata list + &__list { + display: inline-flex; + flex-wrap: wrap; + padding: 0; + margin: 0; + list-style: none; + } + + // Metadata item separator + &__item:not(:last-child)::after { + margin-inline: px2rem(4px); + content: "·"; + } + + // Metadata link + &__link { + color: var(--md-typeset-a-color); + + // Metadata link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + } +} + +// Draft +.md-draft { + display: inline-block; + padding-inline: px2em(8px, 14px); + font-weight: 700; + color: hsla(255, 100%, 100%); + background-color: $clr-red-a400; + border-radius: px2em(2px); +} diff --git a/stylesheets/main/components/_nav.scss b/stylesheets/main/components/_nav.scss new file mode 100644 index 0000000..2414b46 --- /dev/null +++ b/stylesheets/main/components/_nav.scss @@ -0,0 +1,759 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Navigation variables +:root { + --md-nav-icon--prev: svg-load("material/arrow-left.svg"); + --md-nav-icon--next: svg-load("material/chevron-right.svg"); + --md-toc-icon: svg-load("material/table-of-contents.svg"); +} + +// ---------------------------------------------------------------------------- + +// Navigation +.md-nav { + font-size: px2rem(14px); + line-height: 1.3; + + // Navigation title + &__title { + display: block; + padding: 0 px2rem(12px); + overflow: hidden; + font-weight: 700; + color: var(--md-default-fg-color--light); + text-overflow: ellipsis; + + // Navigaton button + .md-nav__button { + display: none; + + // Stretch images based on height, as it's the smaller dimension + img { + width: auto; + height: 100%; + } + + // Button with logo, pointing to `config.site_url` + &.md-logo { + + // Image or icon + :is(img, svg) { + display: block; + width: auto; + max-width: 100%; + height: px2rem(48px); + object-fit: contain; + fill: currentcolor; + } + } + } + } + + // Navigation list + &__list { + padding: 0; + margin: 0; + list-style: none; + } + + // Navigation link + &__link { + display: flex; + gap: px2rem(8px); + align-items: flex-start; + margin-top: 0.625em; + scroll-snap-align: start; + transition: color 125ms; + + // Navigation link that was passed + &--passed { + color: var(--md-default-fg-color--light); + } + + // Active link + .md-nav__item &--active { + + // Also enable color transitions on inline code blocks + &, + code { + color: var(--md-typeset-a-color); + } + } + + // Navigation link title + .md-ellipsis { + // Hack: Safari exhibits a bug where the text will sometimes disappear + // and the element will become unclickable. Setting `position: relative` + // seems to fix the issue - see https://bit.ly/3HljM1T + position: relative; + } + + // Always align navigation icons to the end + .md-icon:last-child { + margin-inline-start: auto; + } + + // Navigation link icon + svg { + // Hack: Safari has another bug where SVGs disappear on hover - same fix + // as above via `position: relative` - see https://t.ly/5fSj1 + position: relative; + flex-shrink: 0; + height: 1.3em; + fill: currentcolor; + } + + // Navigation link on focus/hover + &:is([href], [for]):is(:focus, :hover) { + color: var(--md-accent-fg-color); + cursor: pointer; + } + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + + // Navigation link for table of contents + .md-nav--primary &[for="__toc"] { + display: none; + + // Table of contents icon + .md-icon::after { + display: block; + width: 100%; + height: 100%; + background-color: currentcolor; + mask-image: var(--md-toc-icon); + } + + // Hide table of contents + ~ .md-nav { + display: none; + } + } + } + + // Navigation container (for section index pages) + &__container > .md-nav__link { + margin-top: 0; + + // Stretch first child + &:first-child { + flex-grow: 1; + // Hack: if a very long word is used, it can push the arrow out of sight. + // Setting this property contains the text - see https://t.ly/E02vp + min-width: 0; + } + } + + // Navigation icon + &__icon { + flex-shrink: 0; + } + + // Repository information container + &__source { + display: none; + } + + // [tablet -]: Layered navigation + @include break-to-device(tablet) { + + // Primary and nested navigation + &--primary, + &--primary & { + position: absolute; + inset-inline: 0; + top: 0; + z-index: 1; + display: flex; + flex-direction: column; + height: 100%; + background-color: var(--md-default-bg-color); + } + + // Primary navigation + &--primary { + + // Navigation title and item + :is(.md-nav__title, .md-nav__item) { + font-size: px2rem(16px); + line-height: 1.5; + } + + // Navigation title + .md-nav__title { + position: relative; + height: px2rem(112px); + padding: px2rem(60px) px2rem(16px) px2rem(4px); + line-height: px2rem(48px); + color: var(--md-default-fg-color--light); + white-space: nowrap; + cursor: pointer; + background-color: var(--md-default-fg-color--lightest); + + // Navigation icon + .md-nav__icon { + position: absolute; + inset-inline-start: px2rem(8px); + top: px2rem(8px); + display: block; + width: px2rem(24px); + height: px2rem(24px); + margin: px2rem(4px); + + // Navigation icon in link to previous level + &::after { + display: block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + mask-image: var(--md-nav-icon--prev); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + } + + // Navigation list + ~ .md-nav__list { + overflow-y: auto; + touch-action: pan-y; + scroll-snap-type: y mandatory; + background-color: var(--md-default-bg-color); + box-shadow: + 0 px2rem(1px) 0 var(--md-default-fg-color--lightest) inset; + + // Omit border on first child + > :first-child { + border-top: 0; + } + } + + // Top-level navigation title + &[for="__drawer"] { + font-weight: 700; + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + } + + // Button with logo, pointing to `config.site_url` + .md-logo { + position: absolute; + inset-inline: px2rem(4px); + top: px2rem(4px); + display: block; + padding: px2rem(8px); + margin: px2rem(4px); + } + } + + // Navigation list + .md-nav__list { + flex: 1; + } + + // Navigation item + .md-nav__item { + border-top: px2rem(1px) solid var(--md-default-fg-color--lightest); + + // Navigation link in active navigation + &--active > .md-nav__link { + color: var(--md-typeset-a-color); + + // Navigation link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + } + } + + // Navigation link + .md-nav__link { + padding: px2rem(12px) px2rem(16px); + margin-top: 0; + + // Navigation link icon + svg { + margin-top: 0.1em; + } + + // Adjust spacing on nested link + > .md-nav__link { + padding: 0; + } + + // Navigation icon + .md-nav__icon { + width: px2rem(24px); + height: px2rem(24px); + margin-inline-end: px2rem(-4px); + font-size: px2rem(24px); + + // Navigation icon in link to next level + &::after { + display: block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + mask-image: var(--md-nav-icon--next); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + } + } + + // Flip icon vertically + .md-nav__icon { + + // Adjust for right-to-left languages + [dir="rtl"] &::after { + transform: scale(-1); + } + } + + // Table of contents contained in primary navigation + .md-nav--secondary { + + // Navigation on level 2-6 + .md-nav { + position: static; + background-color: transparent; + + // Navigation link on level 3 + .md-nav__link { + padding-inline-start: px2rem(28px); + } + + // Navigation link on level 4 + .md-nav .md-nav__link { + padding-inline-start: px2rem(40px); + } + + // Navigation link on level 5 + .md-nav .md-nav .md-nav__link { + padding-inline-start: px2rem(52px); + } + + // Navigation link on level 6 + .md-nav .md-nav .md-nav .md-nav__link { + padding-inline-start: px2rem(64px); + } + } + } + } + + // Table of contents + &--secondary { + background-color: transparent; + } + + // Hide nested navigation + &__toggle ~ & { + display: flex; + opacity: 0; + transition: + transform 250ms cubic-bezier(0.8, 0, 0.6, 1), + opacity 125ms 50ms; + transform: translateX(100%); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(-100%); + } + } + + // Show nested navigation when toggle is active + &__toggle:checked ~ & { + opacity: 1; + transition: + transform 250ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 125ms 125ms; + transform: translateX(0); + + // Navigation list + > .md-nav__list { + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + } + } + } + + // [tablet portrait -]: Layered navigation with table of contents + @include break-to-device(tablet portrait) { + + // Show link to table of contents + &--primary &__link[for="__toc"] { + display: flex; + + // Show table of contents icon + .md-icon::after { + content: ""; + } + + // Hide navigation link to current page + + .md-nav__link { + display: none; + } + + // Show table of contents + ~ .md-nav { + display: flex; + } + } + + // Repository information container + &__source { + display: block; + padding: 0 px2rem(4px); + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color--dark); + } + } + + // [tablet landscape]: Layered navigation with table of contents + @include break-at-device(tablet landscape) { + + // Show link to integrated table of contents + &--integrated &__link[for="__toc"] { + display: flex; + + // Show table of contents icon + .md-icon::after { + content: ""; + } + + // Hide navigation link to current page + + .md-nav__link { + display: none; + } + + // Show table of contents + ~ .md-nav { + display: flex; + } + } + } + + // [tablet landscape +]: Tree-like table of contents + @include break-from-device(tablet landscape) { + margin-bottom: px2rem(-8px); + + // Table of contents + &--secondary { + + // Navigation title + .md-nav__title { + position: sticky; + top: 0; + // Hack: because of the hack that we need to make .md-ellipsis work in + // Safari, we need to set `z-index` here as - see https://bit.ly/3s5M2jm + z-index: 1; + background: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(8px) px2rem(8px) var(--md-default-bg-color); + + // Adjust snapping behavior + &[for="__toc"] { + scroll-snap-align: start; + } + + // Hide navigation icon + .md-nav__icon { + display: none; + } + } + + // Adjust spacing for navigation list - same reason as below + .md-nav__list { + padding-inline-start: px2rem(12px); + padding-bottom: px2rem(8px); + } + + // Adjust spacing for navigation link - before this change, we set spacing + // on the left and right of a navigation item, but this led to the problem + // of cropped focus outlines, because we must set `overflow: hidden` on + // the navigation list for smooth expand and collapse transitions. + .md-nav__item > .md-nav__link { + margin-inline-end: px2rem(8px); + } + } + } + + // [screen +]: Tree-like navigation + @include break-from-device(screen) { + margin-bottom: px2rem(-8px); + transition: max-height 250ms cubic-bezier(0.86, 0, 0.07, 1); + + // Primary navigation + &--primary { + + // Navigation title + .md-nav__title { + position: sticky; + top: 0; + // Hack: because of the hack that we need to make .md-ellipsis work in + // Safari, we need to set `z-index` here as - see https://bit.ly/3s5M2jm + z-index: 1; + background: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(8px) px2rem(8px) var(--md-default-bg-color); + + // Adjust snapping behavior + &[for="__drawer"] { + scroll-snap-align: start; + } + + // Hide navigation icon + .md-nav__icon { + display: none; + } + } + + // Adjust spacing for navigation list - same reason as below + .md-nav__list { + padding-inline-start: px2rem(12px); + padding-bottom: px2rem(8px); + } + + // Adjust spacing for navigation link - before this change, we set spacing + // on the left and right of a navigation item, but this led to the problem + // of cropped focus outlines, because we must set `overflow: hidden` on + // the navigation list for smooth expand and collapse transitions. + .md-nav__item > .md-nav__link { + margin-inline-end: px2rem(8px); + } + } + + // Hide nested navigation + &__toggle ~ & { + display: grid; + grid-template-rows: 0fr; + visibility: collapse; + opacity: 0; + transition: + grid-template-rows 250ms cubic-bezier(0.86, 0, 0.07, 1), + opacity 250ms, + visibility 0ms 250ms; + + // Navigation list + > .md-nav__list { + overflow: hidden; + } + } + + // Show nested navigation when toggle is active or indeterminate + &__toggle:is(:checked, .md-toggle--indeterminate) ~ & { + grid-template-rows: 1fr; + visibility: visible; + opacity: 1; + transition: + grid-template-rows 250ms cubic-bezier(0.86, 0, 0.07, 1), + opacity 150ms 100ms, + visibility 0ms; + } + + // Disable transition for expanded navigation + &__toggle.md-toggle--indeterminate ~ & { + transition: none; + } + + // Hide navigation title in nested navigation + &__item--nested > & > &__title { + display: none; + } + + // Navigation section + &__item--section { + display: block; + margin: 1.25em 0; + + // Adjust spacing on last child + &:last-child { + margin-bottom: 0; + } + + // Show navigation link as title + > .md-nav__link { + font-weight: 700; + + // Make labels discernable from links + &[for] { + color: var(--md-default-fg-color--light); + } + + // Omit clicks if not a section index page + &:not(.md-nav__container) { + pointer-events: none; + } + + // Hide navigation icon + > [for], + .md-icon { + display: none; + } + } + + // Navigation + > .md-nav { + display: block; + margin-inline-start: px2rem(-12px); + visibility: visible; + opacity: 1; + + // Adjust spacing on next level item + > .md-nav__list > .md-nav__item { + padding: 0; + } + } + } + + // Navigation icon + &__icon { + width: px2rem(18px); + height: px2rem(18px); + border-radius: 100%; + transition: background-color 250ms; + + // Navigation icon on hover + &:hover { + background-color: var(--md-accent-fg-color--transparent); + } + + // Navigation icon content + &::after { + display: inline-block; + width: 100%; + height: 100%; + vertical-align: px2rem(-2px); + content: ""; + background-color: currentcolor; + border-radius: 100%; + mask-image: var(--md-nav-icon--next); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + transition: transform 250ms; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: rotate(180deg); + } + + // Navigation icon - rotate icon when toggle is active or indeterminate + .md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link &, + .md-nav__item--nested .md-toggle--indeterminate ~ .md-nav__link & { + transform: rotate(90deg); + } + } + } + + // Modifier for when navigation tabs are rendered + &--lifted { + + // Hide site title + > .md-nav__title { + display: none; + } + + // Hide level 0 navigation items + > .md-nav__list > .md-nav__item { + display: none; + + // Active parent navigation item + &--active { + display: block; + + // Show navigation link as title + > .md-nav__link { + position: sticky; + top: 0; + z-index: 1; + margin-top: 0; + background: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(8px) px2rem(8px) var(--md-default-bg-color); + + // Omit clicks if not a section index page + &:not(.md-nav__container) { + pointer-events: none; + } + } + + // Adjust spacing for navigation section + &.md-nav__item--section { + margin: 0; + } + } + + // Adjust spacing for nested navigation + > .md-nav:not(.md-nav--secondary) { + margin-inline-start: px2rem(-12px); + } + + // Make labels discernable from links + > [for] { + color: var(--md-default-fg-color--light); + } + } + + // Hack: Always show active navigation tab on breakpoint screen, despite + // of checkbox being checked or not - see https://t.ly/Qc311 + .md-nav[data-md-level="1"] { + grid-template-rows: 1fr; + visibility: visible; + opacity: 1; + } + } + + // Modifier for when table of contents is rendered in primary navigation + &--integrated > .md-nav__list > .md-nav__item--active { + + // Show integrated table of contents + .md-nav--secondary { + display: block; + margin-bottom: 1.25em; + visibility: visible; + border-inline-start: px2rem(1px) solid var(--md-primary-fg-color); + opacity: 1; + + // Navigation list + > .md-nav__list { + padding-bottom: 0; + overflow: visible; + } + + // Hide table of contents title + > .md-nav__title { + display: none; + } + } + } + } +} diff --git a/stylesheets/main/components/_pagination.scss b/stylesheets/main/components/_pagination.scss new file mode 100644 index 0000000..54ca4f3 --- /dev/null +++ b/stylesheets/main/components/_pagination.scss @@ -0,0 +1,85 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Pagination +.md-pagination { + display: flex; + gap: px2rem(8px); + align-items: center; + justify-content: center; + font-size: px2rem(16px); + font-weight: 700; + + // Pagination item + > * { + display: flex; + align-items: center; + justify-content: center; + min-width: px2rem(36px); + height: px2rem(36px); + text-align: center; + border-radius: px2rem(4px); + } + + // Active pagination item + &__current { + color: var(--md-default-fg-color--light); + background-color: var(--md-default-fg-color--lightest); + } + + // Pagination link + &__link { + transition: + color 125ms, + background-color 125ms; + + // Pagination link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + + // Pagination icon + svg { + color: var(--md-accent-fg-color); + } + } + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + + // Pagination icon + svg { + display: block; + width: px2rem(24px); + max-height: 100%; + color: var(--md-default-fg-color--lighter); + fill: currentcolor; + } + } +} diff --git a/stylesheets/main/components/_post.scss b/stylesheets/main/components/_post.scss new file mode 100644 index 0000000..cc72f04 --- /dev/null +++ b/stylesheets/main/components/_post.scss @@ -0,0 +1,202 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Post +.md-post { + + // Post backlink + &__back { + padding-bottom: px2rem(24px); + margin-bottom: px2rem(24px); + border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest); + + // [tablet -]: Hide post backlink + @include break-to-device(tablet) { + display: none; + } + + // Adjust for right-to-left languages + [dir="rtl"] & { + + // Flip icon vertically + svg { + transform: scaleX(-1); + } + } + } + + // Post authors + &__authors { + display: flex; + flex-direction: column; + gap: px2rem(12px); + margin: 0 px2rem(12px) px2rem(24px); + } + + // Post metadata + .md-post__meta { + + // Navigation link + a { + transition: color 125ms; + + // Navigation link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + } + } + + // Post navigation title @todo - generalize + &__title { + font-weight: 700; + color: var(--md-default-fg-color--light); + } + + // Post excerpt + &--excerpt { + margin-bottom: px2rem(64px); + + // Post excerpt header + .md-post__header { + display: flex; + gap: px2rem(12px); + align-items: center; + min-height: px2rem(32px); + } + + // Post excerpt authors + .md-post__authors { + display: inline-flex; + flex-direction: row; + gap: px2rem(4px); + align-items: center; + min-height: px2rem(48px); + margin: 0; + } + + // Post excerpt metadata + .md-post__meta .md-meta__list { + margin-inline-end: px2rem(8px); + } + + // Post excerpt content + .md-post__content > :first-child { + --md-scroll-margin: #{px2rem(120px)}; + + margin-top: 0; + } + } + + // Add margin to table of contents + > .md-nav--secondary { + margin: 1em 0; + } +} + +// ---------------------------------------------------------------------------- + +// Post author profile +.md-profile { + display: flex; + gap: px2rem(12px); + align-items: center; + width: 100%; + font-size: px2rem(14px); + line-height: 1.4; + + // Post author description + &__description { + flex-grow: 1; + } +} + +// ---------------------------------------------------------------------------- + +// Content area for post +.md-content--post { + display: flex; + + // [tablet -]: Switch to inverted column layout + @include break-to-device(tablet) { + flex-flow: column-reverse; + } + + // Content wrapper + > .md-content__inner { + min-width: 0; + + // [screen +]: Adjust spacing between content area and sidebars + @include break-from-device(screen) { + margin-inline-start: px2rem(24px); + } + } +} + +// Sidebar for post +.md-sidebar.md-sidebar--post { + + // [tablet -]: Adjust spacing + @include break-to-device(tablet) { + position: initial; + width: 100%; + padding: 0; + + .md-sidebar__scrollwrap { + overflow: visible; + } + + .md-sidebar__inner { + padding: 0; + } + + .md-post__meta { + margin-inline: px2rem(12px); + } + + .md-nav__item { + display: inline; + border: none; + } + + .md-nav__list { + display: inline-flex; + flex-wrap: wrap; + gap: px2rem(12px); + padding-block: px2rem(12px); + } + + .md-nav__link { + padding: 0; + } + + .md-nav { + position: initial; + height: auto; + margin-bottom: 0; + } + } +} diff --git a/stylesheets/main/components/_progress.scss b/stylesheets/main/components/_progress.scss new file mode 100644 index 0000000..7e5202a --- /dev/null +++ b/stylesheets/main/components/_progress.scss @@ -0,0 +1,53 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Progress variables +:root { + --md-progress-value: 0; + --md-progress-delay: 400ms; +} + +// ---------------------------------------------------------------------------- + +// Progress indicator +.md-progress { + position: fixed; + top: 0; + z-index: 4; + width: 100%; + height: px2rem(1.5px); + background: var(--md-primary-bg-color); + opacity: + min( + clamp(0, var(--md-progress-value), 1), + clamp(0, 100 - var(--md-progress-value), 1) + ); + transition: + transform 500ms cubic-bezier(0.19, 1, 0.22, 1), + opacity 250ms var(--md-progress-delay); + transform: scaleX(calc(var(--md-progress-value) * 1%)); + transform-origin: left; +} diff --git a/stylesheets/main/components/_search.scss b/stylesheets/main/components/_search.scss new file mode 100644 index 0000000..a517f5c --- /dev/null +++ b/stylesheets/main/components/_search.scss @@ -0,0 +1,707 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Search variables +:root { + --md-search-result-icon: svg-load("material/file-search-outline.svg"); +} + +// ---------------------------------------------------------------------------- + +// Search +.md-search { + position: relative; + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + padding: px2rem(4px) 0; + } + + // [no-js]: Hide search + .no-js & { + display: none; + } + + // Search overlay + &__overlay { + z-index: 1; + opacity: 0; + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + position: absolute; + inset-inline-start: px2rem(-44px); + top: px2rem(-20px); + width: px2rem(40px); + height: px2rem(40px); + overflow: hidden; + pointer-events: none; + background-color: var(--md-default-bg-color); + border-radius: px2rem(20px); + transition: + transform 300ms 100ms, + opacity 200ms 200ms; + transform-origin: center; + + // Show overlay when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + opacity: 1; + transition: + transform 400ms, + opacity 100ms; + } + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + position: fixed; + inset-inline-start: 0; + top: 0; + width: 0; + height: 0; + cursor: pointer; + background-color: hsla(0, 0%, 0%, 0.54); + transition: + width 0ms 250ms, + height 0ms 250ms, + opacity 250ms; + + // Show overlay when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + width: 100%; + // Hack: when the header is translated upon scrolling, a new layer is + // induced, which means that the height will now refer to the height of + // the header, albeit positioning is fixed. This should be mitigated + // in all cases when setting the height to 2x the viewport. + height: 200vh; + opacity: 1; + transition: + width 0ms, + height 0ms, + opacity 250ms; + } + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + + // [mobile portrait -]: Scale up 45 times + @include break-to-device(mobile portrait) { + transform: scale(45); + } + + // [mobile landscape]: Scale up 60 times + @include break-at-device(mobile landscape) { + transform: scale(60); + } + + // [tablet portrait]: Scale up 75 times + @include break-at-device(tablet portrait) { + transform: scale(75); + } + } + } + + // Search wrapper + &__inner { + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + position: fixed; + inset-inline-start: 0; + top: 0; + z-index: 2; + width: 0; + height: 0; + overflow: hidden; + opacity: 0; + transition: + width 0ms 300ms, + height 0ms 300ms, + transform 150ms 150ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 150ms 150ms; + transform: translateX(5%); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(-5%); + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + width: 100%; + height: 100%; + opacity: 1; + transition: + width 0ms 0ms, + height 0ms 0ms, + transform 150ms 150ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms 150ms; + transform: translateX(0); + } + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + position: relative; + float: inline-end; + width: px2rem(234px); + padding: px2rem(2px) 0; + transition: width 250ms cubic-bezier(0.1, 0.7, 0.1, 1); + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + + // [tablet landscape]: Omit overlaying header title + @include break-at-device(tablet landscape) { + width: px2rem(468px); + } + + // [screen +]: Match width of content area + @include break-from-device(screen) { + width: px2rem(688px); + } + } + } + + // Search form + &__form { + position: relative; + z-index: 2; + height: px2rem(48px); + background-color: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(12px) transparent; + transition: + color 250ms, + background-color 250ms; + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + height: px2rem(36px); + background-color: hsla(0, 0%, 0%, 0.26); + border-radius: px2rem(2px); + + // Search form on hover + &:hover { + background-color: hsla(0, 0%, 100%, 0.12); + } + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + color: var(--md-default-fg-color); + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px) px2rem(2px) 0 0; + box-shadow: 0 0 px2rem(12px) hsla(0, 0%, 0%, 0.07); + } + } + + // Search input + &__input { + position: relative; + z-index: 2; + width: 100%; + height: 100%; + padding-inline: px2rem(72px) px2rem(44px); + font-size: px2rem(18px); + text-overflow: ellipsis; + background: transparent; + + // Search placeholder + &::placeholder { + transition: color 250ms; + } + + // Search icon and placeholder + ~ .md-search__icon, + &::placeholder { + color: var(--md-default-fg-color--light); + } + + // Remove the "x" rendered by Internet Explorer + &::-ms-clear { + display: none; + } + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + width: 100%; + height: px2rem(48px); + font-size: px2rem(18px); + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + font-size: px2rem(16px); + color: inherit; + + // Search placeholder + &::placeholder { + color: var(--md-primary-bg-color--light); + } + + // Search icon + + .md-search__icon { + color: var(--md-primary-bg-color); + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + text-overflow: clip; + + // Search icon and placeholder + + .md-search__icon { + color: var(--md-default-fg-color--light); + } + + // Search placeholder + &::placeholder { + color: transparent; + } + } + } + } + + // Search icon + &__icon { + display: inline-block; + width: px2rem(24px); + height: px2rem(24px); + cursor: pointer; + transition: + color 250ms, + opacity 250ms; + + // Search icon on hover + &:hover { + opacity: 0.7; + } + + // Search focus button + &[for="__search"] { + position: absolute; + inset-inline-start: px2rem(10px); + top: px2rem(6px); + z-index: 2; + + // Adjust for right-to-left languages + [dir="rtl"] & svg { + transform: scaleX(-1); + } + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + inset-inline-start: px2rem(16px); + top: px2rem(12px); + + // Hide the magnifying glass + svg:first-child { + display: none; + } + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + pointer-events: none; + + // Hide the back arrow + svg:last-child { + display: none; + } + } + } + } + + // Search options + &__options { + position: absolute; + inset-inline-end: px2rem(10px); + top: px2rem(6px); + z-index: 2; + pointer-events: none; + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + inset-inline-end: px2rem(16px); + top: px2rem(12px); + } + + // Search option buttons + > .md-icon { + margin-inline-start: px2rem(4px); + color: var(--md-default-fg-color--light); + opacity: 0; + transition: + transform 150ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + transform: scale(0.75); + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Show buttons when search is active and input non-empty + [data-md-toggle="search"]:checked ~ .md-header // stylelint-disable-line + .md-search__input:valid ~ & { + pointer-events: initial; + opacity: 1; + transform: scale(1); + + // Search focus icon + &:hover { + opacity: 0.7; + } + } + } + } + + // Search suggestions + &__suggest { + position: absolute; + top: 0; + display: flex; + align-items: center; + width: 100%; + height: 100%; + padding-inline: px2rem(72px) px2rem(44px); + font-size: px2rem(18px); + color: var(--md-default-fg-color--lighter); + white-space: nowrap; + opacity: 0; + transition: opacity 50ms; + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + font-size: px2rem(16px); + } + + // Show suggestions when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + opacity: 1; + transition: opacity 300ms 100ms; + } + } + + // Search output + &__output { + position: absolute; + z-index: 1; + width: 100%; + overflow: hidden; + border-end-start-radius: px2rem(2px); + border-end-end-radius: px2rem(2px); + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + top: px2rem(48px); + bottom: 0; + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + top: px2rem(38px); + opacity: 0; + transition: opacity 400ms; + + // Show output when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + box-shadow: var(--md-shadow-z3); + opacity: 1; + } + } + } + + // Search scroll wrapper + &__scrollwrap { + height: 100%; + overflow-y: auto; + // Hack: Chrome 88+ has weird overscroll behavior. Overall, scroll snapping + // seems to be something that is not ready for prime time on some browsers. + // scroll-snap-type: y mandatory; + touch-action: pan-y; + background-color: var(--md-default-bg-color); + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // Mitigiate excessive repaints on non-retina devices + @media (max-resolution: 1dppx) { + transform: translateZ(0); + } + + // [tablet landscape]: Set fixed width to omit unnecessary reflow + @include break-at-device(tablet landscape) { + width: px2rem(468px); + } + + // [screen +]: Set fixed width to omit unnecessary reflow + @include break-from-device(screen) { + width: px2rem(688px); + } + + // [tablet landscape +]: Limit height to viewport + @include break-from-device(tablet landscape) { + max-height: 0; + scrollbar-color: var(--md-default-fg-color--lighter) transparent; + scrollbar-width: thin; + + // Show scroll wrapper when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + max-height: 75vh; + } + + // Search scroll wrapper on hover + &:hover { + scrollbar-color: var(--md-accent-fg-color) transparent; + } + + // Webkit scrollbar + &::-webkit-scrollbar { + width: px2rem(4px); + height: px2rem(4px); + } + + // Webkit scrollbar thumb + &::-webkit-scrollbar-thumb { + background-color: var(--md-default-fg-color--lighter); + + // Webkit scrollbar thumb on hover + &:hover { + background-color: var(--md-accent-fg-color); + } + } + } + } +} + +// Search result +.md-search-result { + color: var(--md-default-fg-color); + word-break: break-word; + + // Search result metadata + &__meta { + padding: 0 px2rem(16px); + font-size: px2rem(12.8px); + line-height: px2rem(36px); + color: var(--md-default-fg-color--light); + scroll-snap-align: start; + background-color: var(--md-default-fg-color--lightest); + + // [tablet landscape +]: Adjust spacing + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + } + } + + // Search result list + &__list { + padding: 0; + margin: 0; + list-style: none; + // Hack: omit accidental text selection on fast toggle of more button + user-select: none; + } + + // Search result item + &__item { + box-shadow: 0 px2rem(-1px) var(--md-default-fg-color--lightest); + + // Omit border on first child + &:first-child { + box-shadow: none; + } + } + + // Search result link + &__link { + display: block; + scroll-snap-align: start; + outline: none; + transition: background-color 250ms; + + // Search result link on focus/hover + &:is(:focus, :hover) { + background-color: var(--md-accent-fg-color--transparent); + } + + // Adjust spacing on last child of last link + &:last-child p:last-child { + margin-bottom: px2rem(12px); + } + } + + // Search result more container + &__more > summary { + position: sticky; + top: 0; + z-index: 1; + display: block; + cursor: pointer; + scroll-snap-align: start; + outline: none; + + // Hide native details marker + &::marker { + display: none; + } + + // Hide native details marker - legacy, must be split into a separate rule, + // so older browsers don't consider the selector list as invalid + &::-webkit-details-marker { + display: none; + } + + // Search result more button + > div { + padding: px2em(12px) px2rem(16px); + font-size: px2rem(12.8px); + color: var(--md-typeset-a-color); + transition: + color 250ms, + background-color 250ms; + + // [tablet landscape +]: Adjust spacing + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + } + } + + // Search result more link on focus/hover + &:is(:focus, :hover) > div { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + } + } + + // Adjust background for more container in open state + &__more[open] > summary { + background-color: var(--md-default-bg-color); + // box-shadow: 0 px2rem(-1px) hsla(0, 0%, 0%, 0.07) inset; + } + + // Search result article + &__article { + position: relative; + padding: 0 px2rem(16px); + overflow: hidden; + + // [tablet landscape +]: Adjust spacing + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + } + } + + // Search result icon + &__icon { + position: absolute; + inset-inline-start: 0; + width: px2rem(24px); + height: px2rem(24px); + margin: px2rem(10px); + color: var(--md-default-fg-color--light); + + // [tablet portrait -]: Hide icon + @include break-to-device(tablet portrait) { + display: none; + } + + // Search result icon content + &::after { + display: inline-block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + mask-image: var(--md-search-result-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: scaleX(-1); + } + } + } + + // Typesetted content + .md-typeset { + font-size: px2rem(12.8px); + line-height: 1.6; + color: var(--md-default-fg-color--light); + + // Search result article title + h1 { + margin: px2rem(11px) 0; + font-size: px2rem(16px); + font-weight: 400; + line-height: 1.4; + color: var(--md-default-fg-color); + + // Search term highlighting + mark { + text-decoration: none; + } + } + + // Search result section title + h2 { + margin: 0.5em 0; + font-size: px2rem(12.8px); + font-weight: 700; + line-height: 1.6; + color: var(--md-default-fg-color); + + // Search term highlighting + mark { + text-decoration: none; + } + } + } + + // Search result terms + &__terms { + display: block; + margin: 0.5em 0; + font-size: px2rem(12.8px); + font-style: italic; + color: var(--md-default-fg-color); + } + + // Search term highlighting + mark { + color: var(--md-accent-fg-color); + text-decoration: underline; + background-color: transparent; + } +} diff --git a/stylesheets/main/components/_select.scss b/stylesheets/main/components/_select.scss new file mode 100644 index 0000000..ccc3d1e --- /dev/null +++ b/stylesheets/main/components/_select.scss @@ -0,0 +1,115 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Selection +.md-select { + position: relative; + z-index: 1; + + // Selection tooltip + &__inner { + position: absolute; + top: calc(100% - #{px2rem(4px)}); + left: 50%; + max-height: 0; + margin-top: px2rem(4px); + color: var(--md-default-fg-color); + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z2); + opacity: 0; + transition: + transform 250ms 375ms, + opacity 250ms 250ms, + max-height 0ms 500ms; + transform: translate3d(-50%, px2rem(6px), 0); + + // Selection bubble on parent focus/hover + .md-select:is(:focus-within, :hover) & { + max-height: px2rem(200px); + opacity: 1; + transition: + transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 250ms, + max-height 0ms; + transform: translate3d(-50%, 0, 0); + } + + // Selection bubble handle + &::after { + position: absolute; + top: 0; + left: 50%; + width: 0; + height: 0; + margin-top: px2rem(-4px); + margin-left: px2rem(-4px); + content: ""; + border: px2rem(4px) solid transparent; + border-top: 0; + border-bottom-color: var(--md-default-bg-color); + } + } + + // Selection list + &__list { + max-height: inherit; + padding: 0; + margin: 0; + overflow: auto; + font-size: px2rem(16px); + list-style-type: none; + border-radius: px2rem(2px); + } + + // Selection item + &__item { + line-height: px2rem(36px); + } + + // Selection link + &__link { + display: block; + width: 100%; + padding-inline: px2rem(12px) px2rem(24px); + cursor: pointer; + scroll-snap-align: start; + outline: none; + transition: + background-color 250ms, + color 250ms; + + // Link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Link on focus + &:focus { + background-color: var(--md-default-fg-color--lightest); + } + } +} diff --git a/stylesheets/main/components/_sidebar.scss b/stylesheets/main/components/_sidebar.scss new file mode 100644 index 0000000..7eb16d7 --- /dev/null +++ b/stylesheets/main/components/_sidebar.scss @@ -0,0 +1,209 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Sidebar +.md-sidebar { + position: sticky; + top: px2rem(48px); + flex-shrink: 0; + align-self: flex-start; + width: px2rem(242px); + padding: px2rem(24px) 0; + + // [print]: Hide sidebar + @media print { + display: none; + } + + // Primary sidebar with navigation + &--primary { + + // [tablet -]: Show navigation as drawer + @include break-to-device(tablet) { + position: fixed; + inset-inline-start: px2rem(-242px); + top: 0; + z-index: 5; + display: block; + width: px2rem(242px); + height: 100%; + background-color: var(--md-default-bg-color); + transition: + transform 250ms cubic-bezier(0.4, 0, 0.2, 1), + box-shadow 250ms; + transform: translateX(0); + + // Show sidebar when drawer is active + [data-md-toggle="drawer"]:checked ~ .md-container & { + box-shadow: var(--md-shadow-z3); + transform: translateX(px2rem(242px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(-242px)); + } + } + + // Stretch scroll wrapper for primary sidebar + .md-sidebar__scrollwrap { + position: absolute; + inset: 0; + margin: 0; + overflow: hidden; + scroll-snap-type: none; + } + } + } + + // [screen +]: Show navigation as sidebar + @include break-from-device(screen) { + height: 0; + + // [no-js]: Switch to native sticky behavior + .no-js & { + height: auto; + } + + // Adjust spacing for sticky navigation tabs + .md-header--lifted ~ .md-container & { + top: px2rem(96px); + } + } + + // Secondary sidebar with table of contents + &--secondary { + display: none; + order: 2; + + // [tablet landscape +]: Show table of contents as sidebar + @include break-from-device(tablet landscape) { + height: 0; + + // [no-js]: Switch to native sticky behavior + .no-js & { + height: auto; + } + + // Sidebar is visible + &:not([hidden]) { + display: block; + } + + // Ensure smooth scrolling on iOS + .md-sidebar__scrollwrap { + touch-action: pan-y; + } + } + } + + // Sidebar scroll wrapper + &__scrollwrap { + margin: 0 px2rem(4px); + overflow-y: auto; + scrollbar-color: var(--md-default-fg-color--lighter) transparent; + scrollbar-gutter: stable; + // Hack: Chrome 81+ exhibits a strange bug, where it scrolls the container + // to the bottom if `scroll-snap-type` is set on the initial render. For + // this reason, we disable scroll snapping until this is resolved (#1667). + // scroll-snap-type: y mandatory; + scrollbar-width: thin; + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // Webkit scrollbar + &::-webkit-scrollbar { + width: px2rem(4px); + height: px2rem(4px); + } + + // Sidebar scroll wrapper on focus/hover + &:is(:focus-within, :hover) { + scrollbar-color: var(--md-accent-fg-color) transparent; + + // Webkit scrollbar thumb + &::-webkit-scrollbar-thumb { + background-color: var(--md-default-fg-color--lighter); + + // Webkit scrollbar thumb on hover + &:hover { + background-color: var(--md-accent-fg-color); + } + } + } + } + + // Hack: the scrollbar is only visible when the sidebar's contents overflow, + // which is nice, but leads to the problem where the chevrons of expandable + // sections will jump by `4px` when the sidebar is shown. We wanted to fix + // this problem for so long, but haven't found a clean way of doing it. + // Until now. The following declaration is only applied to Webkit browsers + // (e.g. Chrome and Safari), which support styling of scrollbars. The trick + // is to add conditional padding on the side of the scrollbar only if the + // sidebar's content doesn't overflow. This hack is inspired and adapted + // from Ayke van Laëthem's year old trick – see https://bit.ly/3Sb1qql + @supports selector(::-webkit-scrollbar) { + + // Sidebar scroll wrapper + &__scrollwrap { + scrollbar-gutter: auto; + } + + // Sidebar wrapper + &__inner { + padding-inline-end: calc(100% - #{px2rem(230px)}); + } + } +} + +// [tablet -]: Show overlay on active drawer +@include break-to-device(tablet) { + + // Drawer overlay + .md-overlay { + position: fixed; + top: 0; + z-index: 5; + width: 0; + height: 0; + background-color: hsla(0, 0%, 0%, 0.54); + opacity: 0; + transition: + width 0ms 250ms, + height 0ms 250ms, + opacity 250ms; + + // Show overlay when drawer is active + [data-md-toggle="drawer"]:checked ~ & { + width: 100%; + height: 100%; + opacity: 1; + transition: + width 0ms, + height 0ms, + opacity 250ms; + } + } +} diff --git a/stylesheets/main/components/_source.scss b/stylesheets/main/components/_source.scss new file mode 100644 index 0000000..e2cb91e --- /dev/null +++ b/stylesheets/main/components/_source.scss @@ -0,0 +1,214 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// Show repository facts +@keyframes facts { + 0% { + height: 0; + } + + 100% { + height: px2rem(13px); + } +} + +// Show repository fact +@keyframes fact { + 0% { + opacity: 0; + transform: translateY(100%); + } + + 50% { + opacity: 0; + } + + 100% { + opacity: 1; + transform: translateY(0%); + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Repository information variables +:root { + --md-source-forks-icon: svg-load("octicons/repo-forked-16.svg"); + --md-source-repositories-icon: svg-load("octicons/repo-16.svg"); + --md-source-stars-icon: svg-load("octicons/star-16.svg"); + --md-source-version-icon: svg-load("octicons/tag-16.svg"); +} + +// ---------------------------------------------------------------------------- + +// Repository information +.md-source { + display: block; + font-size: px2rem(13px); + line-height: 1.2; + white-space: nowrap; + outline-color: var(--md-accent-fg-color); + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + transition: opacity 250ms; + + // Repository information on hover + &:hover { + opacity: 0.7; + } + + // Repository icon + &__icon { + display: inline-block; + width: px2rem(40px); + height: px2rem(48px); + vertical-align: middle; + + // Align with margin only (as opposed to normal button alignment) + svg { + margin-inline-start: px2rem(12px); + margin-top: px2rem(12px); + } + + // Adjust spacing if icon is present + + .md-source__repository { + padding-inline-start: px2rem(40px); + margin-inline-start: px2rem(-40px); + } + } + + // Repository name + &__repository { + display: inline-block; + max-width: calc(100% - #{px2rem(24px)}); + margin-inline-start: px2rem(12px); + overflow: hidden; + text-overflow: ellipsis; + vertical-align: middle; + } + + // Repository facts + &__facts { + display: flex; + gap: px2rem(8px); + width: 100%; + padding: 0; + margin: px2rem(2px) 0 0; + overflow: hidden; + font-size: px2rem(11px); + list-style-type: none; + opacity: 0.75; + + // Show after the data was loaded + .md-source__repository--active & { + animation: facts 250ms ease-in; + } + } + + // Repository fact + &__fact { + overflow: hidden; + text-overflow: ellipsis; + + // Show after the data was loaded + .md-source__repository--active & { + animation: fact 400ms ease-out; + } + + // Repository fact icon + &::before { + display: inline-block; + width: px2rem(12px); + height: px2rem(12px); + margin-inline-end: px2rem(2px); + vertical-align: text-top; + content: ""; + background-color: currentcolor; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + // Adjust spacing for 2nd+ fact + &:nth-child(1n+2) { + flex-shrink: 0; + } + + // Repository fact: version + &--version::before { + mask-image: var(--md-source-version-icon); + } + + // Repository fact: stars + &--stars::before { + mask-image: var(--md-source-stars-icon); + } + + // Repository fact: forks + &--forks::before { + mask-image: var(--md-source-forks-icon); + } + + // Repository fact: repositories + &--repositories::before { + mask-image: var(--md-source-repositories-icon); + } + } +} + +// Source file information +.md-source-file { + margin: 1em 0; + + // Source file information fact + &__fact { + display: inline-flex; + gap: px2rem(6px); + align-items: center; + margin-inline-end: px2rem(12px); + font-size: px2rem(13.6px); + color: var(--md-default-fg-color--light); + + // Adjust vertical spacing + .md-icon { + flex-shrink: 0; + margin-bottom: px2rem(1px); + } + + // Author + .md-author { + float: inline-start; + margin-right: px2rem(4px); + } + + // Adjust size of icon + svg { + width: px2rem(18px); + } + } +} diff --git a/stylesheets/main/components/_status.scss b/stylesheets/main/components/_status.scss new file mode 100644 index 0000000..037c220 --- /dev/null +++ b/stylesheets/main/components/_status.scss @@ -0,0 +1,73 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Status variables +:root { + --md-status: svg-load("material/information-outline.svg"); + --md-status--new: svg-load("material/alert-decagram.svg"); + --md-status--deprecated: svg-load("material/trash-can.svg"); + --md-status--encrypted: svg-load("material/shield-lock.svg"); +} + +// ---------------------------------------------------------------------------- + +// Status +.md-status { + + // Status icon + &::after { + display: inline-block; + width: px2em(18px); + height: px2em(18px); + vertical-align: text-bottom; + content: ""; + background-color: var(--md-default-fg-color--light); + mask-image: var(--md-status); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + // Status icon on hover + &:hover::after { + background-color: currentcolor; + } + + // Status: new + &--new::after { + mask-image: var(--md-status--new); + } + + // Status: deprecated + &--deprecated::after { + mask-image: var(--md-status--deprecated); + } + + // Status: encrypted + &--encrypted::after { + mask-image: var(--md-status--encrypted); + } +} diff --git a/stylesheets/main/components/_tabs.scss b/stylesheets/main/components/_tabs.scss new file mode 100644 index 0000000..f048a51 --- /dev/null +++ b/stylesheets/main/components/_tabs.scss @@ -0,0 +1,133 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Navigation tabs +.md-tabs { + // Must be higher than the z-index of the back-to-top button, or the button + // will overlay the navigation tabs bar when scrolling up fast. + z-index: 3; + display: block; + width: 100%; + overflow: auto; + line-height: 1.3; + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + + // [print]: Hide tabs + @media print { + display: none; + } + + // [tablet -]: Hide tabs + @include break-to-device(tablet) { + display: none; + } + + // Navigation tabs are hidden + &[hidden] { + pointer-events: none; + } + + // Navigation tabs list + &__list { + display: flex; + padding: 0; + margin: 0; + margin-inline-start: px2rem(4px); + overflow: auto; + white-space: nowrap; + list-style: none; + contain: content; + // Hack: don't show scrollbar when navigation tabs overflow, which should + // only happen in rare occasions, as adding too many top level sections is + // discouraged, since hiding content on horitontal axis doesn't lead to a + // good user experience. It's just harder to discover. + scrollbar-width: none; + + // Hack: see above + &::-webkit-scrollbar { + display: none; + } + } + + // Navigation tabs item + &__item { + height: px2rem(48px); + padding-inline: px2rem(12px); + + // Navigation tabs link in active navigation + &--active .md-tabs__link { + color: inherit; + opacity: 1; + } + } + + // Navigation tabs link - could be defined as block elements and aligned via + // line height, but this would imply more repaints when scrolling + &__link { + display: flex; + margin-top: px2rem(16px); + font-size: px2rem(14px); + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + // Hack: save a repaint when tabs are appearing on scrolling up + backface-visibility: hidden; + opacity: 0.7; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 250ms; + + // Navigation tabs link on focus/hover + &:is(:focus, :hover) { + color: inherit; + opacity: 1; + } + + // Navigation tabs link icon + svg { + height: 1.3em; + margin-inline-end: px2rem(8px); + fill: currentcolor; + } + + // Delay transitions by a small amount + @for $i from 2 through 16 { + .md-tabs__item:nth-child(#{$i}) & { + transition-delay: 20ms * ($i - 1); + } + } + + // Hide tabs upon scrolling - disable transition to minimizes repaints + // while scrolling down, while scrolling up seems to be okay + .md-tabs[hidden] & { + opacity: 0; + transition: + transform 0ms 100ms, + opacity 100ms; + transform: translateY(50%); + } + } +} diff --git a/stylesheets/main/components/_tag.scss b/stylesheets/main/components/_tag.scss new file mode 100644 index 0000000..65c431a --- /dev/null +++ b/stylesheets/main/components/_tag.scss @@ -0,0 +1,105 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tag variables +:root { + --md-tag-icon: svg-load("material/pound.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Tag list (if not hidden) + .md-tags:not([hidden]) { + display: inline-flex; + flex-wrap: wrap; + gap: px2em(8px); + margin-top: px2em(-2px); + margin-bottom: px2em(12px); + } + + // Tag + .md-tag { + display: inline-flex; + gap: px2em(8px); + align-items: center; + padding: px2em(4px, 12.8px) px2em(10px, 12.8px); + font-size: px2rem(12.8px); // Fallback + font-size: min(px2em(12.8px), px2rem(12.8px)); + font-weight: 700; + line-height: 1.6; + letter-spacing: initial; + background: var(--md-default-fg-color--lightest); + border-radius: px2rem(48px); + + // Linked tag + &[href] { + color: inherit; + outline: none; + -webkit-tap-highlight-color: transparent; + transition: + color 125ms, + background-color 125ms; + + // Linked tag on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-bg-color); + background-color: var(--md-accent-fg-color); + } + } + + // Tag inside headline + [id] > & { + vertical-align: text-top; + } + } + + // Tag icon + .md-tag-icon { + + // Tag icon content + &::before { + display: inline-block; + width: 1.2em; + height: 1.2em; + vertical-align: text-bottom; + content: ""; + background-color: var(--md-default-fg-color--lighter); + mask-image: var(--md-tag-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + transition: background-color 125ms; + } + + // Linked tag on focus/hover + &[href]:is(:focus, :hover)::before { + background-color: var(--md-accent-bg-color); + } + } +} diff --git a/stylesheets/main/components/_tooltip.scss b/stylesheets/main/components/_tooltip.scss new file mode 100644 index 0000000..4e14a4e --- /dev/null +++ b/stylesheets/main/components/_tooltip.scss @@ -0,0 +1,316 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// Continuous pulse animation +@keyframes pulse { + 0% { + transform: scale(0.95); + } + + 75% { + transform: scale(1); + } + + 100% { + transform: scale(0.95); + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tooltip variables +:root { + --md-annotation-bg-icon: svg-load("material/circle.svg"); + --md-annotation-icon: svg-load("material/plus-circle.svg"); + --md-tooltip-width: #{px2rem(400px)}; +} + +// ---------------------------------------------------------------------------- + +// Tooltip +.md-tooltip { + position: absolute; + top: var(--md-tooltip-y); + left: + clamp( + var(--md-tooltip-0, #{px2rem(0px)}) + #{px2rem(16px)}, + var(--md-tooltip-x), + 100vw + + var(--md-tooltip-0, #{px2rem(0px)}) + #{px2rem(16px)} - + var(--md-tooltip-width) - + 2 * #{px2rem(16px)} + ); + // Hack: set an explicit `z-index` so we can transition it to ensure that any + // following elements are not overlaying the tooltip during the transition. + z-index: 0; + width: var(--md-tooltip-width); + max-width: calc(100vw - 2 * #{px2rem(16px)}); + font-family: var(--md-text-font-family); + color: var(--md-default-fg-color); + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z2); + opacity: 0; + transition: + transform 0ms 250ms, + opacity 250ms, + z-index 250ms; + transform: translateY(px2rem(-8px)); + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // Active tooltip + &--active { + z-index: 2; + opacity: 1; + transition: + transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 250ms, + z-index 0ms; + transform: translateY(0); + } + + // Inline tooltip + &--inline { + width: auto; + font-weight: 700; + user-select: none; + + // Tooltip is not active + &:not(.md-tooltip--active) { + transform: translateY(px2rem(4px)) scale(0.9); + } + + // Tooltip wrapper + .md-tooltip__inner { + padding: px2rem(4px) px2rem(8px); + font-size: px2rem(10px); + } + + // Hack: When the host element is hidden, the context for the tooltip is + // lost immediately, resulting in invalid and sometimes jumpy positioning. + [hidden] + & { + display: none; + } + } + + // Show outline on target and for keyboard devices + :is(.focus-visible > &, &:target) { + outline: var(--md-accent-fg-color) auto; + } + + // Tooltip wrapper + &__inner { + padding: px2rem(16px); + font-size: px2rem(12.8px); + + // Adjust spacing on first child + &.md-typeset > :first-child { + margin-top: 0; + } + + // Adjust spacing on last child + &.md-typeset > :last-child { + margin-bottom: 0; + } + } +} + +// ---------------------------------------------------------------------------- + +// Annotation +.md-annotation { + font-style: initial; + font-weight: 400; + text-align: initial; + white-space: normal; + vertical-align: text-bottom; + outline: none; + + // Adjust for right-to-left languages + [dir="rtl"] & { + direction: rtl; + } + + // Annotation index in code block + code & { + font-family: var(--md-code-font-family); + font-size: inherit; + } + + // Annotation is not hidden (e.g. when copying) + &:not([hidden]) { + display: inline-block; + // Hack: ensure that the line height doesn't exceed the line height of the + // hosting line, because it will lead to dancing pixels. + line-height: 1.25; + } + + // Annotation index + &__index { + position: relative; + z-index: 0; + display: inline-block; + margin-inline: 0.4ch; + vertical-align: text-top; + cursor: pointer; + user-select: none; + outline: none; + // Hack: Work around Firefox bug that renders a subpixel outline when + // rotating a mask image element - see https://t.ly/qA1s4 + overflow: hidden; // stylelint-disable-line order/properties-order + border-radius: 0.01px; + + // Hack: increase specificity to override default for anchors in typesetted + // content, because transitions are defined on anchor elements + .md-annotation & { + transition: z-index 250ms; + } + + // [screen]: Render annotation markers as icons + @media screen { + width: 2.2ch; + + // Annotation is visible + [data-md-visible] > & { + animation: pulse 2000ms infinite; + } + + // Annotation marker background + &::before { + position: absolute; + top: -0.1ch; + z-index: -1; + width: 2.2ch; + height: 2.2ch; + content: ""; + background: var(--md-default-bg-color); + mask-image: var(--md-annotation-bg-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + // Annotation marker – the marker must be positioned absolutely behind + // the index, because it shouldn't impact the rendering of a code block. + // Otherwise, small rounding differences in browsers can sometimes mess up + // alignment of text following an annotation. + &::after { + position: absolute; + top: -0.1ch; + z-index: -1; + width: 2.2ch; + height: 2.2ch; + content: ""; + background-color: var(--md-default-fg-color--lighter); + mask-image: var(--md-annotation-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + transition: + background-color 250ms, + transform 250ms; + // Hack: promote to own layer to reduce jitter + transform: scale(1.0001); + + // Annotation marker for active tooltip + .md-tooltip--active + & { + transform: rotate(45deg); + } + + // Annotation marker for active tooltip or on hover + :is(.md-tooltip--active + &, :hover > &) { + background-color: var(--md-accent-fg-color); + } + } + } + + // Annotation index for active tooltip + .md-tooltip--active + & { + z-index: 2; + transition-duration: 0ms; + animation-play-state: paused; + } + + // Annotation marker + [data-md-annotation-id] { + display: inline-block; + + // [print]: Render annotation markers as numbers + @media print { + padding: 0 0.6ch; + font-weight: 700; + color: var(--md-default-bg-color); + white-space: nowrap; + background: var(--md-default-fg-color--lighter); + border-radius: 2ch; + + // Annotation marker content + &::after { + content: attr(data-md-annotation-id); + } + } + } + } +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Annotation list + .md-annotation-list { + list-style: none; + counter-reset: xxx; + + // Annotation list item + li { + position: relative; + + // Annotation list marker + &::before { + position: absolute; + inset-inline-start: px2em(-34px); + top: px2em(4px); + min-width: 2ch; + height: 2ch; + padding: 0 0.6ch; + font-size: px2em(14.2px); + font-weight: 700; + line-height: 1.25; + color: var(--md-default-bg-color); + text-align: center; + content: counter(xxx); + counter-increment: xxx; + background: var(--md-default-fg-color--lighter); + border-radius: 2ch; + } + } + } +} diff --git a/stylesheets/main/components/_tooltip2.scss b/stylesheets/main/components/_tooltip2.scss new file mode 100644 index 0000000..e1a9ba6 --- /dev/null +++ b/stylesheets/main/components/_tooltip2.scss @@ -0,0 +1,210 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tooltip variables +:root { + --md-tooltip-width: #{px2rem(400px)}; + --md-tooltip-tail: #{px2rem(6px)}; +} + +// ---------------------------------------------------------------------------- + +// Tooltip +.md-tooltip2 { + position: absolute; + // Note that the top offset is computed from the host element offset plus the + // tooltip offset, which is always measured relative to the host element + top: + calc( + var(--md-tooltip-host-y) + + var(--md-tooltip-y) + ); + // Hack: set an explicit `z-index` so we can transition it to ensure that any + // following elements are not overlaying the tooltip during the transition. + z-index: 0; + inline-size: 100%; + font-family: var(--md-text-font-family); + color: var(--md-default-fg-color); + pointer-events: none; + opacity: 0; + transition: + transform 0ms 250ms, + opacity 250ms, + z-index 250ms; + transform: translateY(px2rem(-8px)); + // We explicitly set the origin to the tooltip tail, allowing the author to + // easily add further transforms to the tooltip, customizing the transition + transform-origin: + calc( + var(--md-tooltip-host-x) + + var(--md-tooltip-x) + ) + 0; + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // Tooltip tail + &::before { + position: absolute; + // The offset of the tooltip tail is computed from the host element offset, + // plus the tooltip offset, which equals the center of the host element, + // and minus the half width of the tooltip tail to center it. Then, on both + // sides, the tooltip tail is padded with 150% of the inset area. + left: + clamp( + 1.5 * #{px2rem(16px)}, + calc( + var(--md-tooltip-host-x) + + var(--md-tooltip-x) - + var(--md-tooltip-tail) + ), + calc( + 100vw - + 2 * var(--md-tooltip-tail) - + 1.5 * #{px2rem(16px)} + ) + ); + z-index: 1; + display: block; + content: ""; + border-inline: var(--md-tooltip-tail) solid transparent; + } + + // Tooltip tail if rendered above target + &--top::before { + bottom: calc(-1 * var(--md-tooltip-tail) + px2rem(0.5px)); + filter: drop-shadow(0 1px 0 hsla(0, 0%, 0%, 0.05)); + border-top: var(--md-tooltip-tail) solid var(--md-default-bg-color); + } + + // Tooltip tail if rendered below target + &--bottom::before { + top: calc(-1 * var(--md-tooltip-tail) + px2rem(0.5px)); + filter: drop-shadow(0 -1px 0 hsla(0, 0%, 0%, 0.05)); + border-bottom: var(--md-tooltip-tail) solid var(--md-default-bg-color); + } + + // Tooltip is visible + &--active { + z-index: 2; + opacity: 1; + transition: + transform 400ms cubic-bezier(0, 1, 0.5, 1), + opacity 250ms, + z-index 0ms; + transform: translateY(0); + } + + // Tooltip wrapper + &__inner { + position: relative; + // The tooltip is slightly moved to the left, so it nicely aligns with the + // content of the tooltip set by the padding of this element. On both sides, + // the tooltip is padded with the inset area, so it never touches the edge + // of the window for a better user experience. + left: + clamp( + #{px2rem(16px)}, + calc( + var(--md-tooltip-host-x) - + #{px2rem(16px)} + ), + calc( + 100vw - + var(--md-tooltip-width) - + #{px2rem(16px)} + ) + ); + max-width: calc(100vw - 2 * #{px2rem(16px)}); + max-height: 40vh; + scrollbar-gutter: stable; + scrollbar-width: thin; + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z2); + + // Webkit scrollbar + &::-webkit-scrollbar { + width: px2rem(4px); + height: px2rem(4px); + } + + // Webkit scrollbar thumb + &::-webkit-scrollbar-thumb { + background-color: var(--md-default-fg-color--lighter); + + // Webkit scrollbar thumb on hover + &:hover { + background-color: var(--md-accent-fg-color); + } + } + + // Tooltip is non-interactive - this role should be set if the tooltip has + // only informational and non-interactive content, e.g., an actual tooltip. + // It has no explicitl width set, uses a smaller font, and is centered, + // other than a tooltip with typesetted content. + [role="tooltip"] > & { + left: + clamp( + #{px2rem(16px)}, + calc( + var(--md-tooltip-host-x) + + var(--md-tooltip-x) - + var(--md-tooltip-width) / 2 + ), + calc( + 100vw - + var(--md-tooltip-width) - + #{px2rem(16px)} + ) + ); + width: fit-content; + // @todo refactor - this is currently a hack to fix overly long tooltips, + // but should be refactored in the future to be more flexible + max-width: + min( + calc(100vw - 2 * #{px2rem(16px)}), + 400px + ); + padding: px2rem(4px) px2rem(8px); + font-size: px2rem(10px); + font-weight: 700; + // If the author wishes to keep the tooltip visible upon hover and make + // the text selectable, this property can be set to `initial` + user-select: none; + } + + // Adjust spacing on first child + &.md-typeset > :first-child { + margin-top: 0; + } + + // Adjust spacing on last child + &.md-typeset > :last-child { + margin-bottom: 0; + } + } +} diff --git a/stylesheets/main/components/_top.scss b/stylesheets/main/components/_top.scss new file mode 100644 index 0000000..10fd637 --- /dev/null +++ b/stylesheets/main/components/_top.scss @@ -0,0 +1,83 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Back-to-top button +.md-top { + position: fixed; + top: px2rem(48px + 16px); + z-index: 2; + display: block; + padding: px2rem(8px) px2rem(16px); + margin-inline-start: 50%; + font-size: px2rem(14px); + color: var(--md-default-fg-color--light); + cursor: pointer; + background-color: var(--md-default-bg-color); + border-radius: px2rem(32px); + outline: none; + box-shadow: var(--md-shadow-z2); + transition: + color 125ms, + background-color 125ms, + transform 125ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 125ms; + transform: translate(-50%, 0); + + // [print]: Hide back-to-top button + @media print { + display: none; + } + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translate(50%, 0); + } + + // Back-to-top button is hidden + &[hidden] { + pointer-events: none; + opacity: 0; + transition-duration: 0ms; + transform: translate(-50%, px2rem(4px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translate(50%, px2rem(4px)); + } + } + + // Back-to-top button on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-bg-color); + background-color: var(--md-accent-fg-color); + } + + // Inline icon + svg { + display: inline-block; + vertical-align: -0.5em; + } +} diff --git a/stylesheets/main/components/_version.scss b/stylesheets/main/components/_version.scss new file mode 100644 index 0000000..0b1fff2 --- /dev/null +++ b/stylesheets/main/components/_version.scss @@ -0,0 +1,156 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// See https://github.com/squidfunk/mkdocs-material/issues/2429 +@keyframes hoverfix { + 0% { + pointer-events: none; + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Version selection variables +:root { + --md-version-icon: svg-load("fontawesome/solid/caret-down.svg"); +} + +// ---------------------------------------------------------------------------- + +// Version selection +.md-version { + flex-shrink: 0; + height: px2rem(48px); + font-size: px2rem(16px); + + // Current selection + &__current { + position: relative; + // Hack: in general, we would use `vertical-align` to align the version at + // the bottom with the title, but since the list uses absolute positioning, + // this won't work consistently. Furthermore, we would need to use inline + // positioning to align the links, which looks jagged. + top: px2rem(1px); + margin-inline: px2rem(28px) px2rem(8px); + color: inherit; + cursor: pointer; + outline: none; + + // Version selection icon + &::after { + display: inline-block; + width: px2rem(8px); + height: px2rem(12px); + margin-inline-start: px2rem(8px); + content: ""; + background-color: currentcolor; + mask-image: var(--md-version-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + } + + // Version alias + &__alias { + margin-left: px2rem(6px); + opacity: 0.7; + } + + // Version selection list + &__list { + position: absolute; + top: px2rem(3px); + z-index: 3; + max-height: 0; + padding: 0; + margin: px2rem(4px) px2rem(16px); + overflow: auto; + color: var(--md-default-fg-color); + list-style-type: none; + scroll-snap-type: y mandatory; + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z2); + opacity: 0; + transition: + max-height 0ms 500ms, + opacity 250ms 250ms; + + // Version selection list on parent focus/hover + .md-version:is(:focus-within, :hover) & { + max-height: px2rem(200px); + opacity: 1; + transition: + max-height 0ms, + opacity 250ms; + } + + // Fix hover on touch devices + @media (pointer: coarse), (hover: none) { + // Switch off on hover + .md-version:hover & { + animation: hoverfix 250ms forwards; + } + + // Enable on focus + .md-version:focus-within & { + animation: none; + } + } + } + + // Version selection item + &__item { + line-height: px2rem(36px); + } + + // Version selection link + &__link { + display: block; + width: 100%; + padding-inline: px2rem(12px) px2rem(24px); + white-space: nowrap; + cursor: pointer; + scroll-snap-align: start; + outline: none; + transition: + color 250ms, + background-color 250ms; + + // Link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Link on focus + &:focus { + background-color: var(--md-default-fg-color--lightest); + } + } +} diff --git a/stylesheets/main/extensions/markdown/_admonition.scss b/stylesheets/main/extensions/markdown/_admonition.scss new file mode 100644 index 0000000..f138497 --- /dev/null +++ b/stylesheets/main/extensions/markdown/_admonition.scss @@ -0,0 +1,195 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:color"; +@use "sass:list"; + +// ---------------------------------------------------------------------------- +// Variables +// ---------------------------------------------------------------------------- + +/// Admonition flavours +$admonitions: ( + "note": pencil-circle $clr-blue-a200, + "abstract": clipboard-text $clr-light-blue-a400, + "info": information $clr-cyan-a700, + "tip": fire $clr-teal-a700, + "success": check $clr-green-a700, + "question": help-circle $clr-light-green-a700, + "warning": alert $clr-orange-a400, + "failure": close $clr-red-a200, + "danger": lightning-bolt-circle $clr-red-a400, + "bug": shield-bug $clr-pink-a400, + "example": test-tube $clr-deep-purple-a200, + "quote": format-quote-close $clr-grey +) !default; + +// ---------------------------------------------------------------------------- +// Rules: layout +// ---------------------------------------------------------------------------- + +// Admonition variables +:root { + @each $name, $props in $admonitions { + --md-admonition-icon--#{$name}: + svg-load("material/#{list.nth($props, 1)}.svg"); + } +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Admonition - note that all styles also apply to details tags, which are + // rendered as collapsible admonitions with summary elements as titles. + .admonition { + display: flow-root; + padding: 0 px2rem(12px); + margin: px2em(20px, 12.8px) 0; + font-size: px2rem(12.8px); + color: var(--md-admonition-fg-color); + background-color: var(--md-admonition-bg-color); + border: px2rem(1.5px) solid $clr-blue-a200; + border-radius: px2rem(4px); + box-shadow: var(--md-shadow-z1); + transition: box-shadow 125ms; + page-break-inside: avoid; + + // [print]: Omit shadow as it may lead to rendering errors + @media print { + box-shadow: none; + } + + // Admonition on focus + &:focus-within { + box-shadow: 0 0 0 px2rem(4px) color.adjust($clr-blue-a200, $alpha: -0.9); + } + + // Hack: Chrome exhibits a weird issue where it will set nested elements to + // content-box. Doesn't happen in other browsers, so looks like a bug. + > * { + box-sizing: border-box; + } + + // Adjust vertical spacing for nested admonitions + .admonition { + margin-top: 1em; + margin-bottom: 1em; + } + + // Adjust spacing for contained table wrappers + .md-typeset__scrollwrap { + margin: 1em px2rem(-12px); + } + + // Adjust spacing for contained tables + .md-typeset__table { + padding: 0 px2rem(12px); + } + + // Adjust spacing for single-child tabbed block container + > .tabbed-set:only-child { + margin-top: 0; + } + + // Adjust spacing on last child + html & > :last-child { + margin-bottom: px2rem(12px); + } + } + + // Admonition title + .admonition-title { + position: relative; + padding-block: px2rem(8px); + padding-inline: px2rem(40px) px2rem(12px); + margin-block: 0; + margin-inline: px2rem(-12px); + font-weight: 700; + background-color: color.adjust($clr-blue-a200, $alpha: -0.9); + border: none; + border-inline-start-width: px2rem(4px); + border-start-start-radius: px2rem(2px); + border-start-end-radius: px2rem(2px); + + // Adjust spacing for title-only admonitions + html &:last-child { + margin-bottom: 0; + } + + // Admonition icon + &::before { + position: absolute; + inset-inline-start: px2rem(12px); + top: px2em(10px); + width: px2rem(20px); + height: px2rem(20px); + content: ""; + background-color: $clr-blue-a200; + mask-image: var(--md-admonition-icon--note); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + // Inline code block + code { + box-shadow: 0 0 0 px2rem(1px) var(--md-default-fg-color--lightest); + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: flavours +// ---------------------------------------------------------------------------- + +// Define admonition flavors +@each $name, $props in $admonitions { + $tint: list.nth($props, 2); + + // Admonition flavour + .md-typeset .admonition.#{$name} { + border-color: $tint; + + // Admonition on focus + &:focus-within { + box-shadow: 0 0 0 px2rem(4px) color.adjust($tint, $alpha: -0.9); + } + } + + // Admonition flavour title + .md-typeset .#{$name} > .admonition-title { + background-color: color.adjust($tint, $alpha: -0.9); + + // Admonition icon + &::before { + background-color: $tint; + mask-image: var(--md-admonition-icon--#{$name}); + } + + // Details marker + &::after { + color: $tint; + } + } +} diff --git a/stylesheets/main/extensions/markdown/_footnotes.scss b/stylesheets/main/extensions/markdown/_footnotes.scss new file mode 100644 index 0000000..727ed64 --- /dev/null +++ b/stylesheets/main/extensions/markdown/_footnotes.scss @@ -0,0 +1,146 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Footnotes variables +:root { + --md-footnotes-icon: svg-load("material/keyboard-return.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Footnote container + .footnote { + font-size: px2rem(12.8px); + color: var(--md-default-fg-color--light); + + // Footnote list - omit left indentation + > ol { + margin-inline-start: 0; + + // Footnote item - footnote items can contain lists, so we need to scope + // the spacing adjustments to the top-level footnote item. + > li { + transition: color 125ms; + + // Darken color on target + &:target { + color: var(--md-default-fg-color); + } + + // Show backreferences on footnote focus without transition + &:focus-within .footnote-backref { + opacity: 1; + transition: none; + transform: translateX(0); + } + + // Show backreferences on footnote hover/target + &:is(:hover, :target) .footnote-backref { + opacity: 1; + transform: translateX(0); + } + + // Adjust spacing on first child + > :first-child { + margin-top: 0; + } + } + } + } + + // Footnote reference + .footnote-ref { + font-size: px2em(12px, 16px); + font-weight: 700; + + // Hack: increase specificity to override default + html & { + outline-offset: px2rem(2px); + } + } + + // Show outline for all devices + [id^="fnref:"]:target > .footnote-ref { + outline: auto; + } + + // Footnote backreference + .footnote-backref { + display: inline-block; + // Hack: omit Unicode arrow for replacement with icon + font-size: 0; + color: var(--md-typeset-a-color); + vertical-align: text-bottom; + opacity: 0; + transition: + color 250ms, + transform 250ms 250ms, + opacity 125ms 250ms; + transform: translateX(px2rem(5px)); + + // [print]: Show footnote backreferences + @media print { + color: var(--md-typeset-a-color); + opacity: 1; + transform: translateX(0); + } + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(-5px)); + } + + // Adjust color on hover + &:hover { + color: var(--md-accent-fg-color); + } + + // Footnote backreference icon + &::before { + display: inline-block; + width: px2rem(16px); + height: px2rem(16px); + content: ""; + background-color: currentcolor; + mask-image: var(--md-footnotes-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + + // Adjust for right-to-left languages + [dir="rtl"] & { + + // Flip icon vertically + svg { + transform: scaleX(-1); + } + } + } + } +} diff --git a/stylesheets/main/extensions/markdown/_toc.scss b/stylesheets/main/extensions/markdown/_toc.scss new file mode 100644 index 0000000..7ce7f4d --- /dev/null +++ b/stylesheets/main/extensions/markdown/_toc.scss @@ -0,0 +1,92 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Headerlink + .headerlink { + display: inline-block; + margin-inline-start: px2rem(10px); + color: var(--md-default-fg-color--lighter); + opacity: 0; + transition: + color 250ms, + opacity 125ms; + + // [print]: Hide headerlinks + @media print { + display: none; + } + } + + // Show headerlinks on parent hover + :is(:hover, :target) > .headerlink, + .headerlink:focus { + opacity: 1; + transition: + color 250ms, + opacity 125ms; + } + + // Adjust color on parent target or focus/hover + :target > .headerlink, + .headerlink:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Adjust scroll margin for all elements with `id` attributes + :target { + --md-scroll-margin: #{px2rem(48px + 24px)}; + --md-scroll-offset: #{px2rem(0px)}; + // Scroll margin is finally ready for prime time - before, we used a hack + // for anchor correction based on pseudo elements but those times are gone. + scroll-margin-top: + calc( + var(--md-scroll-margin) - + var(--md-scroll-offset) + ); + + // [screen +]: Sticky navigation tabs + @include break-from-device(screen) { + + // Adjust scroll margin for sticky navigation tabs + .md-header--lifted ~ .md-container & { + --md-scroll-margin: #{px2rem(96px + 24px)}; + } + } + } + + // Adjust scroll offset for headlines of level 1-3 + :is(h1, h2, h3):target { + --md-scroll-offset: #{px2rem(4px)}; + } + + // Adjust scroll offset for headlines of level 4 + h4:target { + --md-scroll-offset: #{px2rem(3px)}; + } +} diff --git a/stylesheets/main/extensions/pymdownx/_arithmatex.scss b/stylesheets/main/extensions/pymdownx/_arithmatex.scss new file mode 100644 index 0000000..4a163b4 --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_arithmatex.scss @@ -0,0 +1,62 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Arithmatex container + div.arithmatex { + overflow: auto; + + // [mobile -]: Align with body copy + @include break-to-device(mobile) { + margin: 0 px2rem(-16px); + + // Arithmatex content + > * { + width: min-content; + } + } + + // Arithmatex content + > * { + padding: 0 px2rem(16px); + margin-inline: auto !important; // stylelint-disable-line + touch-action: auto; + + // MathJax container - see https://bit.ly/3HR8YJ5 + mjx-container { + margin: 0 !important; // stylelint-disable-line + } + } + + // Prevent horizontal overflow, as this element is not visible but still has + // a height, which might be a bug in MathJax - see https://t.ly/ckPiA + mjx-assistive-mml { + height: 0; + } + } +} diff --git a/stylesheets/main/extensions/pymdownx/_critic.scss b/stylesheets/main/extensions/pymdownx/_critic.scss new file mode 100644 index 0000000..5726fbc --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_critic.scss @@ -0,0 +1,76 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Deletion + del.critic { + background-color: var(--md-typeset-del-color); + box-decoration-break: clone; + } + + // Addition + ins.critic { + background-color: var(--md-typeset-ins-color); + box-decoration-break: clone; + } + + // Comment + .critic.comment { + color: var(--md-code-hl-comment-color); + box-decoration-break: clone; + + // Comment opening mark + &::before { + content: "/* "; + } + + // Comment closing mark + &::after { + content: " */"; + } + } + + // Critic block + .critic.block { + display: block; + padding-inline: px2rem(16px); + margin: 1em 0; + overflow: auto; + box-shadow: none; + + // Adjust spacing on first child + > :first-child { + margin-top: 0.5em; + } + + // Adjust spacing on last child + > :last-child { + margin-bottom: 0.5em; + } + } +} diff --git a/stylesheets/main/extensions/pymdownx/_details.scss b/stylesheets/main/extensions/pymdownx/_details.scss new file mode 100644 index 0000000..52b5b6a --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_details.scss @@ -0,0 +1,124 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Details variables +:root { + --md-details-icon: svg-load("material/chevron-right.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Details + details { + @extend .admonition; + + display: flow-root; + padding-top: 0; + overflow: visible; + + // Details title icon - rotate icon on transition to open state + &[open] > summary::after { + transform: rotate(90deg); + } + + // Adjust spacing for details in closed state + &:not([open]) { + padding-bottom: 0; + box-shadow: none; + + // Hack: we cannot set `overflow: hidden` on the `details` element (which + // is why we set it to `overflow: visible`, as the outline would not be + // visible when focusing. Therefore, we must set the border radius on the + // summary explicitly. + > summary { + border-radius: px2rem(2px); + } + } + } + + // Details title + summary { + @extend .admonition-title; + + display: block; + min-height: px2rem(20px); + padding-inline-end: px2rem(36px); + // Hack: Work around Firefox bug that renders a subpixel outline when + // rotating a mask image element - see https://t.ly/qA1s4 + overflow: hidden; + cursor: pointer; + border-start-start-radius: px2rem(2px); + border-start-end-radius: px2rem(2px); + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Details marker + &::after { + position: absolute; + inset-inline-end: px2rem(8px); + top: px2em(10px); + width: px2rem(20px); + height: px2rem(20px); + content: ""; + background-color: currentcolor; + mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + transition: transform 250ms; + transform: rotate(0deg); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: rotate(180deg); + } + } + + // Hide native details marker - modern + &::marker { + display: none; + } + + // Hide native details marker - legacy, must be split into a separate rule, + // so older browsers don't consider the selector list as invalid + &::-webkit-details-marker { + display: none; + } + } +} diff --git a/stylesheets/main/extensions/pymdownx/_emoji.scss b/stylesheets/main/extensions/pymdownx/_emoji.scss new file mode 100644 index 0000000..df59c64 --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_emoji.scss @@ -0,0 +1,75 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Emoji and icon container + :is(.emojione, .twemoji, .gemoji) { + --md-icon-size: #{px2em(18px)}; + + display: inline-flex; + height: var(--md-icon-size); + vertical-align: text-top; + + // Icon - inlined via mkdocs-material-extensions + svg { + width: var(--md-icon-size); + max-height: 100%; + fill: currentcolor; + } + } + + // Icon with size modifier + :is(.lg, .xl, .xxl, .xxxl) { + vertical-align: text-bottom; + } + + // Adjust icon alignment + .middle { + vertical-align: middle; + } + + // Adjust icon size to 1.5x + .lg { + --md-icon-size: #{px2em(24px)}; + } + + // Adjust icon size to 2x + .xl { + --md-icon-size: #{px2em(36px)}; + } + + // Adjust icon size to 3x + .xxl { + --md-icon-size: #{px2em(48px)}; + } + + // Adjust icon size to 4x + .xxxl { + --md-icon-size: #{px2em(64px)}; + } +} diff --git a/stylesheets/main/extensions/pymdownx/_highlight.scss b/stylesheets/main/extensions/pymdownx/_highlight.scss new file mode 100644 index 0000000..bd86ed1 --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_highlight.scss @@ -0,0 +1,387 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules: syntax highlighting +// ---------------------------------------------------------------------------- + +// Code block +.highlight { + + // .o = Operator + // .ow = Operator, word + :is(.o, .ow) { + color: var(--md-code-hl-operator-color); + } + + .p { // Punctuation + color: var(--md-code-hl-punctuation-color); + } + + // .cpf = Comment, preprocessor file + // .l = Literal + // .s = Literal, string + // .sb = Literal, string backticks + // .sc = Literal, string char + // .s2 = Literal, string double + // .si = Literal, string interpol + // .s1 = Literal, string single + // .ss = Literal, string symbol + :is(.cpf, .l, .s, .sb, .sc, .s2, .si, .s1, .ss) { + color: var(--md-code-hl-string-color); + } + + // .cp = Comment, pre-processor + // .se = Literal, string escape + // .sh = Literal, string heredoc + // .sr = Literal, string regex + // .sx = Literal, string other + :is(.cp, .se, .sh, .sr, .sx) { + color: var(--md-code-hl-special-color); + } + + // .m = Number + // .mb = Number, binary + // .mf = Number, float + // .mh = Number, hex + // .mi = Number, integer + // .il = Number, integer long + // .mo = Number, octal + :is(.m, .mb, .mf, .mh, .mi, .il, .mo) { + color: var(--md-code-hl-number-color); + } + + // .k = Keyword, + // .kd = Keyword, declaration + // .kn = Keyword, namespace + // .kp = Keyword, pseudo + // .kr = Keyword, reserved + // .kt = Keyword, type + :is(.k, .kd, .kn, .kp, .kr, .kt) { + color: var(--md-code-hl-keyword-color); + } + + // .kc = Keyword, constant + // .n = Name + :is(.kc, .n) { + color: var(--md-code-hl-name-color); + } + + // .no = Name, constant + // .nb = Name, builtin + // .bp = Name, builtin pseudo + :is(.no, .nb, .bp) { + color: var(--md-code-hl-constant-color); + } + + // .nc = Name, class + // .ne = Name, exception + // .nf = Name, function + // .nn = Name, namespace + :is(.nc, .ne, .nf, .nn) { + color: var(--md-code-hl-function-color); + } + + // .nd = Name, decorator + // .ni = Name, entity + // .nl = Name, label + // .nt = Name, tag + :is(.nd, .ni, .nl, .nt) { + color: var(--md-code-hl-keyword-color); + } + + // .c = Comment + // .cm = Comment, multiline + // .c1 = Comment, single + // .ch = Comment, shebang + // .cs = Comment, special + // .sd = Literal, string doc + :is(.c, .cm, .c1, .ch, .cs, .sd) { + color: var(--md-code-hl-comment-color); + } + + // .na = Name, attribute + // .nv = Variable, + // .vc = Variable, class + // .vg = Variable, global + // .vi = Variable, instance + :is(.na, .nv, .vc, .vg, .vi) { + color: var(--md-code-hl-variable-color); + } + + // .ge = Generic, emph + // .gr = Generic, error + // .gh = Generic, heading + // .go = Generic, output + // .gp = Generic, prompt + // .gs = Generic, strong + // .gu = Generic, subheading + // .gt = Generic, traceback + :is(.ge, .gr, .gh, .go, .gp, .gs, .gu, .gt) { + color: var(--md-code-hl-generic-color); + } + + // .gd = Diff, delete + // .gi = Diff, insert + :is(.gd, .gi) { + padding: 0 px2em(2px); + margin: 0 px2em(-2px); + border-radius: px2rem(2px); + } + + .gd { // Diff, delete + background-color: var(--md-typeset-del-color); + } + + .gi { // Diff, insert + background-color: var(--md-typeset-ins-color); + } + + // Highlighted line + .hll { + display: block; + padding: 0 px2em(16px, 13.6px); + margin: 0 px2em(-16px, 13.6px); + background-color: var(--md-code-hl-color--light); + box-shadow: 2px 0 0 0 var(--md-code-hl-color) inset; + } + + // Code block title + span.filename { + position: relative; + display: flow-root; + padding: px2em(9px, 13.6px) px2em(16px, 13.6px); + margin-top: 1em; + font-size: px2em(13.6px); + font-weight: 700; + background-color: var(--md-code-bg-color); + border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest); + border-top-left-radius: px2rem(2px); + border-top-right-radius: px2rem(2px); + + // Adjust spacing for code block + + pre { + margin-top: 0; + + // Remove rounded border on top side + > code { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + } + + // Code block line numbers (pymdownx-inline) + [data-linenos]::before { + position: sticky; + left: px2em(-16px, 13.6px); + // A `z-index` of 3 is necessary for ensuring that code block annotations + // don't overlay line numbers, as active annotations have a `z-index` of 2. + z-index: 3; + float: left; + padding-left: px2em(16px, 13.6px); + margin-right: px2em(16px, 13.6px); + margin-left: px2em(-16px, 13.6px); + color: var(--md-default-fg-color--light); + content: attr(data-linenos); + user-select: none; + background-color: var(--md-code-bg-color); + box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset; + } + + // Code block line anchors - Chrome and Safari seem to have a strange bug + // where scroll margin is not applied to anchors inside code blocks. Setting + // positioning to absolute seems to fix the problem. Interestingly, this does + // not happen in Firefox. Furthermore we must set `visibility: hidden` or + // the copy to clipboard functionality will include an empty line between + // each set of lines. + code a[id] { + position: absolute; + visibility: hidden; + } + + // Copying in progress - this class is set before the content is copied and + // removed after copying is done to mitigate whitespace-related issues. + code[data-md-copying] { + // Hack: since we're using grid layout when line spans are enabled, we need + // to set the display property to `initial` to prevent the grid layout from + // being applied to the code block when copying, because it will add empty + // lines to the copied content - see https://t.ly/wt4ye + display: initial; + + // Temporarily remove highlighted lines - see https://bit.ly/32iVGWh + .hll { + display: contents; + } + + // Temporarily remove annotations + .md-annotation { + display: none; + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: layout +// ---------------------------------------------------------------------------- + +// Code block with line numbers +.highlighttable { + display: flow-root; + + // Set table elements to block layout, because otherwise the whole flexbox + // hacking won't work correctly + :is(tbody, td) { + display: block; + padding: 0; + } + + // We need to use flexbox layout, because otherwise it's not possible to + // make the code container scroll while keeping the line numbers static + tr { + display: flex; + } + + // The pre tags are nested inside a table, so we need to omit the margin + // because it collapses below all the overflows + pre { + margin: 0; + } + + // Code block title container + th.filename { + flex-grow: 1; + padding: 0; + text-align: left; + + // Adjust spacing + span.filename { + margin-top: 0; + } + } + + // Code block line numbers - disable user selection, so code can be easily + // copied without accidentally also copying the line numbers + .linenos { + padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px); + padding-right: 0; + font-size: px2em(13.6px); + user-select: none; + background-color: var(--md-code-bg-color); + border-top-left-radius: px2rem(2px); + border-bottom-left-radius: px2rem(2px); + } + + // Code block line numbers container + .linenodiv { + padding-right: px2em(8px, 13.6px); + box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset; + + // Adjust colors and alignment + pre { + color: var(--md-default-fg-color--light); + text-align: right; + } + } + + // Code block container - stretch to remaining space + .code { + flex: 1; + min-width: 0; + } +} + +// Code block line numbers container +.linenodiv a { + color: inherit; +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Code block with line numbers - unfortunately, these selectors need to be + // overly specific so they don't bleed into code blocks in annotations. + .highlighttable { + margin: 1em 0; + direction: ltr; + + // Remove rounded borders on code blocks + > tbody > tr > .code > div > pre > code { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + // Code block result container + .highlight + .result { + padding: 0 px2em(16px); + margin-top: calc(-1em + #{px2em(-2px)}); + overflow: visible; + border: px2rem(1px) solid var(--md-code-bg-color); + border-top-width: px2rem(2px); + border-bottom-right-radius: px2rem(2px); + border-bottom-left-radius: px2rem(2px); + + // Clearfix, because we can't use overflow: auto + &::after { + display: block; + clear: both; + content: ""; + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: top-level +// ---------------------------------------------------------------------------- + +// [mobile -]: Align with body copy +@include break-to-device(mobile) { + + // Top-level code block + .md-content__inner > .highlight { + margin: 1em px2rem(-16px); + + // Remove rounded borders + > .filename, + > pre > code { + border-radius: 0; + } + + // Code block with line numbers - unfortunately, these selectors need to be + // overly specific so they don't bleed into code blocks in annotations. + > .highlighttable > tbody > tr > .filename span.filename, + > .highlighttable > tbody > tr > .linenos, + > .highlighttable > tbody > tr > .code > div > pre > code { + border-radius: 0; + } + + // Code block result container + + .result { + margin-inline: px2rem(-16px); + border-inline-width: 0; + border-radius: 0; + } + } +} diff --git a/stylesheets/main/extensions/pymdownx/_keys.scss b/stylesheets/main/extensions/pymdownx/_keys.scss new file mode 100644 index 0000000..b0a6122 --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_keys.scss @@ -0,0 +1,115 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Keyboard key + .keys { + + // Keyboard key icon + kbd:is(::before, ::after) { + position: relative; + margin: 0; + color: inherit; + -moz-osx-font-smoothing: initial; + -webkit-font-smoothing: initial; + } + + // Surrounding text + span { + padding: 0 px2em(3.2px); + color: var(--md-default-fg-color--light); + } + + // Define keyboard keys with left icon + @each $name, $code in ( + + // Modifiers + "alt": "\2387", + "left-alt": "\2387", + "right-alt": "\2387", + "command": "\2318", + "left-command": "\2318", + "right-command": "\2318", + "control": "\2303", + "left-control": "\2303", + "right-control": "\2303", + "meta": "\25C6", + "left-meta": "\25C6", + "right-meta": "\25C6", + "option": "\2325", + "left-option": "\2325", + "right-option": "\2325", + "shift": "\21E7", + "left-shift": "\21E7", + "right-shift": "\21E7", + "super": "\2756", + "left-super": "\2756", + "right-super": "\2756", + "windows": "\229E", + "left-windows": "\229E", + "right-windows": "\229E", + + // Other keys + "arrow-down": "\2193", + "arrow-left": "\2190", + "arrow-right": "\2192", + "arrow-up": "\2191", + "backspace": "\232B", + "backtab": "\21E4", + "caps-lock": "\21EA", + "clear": "\2327", + "context-menu": "\2630", + "delete": "\2326", + "eject": "\23CF", + "end": "\2913", + "escape": "\238B", + "home": "\2912", + "insert": "\2380", + "page-down": "\21DF", + "page-up": "\21DE", + "print-screen": "\2399" + ) { + .key-#{$name}::before { + padding-right: px2em(6.4px); + content: $code; + } + } + + // Define keyboard keys with right icon + @each $name, $code in ( + "tab": "\21E5", + "num-enter": "\2324", + "enter": "\23CE" + ) { + .key-#{$name}::after { + padding-left: px2em(6.4px); + content: $code; + } + } + } +} diff --git a/stylesheets/main/extensions/pymdownx/_tabbed.scss b/stylesheets/main/extensions/pymdownx/_tabbed.scss new file mode 100644 index 0000000..0740790 --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_tabbed.scss @@ -0,0 +1,417 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tabbed variables +:root { + --md-tabbed-icon--prev: svg-load("material/chevron-left.svg"); + --md-tabbed-icon--next: svg-load("material/chevron-right.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Tabbed container + .tabbed-set { + position: relative; + display: flex; + flex-flow: column wrap; + margin: 1em 0; + border-radius: px2rem(2px); + + // Tab radio button - the Tabbed extension will generate radio buttons with + // labels, so tabs can be triggered without the necessity for JavaScript. + // This is pretty cool, as it has great accessibility out-of-the box, so + // we just hide the radio button and toggle the label color for indication. + > input { + position: absolute; + width: 0; + height: 0; + opacity: 0; + + // Adjust scroll margin + &:target { + --md-scroll-offset: #{px2em(10px, 16px)}; + } + + // Tab label states + @for $i from 20 through 1 { + &:nth-child(#{$i}) { + + // Tab is active + &:checked { + + // Tab label + ~ .tabbed-labels > :nth-child(#{$i}) { + @extend %tabbed-label; + } + + // Tab content + ~ .tabbed-content > :nth-child(#{$i}) { + @extend %tabbed-content; + } + } + + // Tab label on keyboard focus + &.focus-visible ~ .tabbed-labels > :nth-child(#{$i}) { + @extend %tabbed-label-focus-visible; + } + } + } + + // Tab indicator on keyboard focus + &.focus-visible ~ .tabbed-labels::before { + background-color: var(--md-accent-fg-color); + } + } + } + + // Tabbed labels + .tabbed-labels { + display: flex; + max-width: 100%; + overflow: auto; + scrollbar-width: none; // Firefox + box-shadow: 0 px2rem(-1px) var(--md-default-fg-color--lightest) inset; + -ms-overflow-style: none; // IE, Edge + + // [print]: Move one layer up for ordering + @media print { + display: contents; + } + + // [screen and no reduced motion]: Disable animation + @media screen { + + // [js]: Show animated tab indicator + .js & { + position: relative; + + // Tab indicator + &::before { + position: absolute; + bottom: 0; + left: 0; + display: block; + width: var(--md-indicator-width); + height: 2px; + content: ""; + background: var(--md-default-fg-color); + transition: + width 225ms, + background-color 250ms, + transform 250ms; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transform: translateX(var(--md-indicator-x)); + } + } + } + + // Webkit scrollbar + &::-webkit-scrollbar { + display: none; // Chrome, Safari + } + + // Tab label + > label { + flex-shrink: 0; + width: auto; + padding: px2em(10px, 12.8px) 1.25em px2em(8px, 12.8px); + font-size: px2rem(12.8px); + font-weight: 700; + color: var(--md-default-fg-color--light); + white-space: nowrap; + cursor: pointer; + scroll-margin-inline-start: px2rem(20px); + border-bottom: px2rem(2px) solid transparent; + border-radius: px2rem(2px) px2rem(2px) 0 0; + transition: + background-color 250ms, + color 250ms; + + // [print]: Intersperse labels with containers + @media print { + + // Ensure correct order of labels + @for $i from 1 through 20 { + &:nth-child(#{$i}) { + order: $i; + } + } + } + + // Tab label on hover + &:hover { + color: var(--md-default-fg-color); + } + + // Tab label anchor link + > [href]:first-child { + color: inherit; + } + } + + // Tab label with anchor link + &--linked > label { + padding: 0; + + // Move padding one level down to anchor link, so the whole tab area + // becomes clickable, not only the text. + > a { + display: block; + padding: px2em(10px, 12.8px) 1.25em px2em(8px, 12.8px); + } + } + } + + // Tabbed content + .tabbed-content { + width: 100%; + + // [print]: Move one layer up for ordering + @media print { + display: contents; + } + } + + // Tabbed block + .tabbed-block { + display: none; + + // [print]: Intersperse labels with containers + @media print { + display: block; + + // Ensure correct order of containers + @for $i from 1 through 20 { + &:nth-child(#{$i}) { + order: $i; + } + } + } + + // Code block is the first child of a tab - remove margin and mirror + // previous (now deprecated) SuperFences code block grouping behavior + > pre:first-child, + > .highlight:first-child > pre { + margin: 0; + + // Remove rounded borders on code block + > code { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + + // Code block is the first child of a tab - remove margin and mirror + // previous (now deprecated) SuperFences code block grouping behavior + > .highlight:first-child { + + // Code block title - remove spacing and rounded borders + > .filename { + margin: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + // Code block with line numbers - unfortunately, these selectors need to + // be overly specific so they don't bleed into code blocks in annotations. + > .highlighttable { + margin: 0; + + // Remove rounded borders on line numbers and titles + > tbody > tr > .filename span.filename, + > tbody > tr > .linenos { + margin: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + // Remove rounded borders on code blocks + > tbody > tr > .code > div > pre > code { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + + // Code block result container - adjust spacing + + .result { + margin-top: px2em(-2px); + } + } + + // Adjust spacing for nested tabbed container + > .tabbed-set { + margin: 0; + } + } + + // Tabbed button + .tabbed-button { + display: block; + align-self: center; + width: px2rem(18px); + height: px2rem(18px); + margin-top: px2rem(2px); + color: var(--md-default-fg-color--light); + pointer-events: initial; + cursor: pointer; + border-radius: 100%; + transition: background-color 250ms; + + // Tabbed button on hover + &:hover { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + } + + // Tabbed button icon + &::after { + display: block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + mask-image: var(--md-tabbed-icon--prev); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + transition: + background-color 250ms, + transform 250ms; + } + } + + // Tabbed control + .tabbed-control { + position: absolute; + display: flex; + justify-content: start; + width: px2rem(24px); + height: px2rem(38px); + pointer-events: none; + background: + linear-gradient( + to right, + var(--md-default-bg-color) 60%, + transparent + ); + transition: opacity 125ms; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: rotate(180deg); + } + + // Tabbed control is hidden + &[hidden] { + opacity: 0; + } + + // Tabbed control next + &--next { + right: 0; + justify-content: end; + background: + linear-gradient( + to left, + var(--md-default-bg-color) 60%, + transparent + ); + + // Tabbed button icon content + .tabbed-button::after { + mask-image: var(--md-tabbed-icon--next); + } + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: top-level +// ---------------------------------------------------------------------------- + +// [mobile -]: Align with body copy +@include break-to-device(mobile) { + + // Top-level tabbed labels + .md-content__inner > .tabbed-set .tabbed-labels { + max-width: 100vw; + padding-inline-start: px2rem(16px); + margin: 0 px2rem(-16px); + scroll-padding-inline-start: px2rem(16px); + + // Hack: some browsers ignore the right padding on flex containers, + // see https://bit.ly/3lsPS3S + &::after { + padding-inline-end: px2rem(16px); + content: ""; + } + + // Tabbed control previous + ~ .tabbed-control--prev { + width: px2rem(40px); + padding-inline-start: px2rem(16px); + margin-inline-start: px2rem(-16px); + } + + // Tabbed control next + ~ .tabbed-control--next { + width: px2rem(40px); + padding-inline-end: px2rem(16px); + margin-inline-end: px2rem(-16px); + } + } +} + +// ---------------------------------------------------------------------------- +// Placeholders: improve colocation for better compression +// ---------------------------------------------------------------------------- + +// Tab label placeholder +%tabbed-label { + + // [screen]: Show active state + @media screen { + color: var(--md-default-fg-color); + + // [no-js]: Show border (indicator is animated with JavaScript) + .no-js & { + border-color: var(--md-default-fg-color); + } + } +} + +// Tab label on keyboard focus placeholder +%tabbed-label-focus-visible { + color: var(--md-accent-fg-color); +} + +// Tab content placeholder +%tabbed-content { + display: block; +} diff --git a/stylesheets/main/extensions/pymdownx/_tasklist.scss b/stylesheets/main/extensions/pymdownx/_tasklist.scss new file mode 100644 index 0000000..42fe792 --- /dev/null +++ b/stylesheets/main/extensions/pymdownx/_tasklist.scss @@ -0,0 +1,78 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tasklist variables +:root { + --md-tasklist-icon: svg-load("octicons/check-circle-fill-24.svg"); + --md-tasklist-icon--checked: svg-load("octicons/check-circle-fill-24.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Tasklist item + .task-list-item { + position: relative; + list-style-type: none; + + // Make checkbox items align with normal list items, but position + // everything in ems for correct layout at smaller font sizes + [type="checkbox"] { + position: absolute; + inset-inline-start: -2em; + top: 0.45em; + } + } + + // Hide native checkbox, when custom classes are enabled + .task-list-control [type="checkbox"] { + z-index: -1; + opacity: 0; + } + + // Tasklist indicator in unchecked state + .task-list-indicator::before { + position: absolute; + inset-inline-start: px2em(-24px); + top: 0.15em; + width: px2em(20px); + height: px2em(20px); + content: ""; + background-color: var(--md-default-fg-color--lightest); + mask-image: var(--md-tasklist-icon); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + // Tasklist indicator in checked state + [type="checkbox"]:checked + .task-list-indicator::before { + background-color: $clr-green-a400; + mask-image: var(--md-tasklist-icon--checked); + } +} diff --git a/stylesheets/main/integrations/_giscus.scss b/stylesheets/main/integrations/_giscus.scss new file mode 100644 index 0000000..06549d1 --- /dev/null +++ b/stylesheets/main/integrations/_giscus.scss @@ -0,0 +1,39 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// [print]: Hide comment section +@media print { + + // Comments headline + [id="__comments"] { + display: none; + } + + // Comments integration + .giscus { + display: none; + } +} diff --git a/stylesheets/main/integrations/_mermaid.scss b/stylesheets/main/integrations/_mermaid.scss new file mode 100644 index 0000000..b661bc5 --- /dev/null +++ b/stylesheets/main/integrations/_mermaid.scss @@ -0,0 +1,67 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Mermaid variables +:root > * { + --md-mermaid-font-family: var(--md-text-font-family), sans-serif; + + // General colors + --md-mermaid-edge-color: var(--md-code-fg-color); + --md-mermaid-node-bg-color: var(--md-accent-fg-color--transparent); + --md-mermaid-node-fg-color: var(--md-accent-fg-color); + --md-mermaid-label-bg-color: var(--md-default-bg-color); + --md-mermaid-label-fg-color: var(--md-code-fg-color); + + // Sequence diagram colors + --md-mermaid-sequence-actor-bg-color: var(--md-mermaid-label-bg-color); + --md-mermaid-sequence-actor-fg-color: var(--md-mermaid-label-fg-color); + --md-mermaid-sequence-actor-border-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-actor-line-color: var(--md-default-fg-color--lighter); + --md-mermaid-sequence-actorman-bg-color: var(--md-mermaid-label-bg-color); + --md-mermaid-sequence-actorman-line-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-box-bg-color: var(--md-mermaid-node-bg-color); + --md-mermaid-sequence-box-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-label-bg-color: var(--md-mermaid-node-bg-color); + --md-mermaid-sequence-label-fg-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-loop-bg-color: var(--md-mermaid-node-bg-color); + --md-mermaid-sequence-loop-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-loop-border-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-message-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-message-line-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-note-bg-color: var(--md-mermaid-label-bg-color); + --md-mermaid-sequence-note-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-note-border-color: var(--md-mermaid-label-fg-color); + --md-mermaid-sequence-number-bg-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-number-fg-color: var(--md-accent-bg-color); +} + +// ---------------------------------------------------------------------------- + +// Mermaid container +.mermaid { + margin: 1em 0; + line-height: normal; +} diff --git a/stylesheets/main/modifiers/_grid.scss b/stylesheets/main/modifiers/_grid.scss new file mode 100644 index 0000000..9f38512 --- /dev/null +++ b/stylesheets/main/modifiers/_grid.scss @@ -0,0 +1,129 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Grid container + .grid { + display: grid; + grid-template-columns: + repeat( + auto-fit, + minmax( + min(100%, #{px2rem(320px)}), + 1fr + ) + ); + grid-gap: px2rem(8px); + margin: 1em 0; + + // Grid card container - if all grid items should render as cards, the + // `.cards` class can be added, which moves list items up one level. + &.cards > :is(ul, ol) { + display: contents; + } + + // Grid card - a card is either a list item of a grid container with the + // `.cards` class or a single element with the `.card` class, which allows + // to align cards with other components (admonitions, tabs, ...) in grids. + &.cards > :is(ul, ol) > li, + > .card { + display: block; + padding: px2rem(16px); + margin: 0; + border: px2rem(1px) solid var(--md-default-fg-color--lightest); + border-radius: px2rem(2px); + transition: + border 250ms, + box-shadow 250ms; + + // Grid list item on focus/hover + &:is(:focus-within, :hover) { + border-color: transparent; + box-shadow: var(--md-shadow-z2); + } + + // Adjust spacing for horizontal separators + > hr { + margin-block: 1em; + } + + // Adjust spacing on first child + > :first-child { + margin-top: 0; + } + + // Adjust spacing on last child + > :last-child { + margin-bottom: 0; + } + } + + // Grid item + > * { + margin-block: 0; + } + + // Grid item: admonition + > :is(.admonition, details) { + margin-block: 0; + } + + // Grid item: code block + > pre, + > .highlight > *, + > .highlighttable { + margin-block: 0; + } + + // Grid item: code block without line numbers - stretch to match height + // of containing grid item, which must be done explicitly. + > .highlight > pre:only-child, + > .highlight > pre > code { + height: 100%; + } + + // Grid item: code block with line numbers - stretch to match height of + // containing grid item, which is even uglier than the rule before. However, + // it's not possible to achieve this behavior without explicitly setting the + // height on each and every element as we do here. + > .highlighttable, + > .highlighttable > tbody, + > .highlighttable > tbody > tr, + > .highlighttable > tbody > tr > .code, + > .highlighttable > tbody > tr > .code > .highlight, + > .highlighttable > tbody > tr > .code > .highlight > pre, + > .highlighttable > tbody > tr > .code > .highlight > pre > code { + height: 100%; + } + + // Grid item: tabbed container + > .tabbed-set { + margin-block: 0; + } + } +} diff --git a/stylesheets/main/modifiers/_inline.scss b/stylesheets/main/modifiers/_inline.scss new file mode 100644 index 0000000..b324fa6 --- /dev/null +++ b/stylesheets/main/modifiers/_inline.scss @@ -0,0 +1,48 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // [tablet +]: Allow for rendering content as sidebars + @include break-from-device(tablet) { + + // Modifier to float block elements + .inline { + float: inline-start; + width: px2rem(234px); + margin-inline-end: px2rem(16px); + margin-top: 0; + margin-bottom: px2rem(16px); + + // Modifier to move to end (ltr: right, rtl: left) + &.end { + float: inline-end; + margin-inline: px2rem(16px) 0; + } + } + } +} diff --git a/stylesheets/mystyle.css b/stylesheets/mystyle.css index afe8773..fe94927 100644 --- a/stylesheets/mystyle.css +++ b/stylesheets/mystyle.css @@ -1,9 +1,9 @@ -body { - font-family: "LXGW WenKai", sans-serif; - /* Lite version */ - /* font-family: "LXGW WenKai Lite", sans-serif; */ - /* TC version */ - /* font-family: "LXGW WenKai TC", sans-serif; */ - /* Screen version */ - /* font-family: "LXGW WenKai Screen", sans-serif; */ - } +body { + font-family: "LXGW WenKai", sans-serif; + /* Lite version */ + /* font-family: "LXGW WenKai Lite", sans-serif; */ + /* TC version */ + /* font-family: "LXGW WenKai TC", sans-serif; */ + /* Screen version */ + /* font-family: "LXGW WenKai Screen", sans-serif; */ + } diff --git a/stylesheets/palette.scss b/stylesheets/palette.scss new file mode 100644 index 0000000..dcb130d --- /dev/null +++ b/stylesheets/palette.scss @@ -0,0 +1,40 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Dependencies +// ---------------------------------------------------------------------------- + +@import "material-color"; + +// ---------------------------------------------------------------------------- +// Local imports +// ---------------------------------------------------------------------------- + +@import "utilities/break"; +@import "utilities/convert"; + +@import "config"; + +@import "palette/scheme"; +@import "palette/accent"; +@import "palette/primary"; diff --git a/stylesheets/palette/_accent.scss b/stylesheets/palette/_accent.scss new file mode 100644 index 0000000..411e909 --- /dev/null +++ b/stylesheets/palette/_accent.scss @@ -0,0 +1,61 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Define accent colors +@each $name, $color in ( + "red": $clr-red-a400, + "pink": $clr-pink-a400, + "purple": $clr-purple-a200, + "deep-purple": $clr-deep-purple-a200, + "indigo": $clr-indigo-a200, + "blue": $clr-blue-a200, + "light-blue": $clr-light-blue-a700, + "cyan": $clr-cyan-a700, + "teal": $clr-teal-a700, + "green": $clr-green-a700, + "light-green": $clr-light-green-a700, + "lime": $clr-lime-a700, + "yellow": $clr-yellow-a700, + "amber": $clr-amber-a700, + "orange": $clr-orange-a400, + "deep-orange": $clr-deep-orange-a200 +) { + + // Color palette + [data-md-color-accent="#{$name}"] { + --md-accent-fg-color: hsla(#{hex2hsl($color)}, 1); + --md-accent-fg-color--transparent: hsla(#{hex2hsl($color)}, 0.1); + + // Inverted text for lighter shades + @if index("lime" "yellow" "amber" "orange", $name) { + --md-accent-bg-color: hsla(0, 0%, 0%, 0.87); + --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54); + } @else { + --md-accent-bg-color: hsla(0, 0%, 100%, 1); + --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7); + } + } +} diff --git a/stylesheets/palette/_primary.scss b/stylesheets/palette/_primary.scss new file mode 100644 index 0000000..c723072 --- /dev/null +++ b/stylesheets/palette/_primary.scss @@ -0,0 +1,203 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:list"; + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Define primary colors +@each $name, $colors in ( + "red": $clr-red-400 $clr-red-300 $clr-red-600, + "pink": $clr-pink-500 $clr-pink-400 $clr-pink-700, + "purple": $clr-purple-400 $clr-purple-300 $clr-purple-600, + "deep-purple": $clr-deep-purple-400 $clr-deep-purple-300 $clr-deep-purple-500, + "indigo": $clr-indigo-500 $clr-indigo-400 $clr-indigo-700, + "blue": $clr-blue-500 $clr-blue-400 $clr-blue-700, + "light-blue": $clr-light-blue-500 $clr-light-blue-400 $clr-light-blue-700, + "cyan": $clr-cyan-500 $clr-cyan-400 $clr-cyan-700, + "teal": $clr-teal-500 $clr-teal-400 $clr-teal-700, + "green": $clr-green-500 $clr-green-400 $clr-green-700, + "light-green": $clr-light-green-500 $clr-light-green-400 $clr-light-green-700, + "lime": $clr-lime-500 $clr-lime-400 $clr-lime-700, + "yellow": $clr-yellow-500 $clr-yellow-400 $clr-yellow-700, + "amber": $clr-amber-500 $clr-amber-400 $clr-amber-700, + "orange": $clr-orange-400 $clr-orange-400 $clr-orange-600, + "deep-orange": $clr-deep-orange-400 $clr-deep-orange-300 $clr-deep-orange-600, + "brown": $clr-brown-500 $clr-brown-400 $clr-brown-700, + "grey": $clr-grey-600 $clr-grey-500 $clr-grey-700, + "blue-grey": $clr-blue-grey-600 $clr-blue-grey-500 $clr-blue-grey-700 +) { + + // Color palette + [data-md-color-primary="#{$name}"] { + --md-primary-fg-color: hsl(#{hex2hsl(list.nth($colors, 1))}); + --md-primary-fg-color--light: hsl(#{hex2hsl(list.nth($colors, 2))}); + --md-primary-fg-color--dark: hsl(#{hex2hsl(list.nth($colors, 3))}); + + // Inverted text for lighter shades + @if index("lime" "yellow" "amber" "orange", $name) { + --md-primary-bg-color: hsla(0, 0%, 0%, 0.87); + --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54); + } @else { + --md-primary-bg-color: hsla(0, 0%, 100%, 1); + --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); + } + + // Typeset color shades + @if index("grey" "blue-grey", $name) { + --md-typeset-a-color: hsl(#{hex2hsl($clr-indigo-500)}); + } + } +} + +// ---------------------------------------------------------------------------- + +// Adjust link colors for light primary colors +@each $name, $color in ( + "light-green": hsl(88, 58%, 43%), + "lime": hsl(66, 88%, 32%), + "yellow": hsl(54, 100%, 36%), + "amber": hsl(45, 100%, 41%), + "orange": hsl(36, 100%, 45%) +) { + [data-md-color-primary="#{$name}"]:not([data-md-color-scheme="slate"]) { + --md-typeset-a-color: #{$color}; + } +} + +// ---------------------------------------------------------------------------- +// Rules: white +// ---------------------------------------------------------------------------- + +// Define primary colors for white +[data-md-color-primary="white"] { + --md-primary-fg-color: hsla(var(--md-hue), 0%, 100%, 1); + --md-primary-fg-color--light: hsla(var(--md-hue), 0%, 100%, 0.7); + --md-primary-fg-color--dark: hsla(var(--md-hue), 0%, 0%, 0.07); + --md-primary-bg-color: hsla(var(--md-hue), 0%, 0%, 0.87); + --md-primary-bg-color--light: hsla(var(--md-hue), 0%, 0%, 0.54); + + // Typeset `a` color shades + --md-typeset-a-color: hsl(#{hex2hsl($clr-indigo-500)}); + + // Form button + .md-button { + color: var(--md-typeset-a-color); + + // Primary button + &--primary { + color: hsla(var(--md-hue), 0%, 100%, 1); + background-color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + } + } + + // [tablet portrait +]: Header-embedded search + @include break-from-device(tablet landscape) { + + // Search form + .md-search__form { + background-color: hsla(var(--md-hue), 0%, 0%, 0.07); + + // Search form on hover + &:hover { + background-color: hsla(var(--md-hue), 0%, 0%, 0.32); + } + } + + // Search icon + .md-search__input + .md-search__icon { + color: hsla(var(--md-hue), 0%, 0%, 0.87); + } + } + + // [screen +]: Add bottom border for tabs + @include break-from-device(screen) { + + // Navigation tabs + .md-tabs { + border-bottom: px2rem(1px) solid hsla(0, 0%, 0%, 0.07); + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: black +// ---------------------------------------------------------------------------- + +// Define primary colors for black +[data-md-color-primary="black"] { + --md-primary-fg-color: hsla(var(--md-hue), 15%, 9%, 1); + --md-primary-fg-color--light: hsla(var(--md-hue), 15%, 9%, 0.54); + --md-primary-fg-color--dark: hsla(var(--md-hue), 15%, 9%, 1); + --md-primary-bg-color: hsla(var(--md-hue), 15%, 100%, 1); + --md-primary-bg-color--light: hsla(var(--md-hue), 15%, 100%, 0.7); + + // Typeset `a` color shades + --md-typeset-a-color: hsl(#{hex2hsl($clr-indigo-500)}); + + // Form button + .md-button { + color: var(--md-typeset-a-color); + + // Primary button + &--primary { + color: hsla(var(--md-hue), 0%, 100%, 1); + background-color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + } + } + + // Header + .md-header { + background-color: hsla(var(--md-hue), 15%, 9%, 1); + } + + // [tablet portrait -]: Layered navigation + @include break-to-device(tablet portrait) { + + // Repository information container + .md-nav__source { + background-color: hsla(var(--md-hue), 15%, 11%, 0.87); + } + } + + // [tablet -]: Layered navigation + @include break-to-device(tablet) { + + // Site title in main navigation + html & .md-nav--primary .md-nav__title[for="__drawer"] { + background-color: hsla(var(--md-hue), 15%, 9%, 1); + } + } + + // [screen +]: Set background color for tabs + @include break-from-device(screen) { + + // Navigation tabs + .md-tabs { + background-color: hsla(var(--md-hue), 15%, 9%, 1); + } + } +} diff --git a/stylesheets/palette/_scheme.scss b/stylesheets/palette/_scheme.scss new file mode 100644 index 0000000..5048ba1 --- /dev/null +++ b/stylesheets/palette/_scheme.scss @@ -0,0 +1,148 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Only use dark mode on screens +@media screen { + + // Slate theme, i.e. dark mode + [data-md-color-scheme="slate"] { + + // Indicate that the site is rendered with a dark color scheme + color-scheme: dark; + + // Default color shades + --md-default-fg-color: hsla(var(--md-hue), 15%, 90%, 0.82); + --md-default-fg-color--light: hsla(var(--md-hue), 15%, 90%, 0.56); + --md-default-fg-color--lighter: hsla(var(--md-hue), 15%, 90%, 0.32); + --md-default-fg-color--lightest: hsla(var(--md-hue), 15%, 90%, 0.12); + --md-default-bg-color: hsla(var(--md-hue), 15%, 14%, 1); + --md-default-bg-color--light: hsla(var(--md-hue), 15%, 14%, 0.54); + --md-default-bg-color--lighter: hsla(var(--md-hue), 15%, 14%, 0.26); + --md-default-bg-color--lightest: hsla(var(--md-hue), 15%, 14%, 0.07); + + // Code color shades + --md-code-fg-color: hsla(var(--md-hue), 18%, 86%, 0.82); + --md-code-bg-color: hsla(var(--md-hue), 15%, 18%, 1); + + // Code highlighting color shades + --md-code-hl-color: hsla(#{hex2hsl($clr-blue-a400)}, 1); + --md-code-hl-color--light: hsla(#{hex2hsl($clr-blue-a400)}, 0.1); + + // Code highlighting syntax color shades + --md-code-hl-number-color: hsla(6, 74%, 63%, 1); + --md-code-hl-special-color: hsla(340, 83%, 66%, 1); + --md-code-hl-function-color: hsla(291, 57%, 65%, 1); + --md-code-hl-constant-color: hsla(250, 62%, 70%, 1); + --md-code-hl-keyword-color: hsla(219, 66%, 64%, 1); + --md-code-hl-string-color: hsla(150, 58%, 44%, 1); + --md-code-hl-name-color: var(--md-code-fg-color); + --md-code-hl-operator-color: var(--md-default-fg-color--light); + --md-code-hl-punctuation-color: var(--md-default-fg-color--light); + --md-code-hl-comment-color: var(--md-default-fg-color--light); + --md-code-hl-generic-color: var(--md-default-fg-color--light); + --md-code-hl-variable-color: var(--md-default-fg-color--light); + + // Typeset color shades + --md-typeset-color: var(--md-default-fg-color); + + // Typeset `a` color shades + --md-typeset-a-color: var(--md-primary-fg-color); + + // Typeset `kbd` color shades + --md-typeset-kbd-color: hsla(var(--md-hue), 15%, 90%, 0.12); + --md-typeset-kbd-accent-color: hsla(var(--md-hue), 15%, 90%, 0.2); + --md-typeset-kbd-border-color: hsla(var(--md-hue), 15%, 14%, 1); + + // Typeset `mark` color shades + --md-typeset-mark-color: hsla(#{hex2hsl($clr-blue-a200)}, 0.3); + + // Typeset `table` color shades + --md-typeset-table-color: hsla(var(--md-hue), 15%, 95%, 0.12); + --md-typeset-table-color--light: hsla(var(--md-hue), 15%, 95%, 0.035); + + // Admonition color shades + --md-admonition-fg-color: var(--md-default-fg-color); + --md-admonition-bg-color: var(--md-default-bg-color); + + // Footer color shades + --md-footer-bg-color: hsla(var(--md-hue), 15%, 10%, 0.87); + --md-footer-bg-color--dark: hsla(var(--md-hue), 15%, 8%, 1); + + // Shadow depth 1 + --md-shadow-z1: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.05), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.1); + + // Shadow depth 2 + --md-shadow-z2: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.25), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.25); + + // Shadow depth 3 + --md-shadow-z3: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.4), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.35); + + // Hide images for light mode + img[src$="#only-light"], + img[src$="#gh-light-mode-only"] { + display: none; + } + } + + // -------------------------------------------------------------------------- + + // Adjust link colors for dark primary colors + @each $name, $color in ( + "pink": hsl(340, 81%, 63%), + "purple": hsl(291, 53%, 63%), + "deep-purple": hsl(262, 73%, 70%), + "indigo": hsl(219, 76%, 62%), + "teal": hsl(174, 100%, 40%), + "green": hsl(122, 39%, 60%), + "deep-orange": hsl(14, 100%, 65%), + "brown": hsl(16, 45%, 56%), + + // Set neutral colors to indigo + "grey": hsl(219, 66%, 62%), + "blue-grey": hsl(219, 66%, 62%), + "white": hsl(219, 66%, 62%), + "black": hsl(219, 66%, 62%) + ) { + [data-md-color-scheme="slate"][data-md-color-primary="#{$name}"] { + --md-typeset-a-color: #{$color}; + } + } + + // -------------------------------------------------------------------------- + + // Switching in progress - disable all transitions temporarily + [data-md-color-switching] *, + [data-md-color-switching] *::before, + [data-md-color-switching] *::after { + transition-duration: 0ms !important; // stylelint-disable-line + } +} diff --git a/stylesheets/utilities/_break.scss b/stylesheets/utilities/_break.scss new file mode 100644 index 0000000..38ace9f --- /dev/null +++ b/stylesheets/utilities/_break.scss @@ -0,0 +1,219 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:list"; +@use "sass:map"; +@use "sass:math"; + +// ---------------------------------------------------------------------------- +// Variables +// ---------------------------------------------------------------------------- + +/// +/// Device-specific breakpoints +/// +/// @example +/// $break-devices: ( +/// mobile: ( +/// portrait: 220px 479px, +/// landscape: 480px 719px +/// ), +/// tablet: ( +/// portrait: 720px 959px, +/// landscape: 960px 1219px +/// ), +/// screen: ( +/// small: 1220px 1599px, +/// medium: 1600px 1999px, +/// large: 2000px +/// ) +/// ); +/// +$break-devices: () !default; + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +/// +/// Choose minimum and maximum device widths +/// +@function break-select-min-max($devices) { + $min: 1000000; + $max: 0; + @each $key, $value in $devices { + @while type-of($value) == map { + $value: break-select-min-max($value); + } + @if type-of($value) == list { + @each $number in $value { + @if type-of($number) == number { + $min: math.min($number, $min); + @if $max { + $max: math.max($number, $max); + } + } @else { + @error "Invalid number: #{$number}"; + } + } + } @else if type-of($value) == number { + $min: math.min($value, $min); + $max: null; + } @else { + @error "Invalid value: #{$value}"; + } + } + @return $min, $max; +} + +/// +/// Select minimum and maximum widths for a device breakpoint +/// +@function break-select-device($device) { + $current: $break-devices; + @for $n from 1 through length($device) { + @if type-of($current) == map { + $current: map.get($current, list.nth($device, $n)); + } @else { + @error "Invalid device map: #{$devices}"; + } + } + @if type-of($current) == list or type-of($current) == number { + $current: (default: $current); + } + @return break-select-min-max($current); +} + +// ---------------------------------------------------------------------------- +// Mixins +// ---------------------------------------------------------------------------- + +/// +/// A minimum-maximum media query breakpoint +/// +@mixin break-at($breakpoint) { + @if type-of($breakpoint) == number { + @media screen and (min-width: $breakpoint) { + @content; + } + } @else if type-of($breakpoint) == list { + $min: list.nth($breakpoint, 1); + $max: list.nth($breakpoint, 2); + @if type-of($min) == number and type-of($max) == number { + @media screen and (min-width: $min) and (max-width: $max) { + @content; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } +} + +/// +/// An orientation media query breakpoint +/// +@mixin break-at-orientation($breakpoint) { + @if type-of($breakpoint) == string { + @media screen and (orientation: $breakpoint) { + @content; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } +} + +/// +/// A maximum-aspect-ratio media query breakpoint +/// +@mixin break-at-ratio($breakpoint) { + @if type-of($breakpoint) == number { + @media screen and (max-aspect-ratio: $breakpoint) { + @content; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } +} + +/// +/// A minimum-maximum media query device breakpoint +/// +@mixin break-at-device($device) { + @if type-of($device) == string { + $device: $device,; + } + @if type-of($device) == list { + $breakpoint: break-select-device($device); + @if list.nth($breakpoint, 2) { + $min: list.nth($breakpoint, 1); + $max: list.nth($breakpoint, 2); + + @media screen and (min-width: $min) and (max-width: $max) { + @content; + } + } @else { + @error "Invalid device: #{$device}"; + } + } @else { + @error "Invalid device: #{$device}"; + } +} + +/// +/// A minimum media query device breakpoint +/// +@mixin break-from-device($device) { + @if type-of($device) == string { + $device: $device,; + } + @if type-of($device) == list { + $breakpoint: break-select-device($device); + $min: list.nth($breakpoint, 1); + + @media screen and (min-width: $min) { + @content; + } + } @else { + @error "Invalid device: #{$device}"; + } +} + +/// +/// A maximum media query device breakpoint +/// +@mixin break-to-device($device) { + @if type-of($device) == string { + $device: $device,; + } + @if type-of($device) == list { + $breakpoint: break-select-device($device); + $max: list.nth($breakpoint, 2); + + @media screen and (max-width: $max) { + @content; + } + } @else { + @error "Invalid device: #{$device}"; + } +} diff --git a/stylesheets/utilities/_convert.scss b/stylesheets/utilities/_convert.scss new file mode 100644 index 0000000..c53b4f8 --- /dev/null +++ b/stylesheets/utilities/_convert.scss @@ -0,0 +1,80 @@ +//// +/// Copyright (c) 2016-2024 Martin Donath +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:color"; +@use "sass:math"; + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +/// +/// Strip units from a number +/// +@function strip-units($number) { + @return math.div($number, ($number * 0 + 1)); +} + +/// +/// Convert color in HEX to HSL +/// +/// Note, that we need to strip the `deg` units from the `hue` value, as they +/// were added in Color Level 4, which not all browsers support. +/// +@function hex2hsl($color) { + @return + round(strip-units(color.channel($color, "hue", $space: hsl))), + round(color.channel($color, "saturation", $space: hsl)), + round(color.channel($color, "lightness", $space: hsl)); +} + +// ---------------------------------------------------------------------------- + +/// +/// Convert font size in px to em +/// +@function px2em($size, $base: 16px) { + @if unit($size) == px { + @if unit($base) == px { + @return math.div($size, $base) * 1em; + } @else { + @error "Invalid base: #{$base} - unit must be 'px'"; + } + } @else { + @error "Invalid size: #{$size} - unit must be 'px'"; + } +} + +/// +/// Convert font size in px to rem +/// +@function px2rem($size, $base: 20px) { + @if unit($size) == px { + @if unit($base) == px { + @return math.div($size, $base) * 1rem; + } @else { + @error "Invalid base: #{$base} - unit must be 'px'"; + } + } @else { + @error "Invalid size: #{$size} - unit must be 'px'"; + } +} diff --git a/tech-sslh/index.html b/tech-sslh/index.html index c69b7b0..3a8c44f 100644 --- a/tech-sslh/index.html +++ b/tech-sslh/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

sslh 阅读笔记

约 1131 个字 99 行代码 预计阅读时间 14 分钟

最近在读sslh的源码,感觉还是比较有意思的。之前在端口复用里面简单提了下sslh的用法,但是在实践中踩了不少坑,所以把源码拿来读一读,看看内部的结构。

sslh似乎是使用第一个数据包保存的协议信息,为客户端与服务器对应服务建立连接。后续数据包不再需要检查协议了。

便捷上手

apt install sslh # 但最好还是从源码make install,用最新版本;参考仓库的INSTALL安装对应的C库
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

sslh 阅读笔记

约 1131 个字 99 行代码 预计阅读时间 14 分钟

最近在读sslh的源码,感觉还是比较有意思的。之前在端口复用里面简单提了下sslh的用法,但是在实践中踩了不少坑,所以把源码拿来读一读,看看内部的结构。

sslh似乎是使用第一个数据包保存的协议信息,为客户端与服务器对应服务建立连接。后续数据包不再需要检查协议了。

便捷上手

apt install sslh # 但最好还是从源码make install,用最新版本;参考仓库的INSTALL安装对应的C库
 vi /etc/default/sslh
 systemctl start sslh
 

似乎cfg文件里和command line会有冲突。所以commandline用-F /etc/sslh/sslh.cfg(没有则新建一个)指定的配置文件中,不要有和command重复的内容。只放protocols差不多就得了。比较好用的是正则和tls中根据alpn和sni来匹配。

下面是完整的配置文件的一个例子,如果数据包包含”OK1”或者”OK2”,则会被转发到127.0.0.1:1234。其中的name字段表示这条协议在sslh启动后怎么配置,常见的比如regexsshtlshttp

注意,最后一条协议的分号后面不加逗号。

protocols:
@@ -106,6 +106,40 @@
 
 # catch anything else TLS
      { name: "tls"; host: "localhost"; port: "443";  tfo_ok: true },
-

alpn_protocols即使用应用层协议协商编号:TLS Application-Layer Protocol Negotiation (ALPN) Protocol ID。可以在这里看到完整的格式。打个比方,如果说数据包是饺子,tls是饺子皮,ALPN就是表示里面是什么馅的。

sni_hostnames即使用服务器名称指示:Server Name Indication(SNI),类似于服务器端的域名。打个比方,虽然在学校快递(数据包)都会送到菜鸟驿站(服务器),但这些包裹最终是流向不同的宿舍的(SNI)。SNI帮助在tls握手期间就确定ssl证书,而不是在http建立连接后。FQDN指的是Fully Qualified Domain Name,即完整域名,可以看这里的介绍。

sni_hostname和alpn_protocols,属于tls扩展内容,并非强制保留其中。发包的时候注意添加,不然sslh可能识别不到。

\ No newline at end of file diff --git a/try-chatgpt/index.html b/try-chatgpt/index.html index b9c4157..1fb7e23 100644 --- a/try-chatgpt/index.html +++ b/try-chatgpt/index.html @@ -7,10 +7,44 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

ChatGPT来帮忙

约 1574 个字 3 行代码 预计阅读时间 6 分钟

网络站点打包下载

linux用哪个命令可以把一个网址以及其所依赖的js和css等等文件自动下载下来?

在Linux中,你可以使用 wget 命令来自动下载一个网站及其依赖的资源文件(如JS和CSS等)。

下面是一个示例命令:

wget --recursive --no-clobber --page-requisites --html-extension --convert-links --restrict-file-names=windows --domains website.com --no-parent http://website.com
+    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

ChatGPT来帮忙

约 1574 个字 3 行代码 预计阅读时间 6 分钟

网络站点打包下载

linux用哪个命令可以把一个网址以及其所依赖的js和css等等文件自动下载下来?

在Linux中,你可以使用 wget 命令来自动下载一个网站及其依赖的资源文件(如JS和CSS等)。

下面是一个示例命令:

wget --recursive --no-clobber --page-requisites --html-extension --convert-links --restrict-file-names=windows --domains website.com --no-parent http://website.com
 
该命令使用了多个选项,其中一些选项的含义如下:

–recursive: 下载网站的所有链接。 –no-clobber: 不会重复下载已经存在的文件。 –page-requisites: 下载所有页面的资源(如图像,音频和视频)。 –html-extension: 将所有HTML文件扩展名添加为 .html。 –convert-links: 将所有链接转换为本地链接。 –restrict-file-names=windows: 避免使用 Linux 不支持的文件名字符。 –domains website.com: 限制下载的域名范围。 –no-parent: 不会下载父级链接(有助于防止无限递归)。

你可以根据自己的需要修改这些选项以满足特定的要求。

用这条命令被服务器发现恶意下载,被给403 forbidden了怎么办?

如果你使用的命令被服务器认为是恶意下载,并且被服务器拒绝访问,那么你可以考虑以下一些方法来解决这个问题:

修改下载速度:有些服务器可能会限制下载速度,如果你下载的太快,就会被认为是攻击。你可以尝试使用 –limit-rate 选项来限制下载速度,例如:

wget --limit-rate=200k http://example.com
 

修改下载并发数:类似于速度限制,一些服务器也会限制同时进行的下载数。你可以尝试使用 –tries 和 –wait 选项来限制并发下载数,例如:

wget --tries=10 --wait=5 http://example.com
 
添加 User-Agent:有些服务器可能会检查 User-Agent,如果 User-Agent 被认为是恶意的,那么你的请求也会被拒绝。你可以尝试使用 –user-agent 选项来设置 User-Agent,例如:

wget --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" http://example.com
-

与服务器管理员联系:如果以上方法都不能解决问题,你可以联系服务器管理员,说明你的下载请求是合法的,请求他们放行你的请求。 需要注意的是,不要使用非法的方式下载文件,以免侵犯他人的合法权益,并有可能导致法律纠纷。

比较Go、Python、Rust的关系

go、rust、python三种编程语言在语言特性方面有什么区别?各自有什么优势?适用场景有什么区别?

这三种编程语言各有不同的特点和优势,以下是它们的主要区别和适用场景:

Python Python 是一种高级的动态解释型语言,具有简单易学、易读易写的特点。它的语法简单、代码可读性高、支持多种编程范式和丰富的第三方库,适用于各种类型的应用程序开发,尤其擅长数据分析、人工智能和科学计算领域。由于它的开发效率高,常被用于快速原型设计和敏捷开发。

Go Go 是一种开源的编译型语言,由 Google 开发。它的设计目标是为了解决多核、网络、大规模程序开发等问题,具有高效、可靠、简洁等特点。Go 语言在并发编程和网络编程方面表现突出,有着非常高效的 Goroutine 和 Channel 机制,适合于高并发、分布式系统、云计算等领域的开发。

Rust Rust 是一种系统级的编程语言,由 Mozilla 开发。它结合了高效性能、内存安全和并发安全,提供了一个可靠和安全的编程环境。Rust 的主要优势在于其内存安全性和并发性,它具有高效的编译器、丰富的类型系统和高级的模式匹配功能,适用于需要高性能和安全性的系统级编程、网络编程、操作系统和嵌入式开发等领域。

总的来说,Python 适合快速原型设计和敏捷开发,Go 适合高并发、分布式系统和云计算,Rust 适合需要高性能和安全性的系统级编程、网络编程、操作系统和嵌入式开发。选择哪种编程语言取决于具体的应用场景和需求。

计算机安全资源学习

我想学习工业界实用的计算机安全领域的知识,请推荐一些网站

以下是一些可以帮助您学习工业界实用的计算机安全领域的知识的网站:

OWASP (开放式网络安全项目):这个网站提供了大量有关网络应用程序安全的资料和工具。您可以在这里找到安全标准、漏洞检测工具、攻击模拟器等等。

NIST (美国国家标准与技术研究所):这个网站为计算机安全和信息技术提供标准和指南。您可以在这里找到有关安全控制、密码学、风险评估等方面的资料。

SANS (安全培训和认证机构):这个网站提供有关各种计算机安全主题的培训和课程。它还提供了一个博客,其中包含各种有关网络安全的文章和提示。

Dark Reading:这是一家在线出版商,提供了有关网络安全的最新新闻、分析和评论。它还提供了各种资源,包括网络安全白皮书、研究报告和演示文稿。

SecurityFocus:这个网站是一个安全新闻聚合站点,收集了来自各种来源的安全新闻和漏洞报告。它还提供了安全论坛、安全工具等。

Reddit:Reddit上有许多与计算机安全相关的社区,如r/netsec、r/hacking、r/AskNetsec等。这些社区可以让您向其他安全专业人员提问,并与他们分享有用的资源和工具。

GitHub:GitHub是一个软件开发平台,也是许多安全工具和脚本的来源。通过搜索GitHub,您可以找到很多有用的工具,如渗透测试工具、漏洞扫描器等等。

希望这些网站能对您有所帮助!

\ No newline at end of file diff --git a/word-learning/index.html b/word-learning/index.html index f07ef75..baba9ff 100644 --- a/word-learning/index.html +++ b/word-learning/index.html @@ -7,6 +7,40 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

词汇学习

约 943 个字 预计阅读时间 3 分钟

  • encyclopedic 广博的
  • unprecedented 史无前例的,空前的
  • bluntly 直言不讳地
  • as per some estimates 根据一些估计
  • indispensable 必不可少的
  • to name just a few 仅举几例
  • discriminate 鉴别,区别;有区别的
  • remediation 整治
  • cumbersome 繁琐的
  • drastically 剧烈地
  • impede 阻碍
  • stochastic 随机的
  • sharp-edged plateau
  • saturating 饱和的
  • avert 避免,纾解
  • delineation 划定
  • nuisance 滋扰
  • menace 威胁,危险的人或物
  • dismantle 拆开,拆卸,废除
  • undermine 暗中破坏,从根基处损坏
  • provoke 激起,引起
  • ransomware 勒索软件
  • withstand 抵挡,经受住,抵抗
  • camouflage 伪装,隐蔽,欺瞒
  • influx 大量涌入,汇集
  • nullify 使无效,作废,取消
  • calibrate 校准
  • ameliorate 改善,改良
  • prolifical 多产的
  • henceforth 从今以后,今后
  • surmise 推测
  • smuggle 走私
  • prudent 谨慎的
  • intriguing 有趣的,迷人的
  • byproduct 副产品,意外结果
  • inconspicuous 不明显的 不引人注目的
  • brittle 易碎的,难以相处的,尖刻暴躁的,冷淡的
  • deceive 欺骗,误导
  • versatility 多才多艺,多用途,易变,可转动性
  • inflate 使膨胀,使充气,物价上涨
  • conflate 合并,混合
  • incentive 动机,刺激,诱因,鼓励
  • bounty 赏金,奖金,赠物
  • exacerbate 使恶化,使加重
  • fluctuation 波动,涨落,起伏
  • susceptible 易受影响的,易受感染的,可以接受或允许的
  • extraneous 外来的,外部的,无关的
  • amenable (对法律等)负责的,易控制的;经得起检验或考查的
  • vicinity 附近,临近,附近地区,大约的程度或数量
  • retention 保留,记忆力,保持力,滞留,扣留
  • suffice 足够,有能力,满足……的需要,使满足
  • rudimentary 简陋的
  • inadvertently 漫不经心地,疏忽地
  • cease 停止,终止
  • collectively 全体地,共同地
  • daunting 令人畏惧的,使人气馁的
  • encompass 围绕,包围,包含,包括
  • devastating 毁灭性的,令人震惊的
  • retrofit 给机器设备装配(新部件),翻新,改型
  • yield to 让步于,使自己受到xxx的支配
  • sterilizer 消毒者,消毒器
  • salient 显著的,突出的,跳跃的,(角)凸出的
  • nuanced 有细微差别的
  • discern 察觉出,了解;分辨出
  • subsidised 补贴的
  • culprit 犯人,罪犯
  • holistic 全盘的,整体的,功能整体性的
  • endeavor 努力,尽力
  • influx 注入,流入,汇集
  • plausible 貌似真实的,貌似有理的,花言巧语的
  • pertain 有关,存在,适用
  • obsolescence 废弃,陈旧过时,(器官)废退
  • resort to 诉诸,依靠,求助于
  • discrepancy 差异,不一致,区别
  • impair 损害,削弱
  • hefty 重的,健壮的,异常大的,重量级的
  • paucity 少量,缺乏,不足,缺少
  • obstruct 阻碍,阻止,妨碍
  • retention 保留,记忆力,滞留,扣留
  • envision 设想,预想 vt.
  • remediate 补救,治疗,矫正,修复
  • conundrum 谜语,难解的问题
  • depict 展示,描述,显示
  • expedite 加快进展
  • remedy 治疗法,改正,改进,补救
  • instinctive reaction 本能反应
  • deem 认为,视为,相信
  • detour 绕路,绕道,弯路
  • futile 无效的,没用的
  • the hassle of sth. 某事带来的麻烦
  • unencumbered 没有阻碍的,不受妨碍的,无负担的
  • idiosyncrasy (某人特有的)气质,习性,癖好
  • crowdsource 众包
  • stabilize 固定,防止……波动
  • encompass 围绕,包围,完成
  • obviate 避免,消除(贫困、不方便等)
  • conducive to有助于……的,有益于……的
  • pertain to 有关,关于
  • arduous 努力的,艰巨的,难克服的
  • plow 犁,耕, 费力穿过
  • imperative 必要的,不可避免的;必要的事,命令,规则
  • notoriously 臭名昭著地,众所周知地
  • culprit 犯人,罪犯,被告人,肇事者
  • succinct 简洁的
  • reciprocal 互惠的,倒数
  • inadvertent 不经意的,疏忽的
  • disseminate 散布,传播(问卷等)
  • elicitation 引出,启发
  • obsolete 废弃的,老式的,已过时的
  • In particular, it works like SBFL, where a bug-inducing commit and a non-inducing commit are analogous(相似的,可比拟的) to a failing test and a passing test in SBFL, respectively.
  • The effectiveness of recurrent neural network is marginally(略微地) higher than multi-layer perceptron.

词汇学习

约 943 个字 预计阅读时间 3 分钟

  • encyclopedic 广博的
  • unprecedented 史无前例的,空前的
  • bluntly 直言不讳地
  • as per some estimates 根据一些估计
  • indispensable 必不可少的
  • to name just a few 仅举几例
  • discriminate 鉴别,区别;有区别的
  • remediation 整治
  • cumbersome 繁琐的
  • drastically 剧烈地
  • impede 阻碍
  • stochastic 随机的
  • sharp-edged plateau
  • saturating 饱和的
  • avert 避免,纾解
  • delineation 划定
  • nuisance 滋扰
  • menace 威胁,危险的人或物
  • dismantle 拆开,拆卸,废除
  • undermine 暗中破坏,从根基处损坏
  • provoke 激起,引起
  • ransomware 勒索软件
  • withstand 抵挡,经受住,抵抗
  • camouflage 伪装,隐蔽,欺瞒
  • influx 大量涌入,汇集
  • nullify 使无效,作废,取消
  • calibrate 校准
  • ameliorate 改善,改良
  • prolifical 多产的
  • henceforth 从今以后,今后
  • surmise 推测
  • smuggle 走私
  • prudent 谨慎的
  • intriguing 有趣的,迷人的
  • byproduct 副产品,意外结果
  • inconspicuous 不明显的 不引人注目的
  • brittle 易碎的,难以相处的,尖刻暴躁的,冷淡的
  • deceive 欺骗,误导
  • versatility 多才多艺,多用途,易变,可转动性
  • inflate 使膨胀,使充气,物价上涨
  • conflate 合并,混合
  • incentive 动机,刺激,诱因,鼓励
  • bounty 赏金,奖金,赠物
  • exacerbate 使恶化,使加重
  • fluctuation 波动,涨落,起伏
  • susceptible 易受影响的,易受感染的,可以接受或允许的
  • extraneous 外来的,外部的,无关的
  • amenable (对法律等)负责的,易控制的;经得起检验或考查的
  • vicinity 附近,临近,附近地区,大约的程度或数量
  • retention 保留,记忆力,保持力,滞留,扣留
  • suffice 足够,有能力,满足……的需要,使满足
  • rudimentary 简陋的
  • inadvertently 漫不经心地,疏忽地
  • cease 停止,终止
  • collectively 全体地,共同地
  • daunting 令人畏惧的,使人气馁的
  • encompass 围绕,包围,包含,包括
  • devastating 毁灭性的,令人震惊的
  • retrofit 给机器设备装配(新部件),翻新,改型
  • yield to 让步于,使自己受到xxx的支配
  • sterilizer 消毒者,消毒器
  • salient 显著的,突出的,跳跃的,(角)凸出的
  • nuanced 有细微差别的
  • discern 察觉出,了解;分辨出
  • subsidised 补贴的
  • culprit 犯人,罪犯
  • holistic 全盘的,整体的,功能整体性的
  • endeavor 努力,尽力
  • influx 注入,流入,汇集
  • plausible 貌似真实的,貌似有理的,花言巧语的
  • pertain 有关,存在,适用
  • obsolescence 废弃,陈旧过时,(器官)废退
  • resort to 诉诸,依靠,求助于
  • discrepancy 差异,不一致,区别
  • impair 损害,削弱
  • hefty 重的,健壮的,异常大的,重量级的
  • paucity 少量,缺乏,不足,缺少
  • obstruct 阻碍,阻止,妨碍
  • retention 保留,记忆力,滞留,扣留
  • envision 设想,预想 vt.
  • remediate 补救,治疗,矫正,修复
  • conundrum 谜语,难解的问题
  • depict 展示,描述,显示
  • expedite 加快进展
  • remedy 治疗法,改正,改进,补救
  • instinctive reaction 本能反应
  • deem 认为,视为,相信
  • detour 绕路,绕道,弯路
  • futile 无效的,没用的
  • the hassle of sth. 某事带来的麻烦
  • unencumbered 没有阻碍的,不受妨碍的,无负担的
  • idiosyncrasy (某人特有的)气质,习性,癖好
  • crowdsource 众包
  • stabilize 固定,防止……波动
  • encompass 围绕,包围,完成
  • obviate 避免,消除(贫困、不方便等)
  • conducive to有助于……的,有益于……的
  • pertain to 有关,关于
  • arduous 努力的,艰巨的,难克服的
  • plow 犁,耕, 费力穿过
  • imperative 必要的,不可避免的;必要的事,命令,规则
  • notoriously 臭名昭著地,众所周知地
  • culprit 犯人,罪犯,被告人,肇事者
  • succinct 简洁的
  • reciprocal 互惠的,倒数
  • inadvertent 不经意的,疏忽的
  • disseminate 散布,传播(问卷等)
  • elicitation 引出,启发
  • obsolete 废弃的,老式的,已过时的
  • In particular, it works like SBFL, where a bug-inducing commit and a non-inducing commit are analogous(相似的,可比拟的) to a failing test and a passing test in SBFL, respectively.
  • The effectiveness of recurrent neural network is marginally(略微地) higher than multi-layer perceptron.
\ No newline at end of file