mirror of
https://github.com/sern-handler/website
synced 2026-06-20 06:42:23 +00:00
feat: migrate to starlight
This commit is contained in:
21
node_modules/@expressive-code/plugin-frames/LICENSE
generated
vendored
Normal file
21
node_modules/@expressive-code/plugin-frames/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Tibor Schiemann
|
||||
|
||||
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 NONINFRINGEMENT. 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 IN THE
|
||||
SOFTWARE.
|
||||
13
node_modules/@expressive-code/plugin-frames/README.md
generated
vendored
Normal file
13
node_modules/@expressive-code/plugin-frames/README.md
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# @expressive-code/plugin-frames
|
||||
|
||||
A default plugin of Expressive Code, an engine for presenting source code on the web.
|
||||
|
||||
It renders a window frame around every code block. Depending on the code's language, this frame can look like a code editor (similar to VS Code), or like a terminal window.
|
||||
|
||||
## Documentation
|
||||
|
||||
[Read this plugin's documentation](https://expressive-code.com/key-features/frames/) on the Expressive Code website to learn more about its features.
|
||||
|
||||
## Installation (not required)
|
||||
|
||||
No installation is required. This package is **installed by default** by our higher-level packages.
|
||||
264
node_modules/@expressive-code/plugin-frames/dist/index.d.ts
generated
vendored
Normal file
264
node_modules/@expressive-code/plugin-frames/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
import { PluginTexts, ExpressiveCodePlugin } from '@expressive-code/core';
|
||||
|
||||
declare const frameTypes: readonly ["code", "terminal", "none", "auto"];
|
||||
type FrameType = (typeof frameTypes)[number];
|
||||
declare const LanguageGroups: {
|
||||
code: string[];
|
||||
terminal: string[];
|
||||
data: string[];
|
||||
styles: string[];
|
||||
textContent: string[];
|
||||
};
|
||||
declare const LanguagesWithFencedFrontmatter: string[];
|
||||
|
||||
interface FramesStyleSettings {
|
||||
/**
|
||||
* The color to use for the shadow of the frame.
|
||||
* @default
|
||||
* ({ theme, resolveSetting }) => theme.colors['widget.shadow'] || multiplyAlpha(resolveSetting('borderColor'), 0.75)
|
||||
*/
|
||||
shadowColor: string;
|
||||
/**
|
||||
* The CSS value for the box shadow of the frame.
|
||||
* @default
|
||||
* ({ resolveSetting }) => `0.1rem 0.1rem 0.2rem ${resolveSetting('frames.shadowColor')}`
|
||||
*/
|
||||
frameBoxShadowCssValue: string;
|
||||
/**
|
||||
* The CSS `background` value for the active editor tab.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['tab.activeBackground']
|
||||
*/
|
||||
editorActiveTabBackground: string;
|
||||
/**
|
||||
* The foreground color of the active editor tab.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['tab.activeForeground']
|
||||
*/
|
||||
editorActiveTabForeground: string;
|
||||
/**
|
||||
* The border color of the active editor tab.
|
||||
* @default 'transparent'
|
||||
*/
|
||||
editorActiveTabBorderColor: string;
|
||||
/**
|
||||
* The height of the indicator lines highlighting the active editor tab.
|
||||
* These are colorful lines that appear at the top and/or bottom of the active tab.
|
||||
*
|
||||
* The individual line colors can be set in {@link editorActiveTabIndicatorTopColor} and
|
||||
* {@link editorActiveTabIndicatorBottomColor}.
|
||||
*
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('borderWidth')
|
||||
*/
|
||||
editorActiveTabIndicatorHeight: string;
|
||||
/**
|
||||
* The color of the indicator line displayed at the top border of the active editor tab.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['tab.activeBorderTop']
|
||||
*/
|
||||
editorActiveTabIndicatorTopColor: string;
|
||||
/**
|
||||
* The color of the indicator line displayed at the bottom border of the active editor tab.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['tab.activeBorder']
|
||||
*/
|
||||
editorActiveTabIndicatorBottomColor: string;
|
||||
/**
|
||||
* The inline margin (= left margin in horizontal writing mode) to apply inside the tab bar
|
||||
* before the first editor tab.
|
||||
* @default '0'
|
||||
*/
|
||||
editorTabsMarginInlineStart: string;
|
||||
/**
|
||||
* The block margin (= top margin in horizontal writing mode) to apply inside the tab bar
|
||||
* before the editor tabs.
|
||||
* @default '0'
|
||||
*/
|
||||
editorTabsMarginBlockStart: string;
|
||||
/**
|
||||
* The border radius to apply to the outer corners of editor tabs.
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('borderRadius')
|
||||
*/
|
||||
editorTabBorderRadius: string;
|
||||
/**
|
||||
* The CSS `background` value of the editor tab bar.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['editorGroupHeader.tabsBackground']
|
||||
*/
|
||||
editorTabBarBackground: string;
|
||||
/**
|
||||
* The border color of the editor tab bar.
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('borderColor')
|
||||
*/
|
||||
editorTabBarBorderColor: string;
|
||||
/**
|
||||
* The color of the bottom border of the editor tab bar. This is an additional border
|
||||
* that can be used to display a line between the editor tab bar and the code contents.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['editorGroupHeader.tabsBorder'] || 'transparent'
|
||||
*/
|
||||
editorTabBarBorderBottomColor: string;
|
||||
/**
|
||||
* The background color of the code editor.
|
||||
* This color is used for the "code" frame type.
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('codeBackground')
|
||||
*/
|
||||
editorBackground: string;
|
||||
/**
|
||||
* The color of the three dots in the terminal title bar.
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('frames.terminalTitlebarForeground')
|
||||
*/
|
||||
terminalTitlebarDotsForeground: string;
|
||||
/**
|
||||
* The opacity of the three dots in the terminal title bar.
|
||||
* @default '0.15'
|
||||
*/
|
||||
terminalTitlebarDotsOpacity: string;
|
||||
/**
|
||||
* The background color of the terminal title bar.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['titleBar.activeBackground'] || theme.colors['editorGroupHeader.tabsBackground']
|
||||
*/
|
||||
terminalTitlebarBackground: string;
|
||||
/**
|
||||
* The foreground color of the terminal title bar.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['titleBar.activeForeground']
|
||||
*/
|
||||
terminalTitlebarForeground: string;
|
||||
/**
|
||||
* The color of the border between the terminal title bar and the terminal contents.
|
||||
* @default
|
||||
* ({ theme, resolveSetting }) =>
|
||||
* theme.colors['titleBar.border'] ||
|
||||
* onBackground(resolveSetting('borderColor'), theme.type === 'dark' ? '#000000bf' : '#ffffffbf')
|
||||
*/
|
||||
terminalTitlebarBorderBottomColor: string;
|
||||
/**
|
||||
* The background color of the terminal window.
|
||||
* This color is used for the "terminal" frame type.
|
||||
* @default
|
||||
* ({ theme }) => theme.colors['terminal.background']
|
||||
*/
|
||||
terminalBackground: string;
|
||||
/**
|
||||
* The background color of the copy button.
|
||||
* This color is modified by the state-dependent opacity values specified in
|
||||
* {@link inlineButtonBackgroundIdleOpacity}, {@link inlineButtonBackgroundHoverOrFocusOpacity}
|
||||
* and {@link inlineButtonBackgroundActiveOpacity}.
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('frames.inlineButtonForeground')
|
||||
*/
|
||||
inlineButtonBackground: string;
|
||||
/**
|
||||
* The opacity of the copy button background when idle.
|
||||
* @default '0'
|
||||
*/
|
||||
inlineButtonBackgroundIdleOpacity: string;
|
||||
/**
|
||||
* The opacity of the copy button background when hovered or focused.
|
||||
* @default '0.2'
|
||||
*/
|
||||
inlineButtonBackgroundHoverOrFocusOpacity: string;
|
||||
/**
|
||||
* The opacity of the copy button background when pressed.
|
||||
* @default '0.3'
|
||||
*/
|
||||
inlineButtonBackgroundActiveOpacity: string;
|
||||
/**
|
||||
* The foreground color of the copy button.
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('codeForeground')
|
||||
*/
|
||||
inlineButtonForeground: string;
|
||||
/**
|
||||
* The border color of the copy button.
|
||||
* @default
|
||||
* ({ resolveSetting }) => resolveSetting('frames.inlineButtonForeground')
|
||||
*/
|
||||
inlineButtonBorder: string;
|
||||
/**
|
||||
* The opacity of the copy button border.
|
||||
* @default '0.4'
|
||||
*/
|
||||
inlineButtonBorderOpacity: string;
|
||||
/**
|
||||
* The background color of the tooltip shown after successfully copying the code.
|
||||
* @default
|
||||
* ({ theme }) => setLuminance(theme.colors['terminal.ansiGreen'] || '#0dbc79', 0.18)
|
||||
*/
|
||||
tooltipSuccessBackground: string;
|
||||
/**
|
||||
* The foreground color of the tooltip shown after successfully copying the code.
|
||||
* @default 'white'
|
||||
*/
|
||||
tooltipSuccessForeground: string;
|
||||
}
|
||||
declare module '@expressive-code/core' {
|
||||
interface StyleSettings {
|
||||
frames: FramesStyleSettings;
|
||||
}
|
||||
}
|
||||
|
||||
interface PluginFramesOptions {
|
||||
/**
|
||||
* If `true`, and no title was found in the code block's meta string,
|
||||
* the plugin will try to find and extract a comment line containing the code block file name
|
||||
* from the first 4 lines of the code.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
extractFileNameFromCode?: boolean | undefined;
|
||||
/**
|
||||
* If `true`, a "Copy to clipboard" button will be shown for each code block.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
showCopyToClipboardButton?: boolean | undefined;
|
||||
/**
|
||||
* If `true`, the "Copy to clipboard" button of terminal window frames
|
||||
* will remove comment lines starting with `#` from the copied text.
|
||||
*
|
||||
* This is useful to reduce the copied text to the actual commands users need to run,
|
||||
* instead of also copying explanatory comments or instructions.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
removeCommentsWhenCopyingTerminalFrames?: boolean | undefined;
|
||||
}
|
||||
interface PluginFramesProps {
|
||||
/**
|
||||
* The code block's title. For terminal frames, this is displayed as the terminal window title,
|
||||
* and for code frames, it's displayed as the file name in an open file tab.
|
||||
*
|
||||
* If no title is given, the plugin will try to automatically extract a title from a
|
||||
* [file name comment](https://expressive-code.com/key-features/frames/#file-name-comments)
|
||||
* inside your code, unless disabled by the `extractFileNameFromCode` option.
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* Allows you to override the automatic frame type detection for a code block.
|
||||
*
|
||||
* The supported values are `code`, `terminal`, `none` and `auto`.
|
||||
*
|
||||
* @default `auto`
|
||||
*/
|
||||
frame: FrameType;
|
||||
}
|
||||
declare module '@expressive-code/core' {
|
||||
interface ExpressiveCodeBlockProps extends PluginFramesProps {
|
||||
}
|
||||
}
|
||||
declare const pluginFramesTexts: PluginTexts<{
|
||||
terminalWindowFallbackTitle: string;
|
||||
copyButtonTooltip: string;
|
||||
copyButtonCopied: string;
|
||||
}>;
|
||||
declare function pluginFrames(options?: PluginFramesOptions): ExpressiveCodePlugin;
|
||||
|
||||
export { FramesStyleSettings, LanguageGroups, LanguagesWithFencedFrontmatter, PluginFramesOptions, PluginFramesProps, pluginFrames, pluginFramesTexts };
|
||||
588
node_modules/@expressive-code/plugin-frames/dist/index.js
generated
vendored
Normal file
588
node_modules/@expressive-code/plugin-frames/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,588 @@
|
||||
// src/index.ts
|
||||
import { PluginTexts } from "@expressive-code/core";
|
||||
import { h } from "@expressive-code/core/hast";
|
||||
|
||||
// src/styles.ts
|
||||
import { PluginStyleSettings, multiplyAlpha, onBackground, setLuminance } from "@expressive-code/core";
|
||||
var framesStyleSettings = new PluginStyleSettings({
|
||||
defaultValues: {
|
||||
frames: {
|
||||
shadowColor: ({ theme, resolveSetting }) => theme.colors["widget.shadow"] || multiplyAlpha(resolveSetting("borderColor"), 0.75),
|
||||
frameBoxShadowCssValue: ({ resolveSetting }) => `0.1rem 0.1rem 0.2rem ${resolveSetting("frames.shadowColor")}`,
|
||||
editorActiveTabBackground: ({ theme }) => theme.colors["tab.activeBackground"],
|
||||
editorActiveTabForeground: ({ theme }) => theme.colors["tab.activeForeground"],
|
||||
editorActiveTabBorderColor: "transparent",
|
||||
editorActiveTabIndicatorHeight: ({ resolveSetting }) => resolveSetting("borderWidth"),
|
||||
editorActiveTabIndicatorTopColor: ({ theme }) => theme.colors["tab.activeBorderTop"],
|
||||
editorActiveTabIndicatorBottomColor: ({ theme }) => theme.colors["tab.activeBorder"],
|
||||
editorTabsMarginInlineStart: "0",
|
||||
editorTabsMarginBlockStart: "0",
|
||||
editorTabBorderRadius: ({ resolveSetting }) => resolveSetting("borderRadius"),
|
||||
editorTabBarBackground: ({ theme }) => theme.colors["editorGroupHeader.tabsBackground"],
|
||||
editorTabBarBorderColor: ({ resolveSetting }) => resolveSetting("borderColor"),
|
||||
editorTabBarBorderBottomColor: ({ theme }) => theme.colors["editorGroupHeader.tabsBorder"] || "transparent",
|
||||
editorBackground: ({ resolveSetting }) => resolveSetting("codeBackground"),
|
||||
terminalTitlebarDotsForeground: ({ resolveSetting }) => resolveSetting("frames.terminalTitlebarForeground"),
|
||||
terminalTitlebarDotsOpacity: "0.15",
|
||||
terminalTitlebarBackground: ({ theme }) => theme.colors["titleBar.activeBackground"] || theme.colors["editorGroupHeader.tabsBackground"],
|
||||
terminalTitlebarForeground: ({ theme }) => theme.colors["titleBar.activeForeground"],
|
||||
terminalTitlebarBorderBottomColor: ({ theme, resolveSetting }) => theme.colors["titleBar.border"] || onBackground(resolveSetting("borderColor"), theme.type === "dark" ? "#000000bf" : "#ffffffbf"),
|
||||
terminalBackground: ({ theme }) => theme.colors["terminal.background"],
|
||||
inlineButtonBackground: ({ resolveSetting }) => resolveSetting("frames.inlineButtonForeground"),
|
||||
inlineButtonBackgroundIdleOpacity: "0",
|
||||
inlineButtonBackgroundHoverOrFocusOpacity: "0.2",
|
||||
inlineButtonBackgroundActiveOpacity: "0.3",
|
||||
inlineButtonForeground: ({ resolveSetting }) => resolveSetting("codeForeground"),
|
||||
inlineButtonBorder: ({ resolveSetting }) => resolveSetting("frames.inlineButtonForeground"),
|
||||
inlineButtonBorderOpacity: "0.4",
|
||||
tooltipSuccessBackground: ({ theme }) => setLuminance(theme.colors["terminal.ansiGreen"] || "#0dbc79", 0.18),
|
||||
tooltipSuccessForeground: "white"
|
||||
}
|
||||
}
|
||||
});
|
||||
function getFramesBaseStyles({ cssVar }, options) {
|
||||
const dotsSvg = [
|
||||
`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 16' preserveAspectRatio='xMidYMid meet'>`,
|
||||
`<circle cx='8' cy='8' r='8'/>`,
|
||||
`<circle cx='30' cy='8' r='8'/>`,
|
||||
`<circle cx='52' cy='8' r='8'/>`,
|
||||
`</svg>`
|
||||
].join("");
|
||||
const escapedDotsSvg = dotsSvg.replace(/</g, "%3C").replace(/>/g, "%3E");
|
||||
const terminalTitlebarDots = `url("data:image/svg+xml,${escapedDotsSvg}")`;
|
||||
const copySvg = [
|
||||
`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75'>`,
|
||||
`<path d='M3 19a2 2 0 0 1-1-2V2a2 2 0 0 1 1-1h13a2 2 0 0 1 2 1'/>`,
|
||||
`<rect x='6' y='5' width='16' height='18' rx='1.5' ry='1.5'/>`,
|
||||
`</svg>`
|
||||
].join("");
|
||||
const escapedCopySvg = copySvg.replace(/</g, "%3C").replace(/>/g, "%3E");
|
||||
const copyToClipboard = `url("data:image/svg+xml,${escapedCopySvg}")`;
|
||||
const tabBarBackground = [
|
||||
`linear-gradient(to top, ${cssVar("frames.editorTabBarBorderBottomColor")} ${cssVar("borderWidth")}, transparent ${cssVar("borderWidth")})`,
|
||||
`linear-gradient(${cssVar("frames.editorTabBarBackground")}, ${cssVar("frames.editorTabBarBackground")})`
|
||||
].join(",");
|
||||
const frameStyles = `.frame {
|
||||
all: unset;
|
||||
position: relative;
|
||||
display: block;
|
||||
--header-border-radius: calc(${cssVar("borderRadius")} + ${cssVar("borderWidth")});
|
||||
--tab-border-radius: calc(${cssVar("frames.editorTabBorderRadius")} + ${cssVar("borderWidth")});
|
||||
--button-spacing: 0.4rem;
|
||||
--code-background: ${cssVar("frames.editorBackground")};
|
||||
border-radius: var(--header-border-radius);
|
||||
box-shadow: ${cssVar("frames.frameBoxShadowCssValue")};
|
||||
|
||||
.header {
|
||||
display: none;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
|
||||
border-radius: var(--header-border-radius) var(--header-border-radius) 0 0;
|
||||
}
|
||||
|
||||
/* Styles to apply if we have a title bar or tab bar */
|
||||
&.has-title,
|
||||
&.is-terminal {
|
||||
& pre, & code {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent empty window titles from collapsing in height */
|
||||
.title:empty:before {
|
||||
content: '\\a0';
|
||||
}
|
||||
|
||||
/* Editor tab bar */
|
||||
&.has-title:not(.is-terminal) {
|
||||
--button-spacing: calc(1.9rem + 2 * (${cssVar("uiPaddingBlock")} + ${cssVar("frames.editorActiveTabIndicatorHeight")}));
|
||||
|
||||
/* Active editor tab */
|
||||
& .title {
|
||||
position: relative;
|
||||
color: ${cssVar("frames.editorActiveTabForeground")};
|
||||
background: ${cssVar("frames.editorActiveTabBackground")};
|
||||
background-clip: padding-box;
|
||||
margin-block-start: ${cssVar("frames.editorTabsMarginBlockStart")};
|
||||
padding: calc(${cssVar("uiPaddingBlock")} + ${cssVar("frames.editorActiveTabIndicatorHeight")}) ${cssVar("uiPaddingInline")};
|
||||
border: ${cssVar("borderWidth")} solid ${cssVar("frames.editorActiveTabBorderColor")};
|
||||
border-radius: var(--tab-border-radius) var(--tab-border-radius) 0 0;
|
||||
border-bottom: none;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
inset: 0;
|
||||
border-top: ${cssVar("frames.editorActiveTabIndicatorHeight")} solid ${cssVar("frames.editorActiveTabIndicatorTopColor")};
|
||||
border-bottom: ${cssVar("frames.editorActiveTabIndicatorHeight")} solid ${cssVar("frames.editorActiveTabIndicatorBottomColor")};
|
||||
}
|
||||
}
|
||||
|
||||
/* Tab bar background */
|
||||
& .header {
|
||||
display: flex;
|
||||
|
||||
background: ${tabBarBackground};
|
||||
background-repeat: no-repeat;
|
||||
|
||||
padding-inline-start: ${cssVar("frames.editorTabsMarginInlineStart")};
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
inset: 0;
|
||||
border: ${cssVar("borderWidth")} solid ${cssVar("frames.editorTabBarBorderColor")};
|
||||
border-radius: inherit;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminal window */
|
||||
&.is-terminal {
|
||||
--button-spacing: calc(1.9rem + ${cssVar("borderWidth")} + 2 * ${cssVar("uiPaddingBlock")});
|
||||
--code-background: ${cssVar("frames.terminalBackground")};
|
||||
|
||||
/* Terminal title bar */
|
||||
& .header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-block: ${cssVar("uiPaddingBlock")};
|
||||
padding-block-end: calc(${cssVar("uiPaddingBlock")} + ${cssVar("borderWidth")});
|
||||
position: relative;
|
||||
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.025ch;
|
||||
|
||||
color: ${cssVar("frames.terminalTitlebarForeground")};
|
||||
background: ${cssVar("frames.terminalTitlebarBackground")};
|
||||
border: ${cssVar("borderWidth")} solid ${cssVar("borderColor")};
|
||||
border-bottom: none;
|
||||
|
||||
/* Display three dots at the left side of the header */
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
left: ${cssVar("uiPaddingInline")};
|
||||
width: 2.1rem;
|
||||
height: ${2.1 / 60 * 16}rem;
|
||||
line-height: 0;
|
||||
background-color: ${cssVar("frames.terminalTitlebarDotsForeground")};
|
||||
opacity: ${cssVar("frames.terminalTitlebarDotsOpacity")};
|
||||
-webkit-mask-image: ${terminalTitlebarDots};
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-image: ${terminalTitlebarDots};
|
||||
mask-repeat: no-repeat;
|
||||
}
|
||||
/* Display a border below the header */
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
inset: 0;
|
||||
border-bottom: ${cssVar("borderWidth")} solid ${cssVar("frames.terminalTitlebarBorderBottomColor")};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Code */
|
||||
& pre {
|
||||
background: var(--code-background);
|
||||
}
|
||||
}`;
|
||||
const copyButtonStyles = `.copy {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
flex-direction: row;
|
||||
position: absolute;
|
||||
inset-block-start: calc(${cssVar("borderWidth")} + var(--button-spacing));
|
||||
inset-inline-end: calc(${cssVar("borderWidth")} + ${cssVar("uiPaddingInline")} / 2);
|
||||
|
||||
/* RTL support: Code is always LTR, so the inline copy button
|
||||
must match this to avoid overlapping the start of lines */
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
align-self: flex-end;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 0.2rem;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
|
||||
transition-property: opacity, background, border-color;
|
||||
transition-duration: 0.2s;
|
||||
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
|
||||
/* Mobile-first styles: Make the button visible and tappable */
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
background: var(--code-background);
|
||||
opacity: 0.75;
|
||||
|
||||
div {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
|
||||
background: ${cssVar("frames.inlineButtonBackground")};
|
||||
opacity: ${cssVar("frames.inlineButtonBackgroundIdleOpacity")};
|
||||
|
||||
transition-property: inherit;
|
||||
transition-duration: inherit;
|
||||
transition-timing-function: inherit;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
border: ${cssVar("borderWidth")} solid ${cssVar("frames.inlineButtonBorder")};
|
||||
opacity: ${cssVar("frames.inlineButtonBorderOpacity")};
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
inset: 0;
|
||||
background-color: ${cssVar("frames.inlineButtonForeground")};
|
||||
-webkit-mask-image: ${copyToClipboard};
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-image: ${copyToClipboard};
|
||||
mask-repeat: no-repeat;
|
||||
margin: 0.475rem;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
On hover or focus, make the button fully opaque
|
||||
and set hover/focus background opacity
|
||||
*/
|
||||
&:hover, &:focus:focus-visible {
|
||||
opacity: 1;
|
||||
div {
|
||||
opacity: ${cssVar("frames.inlineButtonBackgroundHoverOrFocusOpacity")};
|
||||
}
|
||||
}
|
||||
|
||||
/* On press, set active background opacity */
|
||||
&:active {
|
||||
opacity: 1;
|
||||
div {
|
||||
opacity: ${cssVar("frames.inlineButtonBackgroundActiveOpacity")};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.feedback {
|
||||
--tooltip-arrow-size: 0.35rem;
|
||||
--tooltip-bg: ${cssVar("frames.tooltipSuccessBackground")};
|
||||
color: ${cssVar("frames.tooltipSuccessForeground")};
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
position: relative;
|
||||
align-self: center;
|
||||
background-color: var(--tooltip-bg);
|
||||
z-index: 99;
|
||||
padding: 0.125rem 0.75rem;
|
||||
border-radius: 0.2rem;
|
||||
margin-inline-end: var(--tooltip-arrow-size);
|
||||
opacity: 0;
|
||||
transition-property: opacity, transform;
|
||||
transition-duration: 0.2s;
|
||||
transition-timing-function: ease-in-out;
|
||||
transform: translate3d(0, 0.25rem, 0);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
top: calc(50% - var(--tooltip-arrow-size));
|
||||
inset-inline-end: calc(-2 * (var(--tooltip-arrow-size) - 0.5px));
|
||||
border: var(--tooltip-arrow-size) solid transparent;
|
||||
border-inline-start-color: var(--tooltip-bg);
|
||||
}
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
/* If a mouse is available, hide the button by default and make it smaller */
|
||||
.copy button {
|
||||
opacity: 0;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
/* Reveal the non-hovered button in the following cases:
|
||||
- when the frame is hovered
|
||||
- when a sibling inside the frame is focused
|
||||
- when the copy button shows a visible feedback message
|
||||
*/
|
||||
.frame:hover .copy button:not(:hover),
|
||||
.frame:focus-within :focus-visible ~ .copy button:not(:hover),
|
||||
.frame .copy .feedback.show ~ button:not(:hover) {
|
||||
opacity: 0.75;
|
||||
}
|
||||
}`;
|
||||
const styles = [
|
||||
// Always add base frame styles
|
||||
frameStyles,
|
||||
// Add copy button styles if enabled
|
||||
options.showCopyToClipboardButton ? copyButtonStyles : ""
|
||||
];
|
||||
return styles.join("\n");
|
||||
}
|
||||
|
||||
// src/utils.ts
|
||||
var frameTypes = ["code", "terminal", "none", "auto"];
|
||||
function frameTypeFromString(input) {
|
||||
if (input === "")
|
||||
input = "none";
|
||||
if (input === "editor")
|
||||
input = "code";
|
||||
if (input === "shell")
|
||||
input = "terminal";
|
||||
const frameType = input;
|
||||
return frameTypes.includes(frameType) ? frameType : void 0;
|
||||
}
|
||||
var LanguageGroups = {
|
||||
code: ["astro", "cjs", "htm", "html", "js", "jsx", "mjs", "svelte", "ts", "tsx", "typescript", "vb", "vue", "vue-html"],
|
||||
terminal: ["ansi", "bash", "bat", "batch", "cmd", "console", "nu", "nushell", "powershell", "ps", "ps1", "psd1", "psm1", "sh", "shell", "shellscript", "shellsession", "zsh"],
|
||||
data: ["csv", "env", "ini", "json", "toml", "xml", "yaml", "yml"],
|
||||
styles: ["css", "less", "sass", "scss", "styl", "stylus", "xsl"],
|
||||
textContent: ["markdown", "md", "mdx"]
|
||||
};
|
||||
var LanguagesWithFencedFrontmatter = ["astro", "markdown", "md", "mdx", "toml", "yaml", "yml"];
|
||||
function isTerminalLanguage(language) {
|
||||
return LanguageGroups.terminal.includes(language);
|
||||
}
|
||||
var getFileNameCommentRegExpString = () => [
|
||||
// Start of line
|
||||
`^`,
|
||||
// Optional whitespace
|
||||
`\\s*`,
|
||||
// Mandatory comment start: `//`, `#` (but not `#!`), `<!--` or `/*`
|
||||
`(?://|#(?!!)|<!--|/\\*)`,
|
||||
// Optional whitespace
|
||||
`\\s*`,
|
||||
// Optional prefix before the file name:
|
||||
// - This is intended to match strings like `File name:` or `Example :`,
|
||||
// but not Windows drive letters like `C:`,
|
||||
// or URL protocols like `https:`
|
||||
// - We therefore expect the prefix to begin with any sequence of characters
|
||||
// not starting with a letter + colon (to rule out Windows drive letters)
|
||||
// - The prefix must then be followed by:
|
||||
// - a Japanese colon (`\\uff1a`), or
|
||||
// - a regular colon (`:`) not followed by `//` (to rule out URL protocols)
|
||||
`(?:((?![a-z]:).*?)(?:\\uff1a|:(?!//)))?`,
|
||||
// Optional whitespace
|
||||
`\\s*`,
|
||||
// Capture the file name
|
||||
`(`,
|
||||
// Optional Windows drive letter
|
||||
`(?:[a-z]:)?`,
|
||||
// Optional sequence of characters allowed in file paths
|
||||
`[\\w./~%[\\]+\\\\-]*`,
|
||||
// Optional dot and supported file extension
|
||||
`(?:\\.(?:${Object.values(LanguageGroups).flat().sort().join("|")}))?`,
|
||||
// End of file name capture
|
||||
`)`,
|
||||
// Optional whitespace
|
||||
`\\s*`,
|
||||
// Optional HTML or JS/CSS comment end (`-->` or `*/`)
|
||||
`(?:-->|\\*/)?`,
|
||||
// Optional whitespace
|
||||
`\\s*`,
|
||||
// End of line
|
||||
`$`
|
||||
].join("");
|
||||
var fileNameCommentRegExp;
|
||||
function getFileNameFromComment(line, lang) {
|
||||
if (fileNameCommentRegExp === void 0) {
|
||||
fileNameCommentRegExp = new RegExp(getFileNameCommentRegExpString(), "i");
|
||||
}
|
||||
const matches = fileNameCommentRegExp.exec(line);
|
||||
const textBeforeFileName = matches?.[1] ?? "";
|
||||
const possibleFileName = matches?.[2];
|
||||
if (!possibleFileName)
|
||||
return;
|
||||
if (!possibleFileName.match(/[^.:/\\~]/))
|
||||
return;
|
||||
if (possibleFileName.match(/^\.{2,}(?!\/|\\)/))
|
||||
return;
|
||||
const languageGroup = Object.values(LanguageGroups).find((group) => group.includes(lang));
|
||||
const fileNameWithoutPath = possibleFileName.replace(/^.*[/\\]/, "");
|
||||
const fileExt = fileNameWithoutPath.match(/\.([^.]+)$/)?.[1];
|
||||
const hasTypicalFileNameBeginning = possibleFileName.match(/^(\/|\\|\.[/\\]|~|[a-z]:).+/i);
|
||||
const hasFileNameStartingWithDot = fileNameWithoutPath.startsWith(".");
|
||||
const looksLikeSeparatedPath = (
|
||||
// Contains path separators
|
||||
possibleFileName.match(/[/\\]/) && // Also contains other characters (except path separators, numbers and dots)
|
||||
possibleFileName.match(/[^/\\0-9.]/) && // Does not contain spaces
|
||||
!possibleFileName.match(/\s/) && // Is all lowercase
|
||||
possibleFileName === possibleFileName.toLowerCase()
|
||||
);
|
||||
const hasTypicalFileNamePattern = hasTypicalFileNameBeginning || hasFileNameStartingWithDot || looksLikeSeparatedPath;
|
||||
if (hasTypicalFileNamePattern && (!textBeforeFileName.length || languageGroup === LanguageGroups.terminal)) {
|
||||
return possibleFileName;
|
||||
}
|
||||
if (!fileExt || languageGroup && !languageGroup.includes(fileExt))
|
||||
return;
|
||||
return possibleFileName;
|
||||
}
|
||||
function extractFileNameFromCodeBlock(codeBlock) {
|
||||
let extractedFileName = void 0;
|
||||
let lineIdx = codeBlock.getLines(0, 4).findIndex((line) => {
|
||||
extractedFileName = getFileNameFromComment(line.text, codeBlock.language);
|
||||
return !!extractedFileName;
|
||||
});
|
||||
if (!extractedFileName)
|
||||
return;
|
||||
codeBlock.deleteLine(lineIdx);
|
||||
if (LanguagesWithFencedFrontmatter.includes(codeBlock.language)) {
|
||||
const openingFence = lineIdx > 0 ? codeBlock.getLine(lineIdx - 1)?.text.trim() : void 0;
|
||||
const closingFence = codeBlock.getLine(lineIdx)?.text.trim();
|
||||
const isFrontmatterEmptyNow = openingFence === closingFence && ["---", "+++"].includes(openingFence ?? "");
|
||||
if (isFrontmatterEmptyNow) {
|
||||
lineIdx--;
|
||||
codeBlock.deleteLine(lineIdx);
|
||||
codeBlock.deleteLine(lineIdx);
|
||||
}
|
||||
}
|
||||
if (codeBlock.getLine(lineIdx)?.text.trim().length === 0) {
|
||||
codeBlock.deleteLine(lineIdx);
|
||||
}
|
||||
return extractedFileName;
|
||||
}
|
||||
|
||||
// src/copy-js-module.min.ts
|
||||
var copy_js_module_min_default = 'try{(()=>{function i(o){let e=document.createElement("pre");Object.assign(e.style,{opacity:"0",pointerEvents:"none",position:"absolute",overflow:"hidden",left:"0",top:"0",width:"20px",height:"20px",webkitUserSelect:"auto",userSelect:"all"}),e.ariaHidden="true",e.textContent=o,document.body.appendChild(e);let a=document.createRange();a.selectNode(e);let n=getSelection();if(!n)return!1;n.removeAllRanges(),n.addRange(a);let r=!1;try{r=document.execCommand("copy")}finally{n.removeAllRanges(),document.body.removeChild(e)}return r}async function l(o){let e=o.currentTarget,a=e.dataset,n=!1,r=a.code.replace(/\\u007f/g,`\n`);try{await navigator.clipboard.writeText(r),n=!0}catch{n=i(r)}if(!n||e.parentNode?.querySelector(".feedback"))return;let t=document.createElement("div");t.classList.add("feedback"),t.append(a.copied),e.before(t),t.offsetWidth,requestAnimationFrame(()=>t?.classList.add("show"));let c=()=>!t||t.classList.remove("show"),d=()=>{!t||parseFloat(getComputedStyle(t).opacity)>0||(t.remove(),t=void 0)};setTimeout(c,1500),setTimeout(d,2500),e.addEventListener("blur",c),t.addEventListener("transitioncancel",d),t.addEventListener("transitionend",d)}function s(o){o.querySelectorAll?.("[SELECTOR]").forEach(e=>e.addEventListener("click",l))}s(document);var u=new MutationObserver(o=>o.forEach(e=>e.addedNodes.forEach(a=>{s(a)})));u.observe(document.body,{childList:!0,subtree:!0});document.addEventListener("astro:page-load",()=>{s(document)});})();}catch(e){console.error("[EC] copy-js-module failed:",e)}';
|
||||
|
||||
// src/index.ts
|
||||
var pluginFramesTexts = new PluginTexts({
|
||||
terminalWindowFallbackTitle: "Terminal window",
|
||||
copyButtonTooltip: "Copy to clipboard",
|
||||
copyButtonCopied: "Copied!"
|
||||
});
|
||||
pluginFramesTexts.addLocale("de", {
|
||||
terminalWindowFallbackTitle: "Terminal-Fenster",
|
||||
copyButtonTooltip: "In die Zwischenablage kopieren",
|
||||
copyButtonCopied: "Kopiert!"
|
||||
});
|
||||
function pluginFrames(options = {}) {
|
||||
options = {
|
||||
extractFileNameFromCode: true,
|
||||
showCopyToClipboardButton: true,
|
||||
removeCommentsWhenCopyingTerminalFrames: true,
|
||||
...options
|
||||
};
|
||||
return {
|
||||
name: "Frames",
|
||||
styleSettings: framesStyleSettings,
|
||||
baseStyles: (context) => getFramesBaseStyles(context, options),
|
||||
jsModules: options.showCopyToClipboardButton ? [copy_js_module_min_default.replace(/\[SELECTOR\]/g, ".expressive-code .copy button")] : void 0,
|
||||
hooks: {
|
||||
preprocessMetadata: ({ codeBlock }) => {
|
||||
const { metaOptions, props } = codeBlock;
|
||||
props.title = metaOptions.getString("title") ?? props.title;
|
||||
const frame = metaOptions.getString("frame");
|
||||
if (frame !== void 0) {
|
||||
const frameType = frameTypeFromString(frame);
|
||||
if (frameType === void 0)
|
||||
throw new Error(
|
||||
`Invalid frame type \`${frame}\` found in code block meta string.
|
||||
Valid frame types are: ${frameTypes.join(", ")}.`.replace(/\s+/g, " ")
|
||||
);
|
||||
props.frame = frameType;
|
||||
}
|
||||
},
|
||||
preprocessCode: ({ codeBlock }) => {
|
||||
const { props, language } = codeBlock;
|
||||
if (props.title === void 0 && props.frame !== "none" && options.extractFileNameFromCode) {
|
||||
props.title = extractFileNameFromCodeBlock(codeBlock);
|
||||
}
|
||||
if ((props.frame ?? "auto") === "auto" && isTerminalLanguage(language)) {
|
||||
const titleIsFileName = props.title && getFileNameFromComment(`// ${props.title}`, language);
|
||||
if (titleIsFileName || codeBlock.getLines(0, 4).some((line) => line.text.match(/^\s*#!/))) {
|
||||
props.frame = "code";
|
||||
}
|
||||
}
|
||||
},
|
||||
postprocessRenderedBlock: ({ codeBlock, renderData, locale }) => {
|
||||
const texts = pluginFramesTexts.get(locale);
|
||||
const { title: titleText, frame = "auto" } = codeBlock.props;
|
||||
const isTerminal = frame === "terminal" || frame === "auto" && isTerminalLanguage(codeBlock.language);
|
||||
const visibleTitle = frame !== "none" && titleText || isTerminal ? [h("span", { className: "title" }, titleText || "")] : [];
|
||||
const screenReaderTitle = !titleText && isTerminal ? [h("span", { className: "sr-only" }, texts.terminalWindowFallbackTitle)] : [];
|
||||
const extraElements = [];
|
||||
if (options.showCopyToClipboardButton) {
|
||||
let codeToCopy = codeBlock.code;
|
||||
if (options.removeCommentsWhenCopyingTerminalFrames && isTerminal) {
|
||||
codeToCopy = codeToCopy.replace(/(?<=^|\n)\s*#.*($|\n+)/g, "").trim();
|
||||
}
|
||||
codeToCopy = codeToCopy.replace(/\n/g, "\x7F");
|
||||
extraElements.push(
|
||||
h("div", { className: "copy" }, [
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
title: texts.copyButtonTooltip,
|
||||
"data-copied": texts.copyButtonCopied,
|
||||
"data-code": codeToCopy
|
||||
},
|
||||
[h("div")]
|
||||
)
|
||||
])
|
||||
);
|
||||
}
|
||||
renderData.blockAst = h(
|
||||
"figure",
|
||||
{
|
||||
className: [
|
||||
"frame",
|
||||
// If the code block is a terminal, add the `is-terminal` class
|
||||
...isTerminal ? ["is-terminal"] : [],
|
||||
// If the code block has a title, add the `has-title` class
|
||||
...frame !== "none" && titleText ? ["has-title"] : []
|
||||
]
|
||||
},
|
||||
[
|
||||
h("figcaption", { className: "header" }, [...visibleTitle, ...screenReaderTitle]),
|
||||
// Render the original code block
|
||||
renderData.blockAst,
|
||||
// Add any extra elements (e.g. copy button)
|
||||
...extraElements
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
export {
|
||||
LanguageGroups,
|
||||
LanguagesWithFencedFrontmatter,
|
||||
pluginFrames,
|
||||
pluginFramesTexts
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@expressive-code/plugin-frames/dist/index.js.map
generated
vendored
Normal file
1
node_modules/@expressive-code/plugin-frames/dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
40
node_modules/@expressive-code/plugin-frames/package.json
generated
vendored
Normal file
40
node_modules/@expressive-code/plugin-frames/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@expressive-code/plugin-frames",
|
||||
"version": "0.35.3",
|
||||
"description": "Frames plugin for Expressive Code. Wraps code blocks in a styled editor or terminal frame with support for titles, multiple tabs and more.",
|
||||
"keywords": [],
|
||||
"author": "Tibor Schiemann",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/expressive-code/expressive-code.git",
|
||||
"directory": "packages/@expressive-code/plugin-frames"
|
||||
},
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"exports": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@expressive-code/core": "^0.35.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expressive-code/plugin-shiki": "^0.35.3",
|
||||
"@internal/test-utils": "^0.2.28"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm build-js-modules && tsup ./src/index.ts --format esm --dts --sourcemap --clean",
|
||||
"build-js-modules": "tsm --require=../../../scripts/lib/filter-warnings.cjs ../../../scripts/build-js-module.ts ./src/copy-js-module.ts",
|
||||
"coverage": "vitest run --coverage",
|
||||
"test": "vitest run --reporter verbose",
|
||||
"test-short": "vitest run --reporter basic",
|
||||
"test-watch": "vitest --reporter verbose",
|
||||
"watch": "pnpm build --watch src"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user