feat(code): add shadow effect for code blocks (#713)

This commit is contained in:
Cell
2026-03-12 17:28:15 +08:00
committed by GitHub
parent c8d028aa0e
commit 02ac3f5259
11 changed files with 160 additions and 15 deletions
+43
View File
@@ -53,6 +53,25 @@ def greet(name):
return f"Hello, {name}!"
```
## Shadow
```js {group=tab-shadow name="Always" shadow="always"}
function greet(name) {
return `Hello, ${name}!`
}
```
```python {group=tab-shadow name="Hover" shadow="hover"}
def greet(name):
return f"Hello, {name}!"
```
```go {group=tab-shadow name="Never" shadow="never"}
func greet(name string) string {
return fmt.Sprintf("Hello, %s!", name)
}
```
## Mode
```ts {group=tab-mode name="Classic"}
@@ -121,3 +140,27 @@ function shortFunction() {
console.log('This is a short function.')
}
```
## Code tabs inside other blocks
> [!NOTE]+
>
> ```python {group=tab-nested}
> print("Python")
> ```
>
> ```go {group=tab-nested}
> fmt.Println("Go")
> ```
{{< details open=true >}}
```python {group=tab2}
print("Python")
```
```go {group=tab2}
fmt.Println("Go")
```
{{< /details >}}
+32
View File
@@ -64,6 +64,38 @@ hello('FixIt')
// Hello, FixIt!
```
## Shadow
{{< tabs >}}
{{% tab title="Always" %}}
```js {shadow="always"}
function hello(x = 'world') {
console.log(`Hello, ${x}!`)
}
```
{{% /tab %}}
{{% tab title="Hover" %}}
```js {shadow="hover"}
function hello(x = 'world') {
console.log(`Hello, ${x}!`)
}
```
{{% /tab %}}
{{% tab title="Never" %}}
```js {shadow="never"}
function hello(x = 'world') {
console.log(`Hello, ${x}!`)
}
```
{{% /tab %}}
{{< /tabs >}}
## Collapsed/Expanded
```
+26
View File
@@ -0,0 +1,26 @@
/// Mixin to apply box-shadow with timing control
/// @param {String} $when - When to show shadow: always | hover | never (default: always)
/// @param {List} $shadow - The box-shadow value
/// @example
/// @include box-shadow;
/// @include box-shadow(hover);
/// @include box-shadow(never);
/// @include box-shadow(always, 0 4px 8px rgba(0, 0, 0, 0.15));
@mixin box-shadow(
$when: always,
$shadow: (0 1px 2px -2px rgba(0, 0, 0, 0.08), 0 3px 6px 0 rgba(0, 0, 0, 0.06), 0 5px 12px 4px rgba(0, 0, 0, 0.04))
) {
@if $when == always {
box-shadow: $shadow;
} @else if $when == hover {
transition: box-shadow 0.3s fixit-var(bezier);
&:hover {
box-shadow: $shadow;
}
} @else if $when == never {
box-shadow: none;
} @else {
@warn "box-shadow mixin: unknown $when value '#{$when}'. Expected always, hover, or never.";
}
}
+2 -1
View File
@@ -1,8 +1,9 @@
@import 'theme-vars';
@import 'blur';
@import 'border-radius';
@import 'box-shadow';
@import 'compatibility';
@import 'link';
@import 'loading';
@import 'scrollbar-width';
@import 'theme-vars';
@import 'z-index';
+3
View File
@@ -55,6 +55,9 @@
scrollbar-width: thin,
scrollbar-width-legacy: 12px,
// Animations
bezier: cubic-bezier(.4, 0, .2, 1),
// Other utilities
breadcrumb-height: 0px,
divider-edge-weak: linear-gradient(to right, transparent, fixit-var(divider-bg, #d0d0d5), transparent),
+4 -2
View File
@@ -154,7 +154,8 @@
}
}
[data-header-desktop='sticky'] {
.page .content .highlight.code-block .code-header {
.page .content .highlight.code-block .code-header,
.page .content .code-tabs .tabs-header {
top: calc(#{fixit-var(header-height)} + #{fixit-var(breadcrumb-height)});
}
}
@@ -193,7 +194,8 @@
}
}
[data-header-mobile='sticky'] {
.page .content .highlight.code-block .code-header {
.page .content .highlight.code-block .code-header,
.page .content .code-tabs .tabs-header {
top: calc(#{fixit-var(header-height)} + #{fixit-var(breadcrumb-height)});
}
}
+21 -4
View File
@@ -132,6 +132,14 @@ pre {
// code fences blocks wrapped
&.code-block {
&[data-shadow='always'] {
@include box-shadow(always);
}
&[data-shadow='hover'] {
@include box-shadow(hover);
}
&.instant-height .code-wrapper {
transition: height 0s !important;
}
@@ -267,10 +275,7 @@ pre {
&.is-fullscreen {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
inset: 0;
margin: 0 !important;
overflow: auto;
@include z-index(fixed, 1);
@@ -567,6 +572,14 @@ pre {
border: 1px solid fixit-var(global-border-color);
@include border-radius;
&[data-shadow='always'] {
@include box-shadow(always);
}
&[data-shadow='hover'] {
@include box-shadow(hover);
}
&:has(.code-block.active .code-expand-btn) {
margin-bottom: 1rem;
}
@@ -585,6 +598,9 @@ pre {
font-size: fixit-var(code-block-font-size);
color: fixit-var(code-header-color);
background-color: fixit-var(code-header-background-color);
position: sticky;
top: fixit-var(breadcrumb-height);
@include z-index(base);
@include border-radius(top);
.tabs-items {
@@ -662,6 +678,7 @@ pre {
display: none;
margin: 0;
@include border-radius(bottom);
@include box-shadow(never);
&.active {
display: block;
@@ -60,7 +60,8 @@
margin: 0;
}
.code-block .code-header {
.code-block .code-header,
.code-tabs .tabs-header {
top: initial !important;
}
}
+9 -1
View File
@@ -671,7 +671,15 @@ class FixIt {
$tabs.forEach(b => b.classList.remove('active'));
$tab.classList.add('active');
// 4. move new buttons to actions
// 4. sync shadow mode data attribute
const shadowMode = $tab?.dataset.shadow;
if (shadowMode) {
$container.dataset.shadow = shadowMode;
} else {
delete $container.dataset.shadow;
}
// 5. move new buttons to actions
const $codeHeader = $tab.querySelector('.code-header');
if ($codeHeader) {
$codeHeader.querySelectorAll('.action-btn').forEach(btn => $actions.appendChild(btn));
+2
View File
@@ -1144,6 +1144,8 @@ mode = "classic"
wrapperClass = ""
# the maximum number of lines to show in the code block preview
maxShownLines = 10
# whether to show shadow effect for code blocks, available values: ["always", "hover", "never"]
shadow = "never"
# whether to enable code copy button
copyable = true
# [classic] whether to enable code download button in the code block header
@@ -58,11 +58,25 @@
(printf `class="%s" data-copyable="%v"` $class $config.copyable)
-}}
{{- end -}}
{{- if ne $config.shadow "never" -}}
{{- $wrapper =
replace $wrapper
(printf `class="%s"` $class)
(printf `class="%s" data-shadow="%s"` $class $config.shadow)
-}}
{{- end -}}
{{- if $config.group -}}
{{- $tabTitle := $config.name | default (strings.FirstUpper .Type) | default "Code" -}}
{{- $wrapper =
replace $wrapper
(printf `class="%s"` $class)
(printf `class="%s" data-tab-group="%s" data-tab-title="%s"` $class $config.group $tabTitle) -}}
{{- end -}}
{{- if ne .Options.linenostart nil -}}
{{- $wrapper =
replace $wrapper
`class="code-wrapper"`
(printf `class="code-wrapper" data-line-start="%v"` .)
(printf `class="code-wrapper" data-line-start="%v"` .Options.linenostart)
-}}
{{- end -}}
{{- $wrapperStyle := printf "--fi-max-shown-lines:%v;--fi-line-digit:%v;--fi-line-start:%v;" $maxShownLines $lineNosDigit $lineNoStart -}}
@@ -80,10 +94,6 @@
$lineNosDigit
)
-}}
{{- if $config.group -}}
{{- $tabTitle := $config.name | default (strings.FirstUpper .Type) | default "Code" -}}
{{- $wrapper = replace $wrapper (printf `class="%s"` $class) (printf `class="%s" data-tab-group="%s" data-tab-title="%s"` $class $config.group $tabTitle) -}}
{{- end -}}
{{- $wrapper =
replace $wrapper
(printf `class="%s"` $class)