mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: in-heading testing
This commit is contained in:
1 parent
8ad110f73b
commit
841b5708ae
5 files changed
+89
-25
No files matched your search
@@ -2,8 +2,6 @@
|
|||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { api } from "../core/api/dynamic";
|
import { api } from "../core/api/dynamic";
|
||||||
import { ApiTester } from "./ApiTester";
|
import { ApiTester } from "./ApiTester";
|
||||||
import { Code } from "./Code";
|
|
||||||
import { Heading } from "./Heading";
|
|
||||||
import { MarkdownCustom } from "./MarkdownCustom";
|
import { MarkdownCustom } from "./MarkdownCustom";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -25,10 +23,6 @@ const hasSlugs = apiData.id.includes("[");
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<Heading size="3">
|
|
||||||
<Code>{apiData.id}</Code>
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<ApiTester client:idle {locale} path={apiData.id} />
|
<ApiTester client:idle {locale} path={apiData.id} />
|
||||||
|
|
||||||
<MarkdownCustom body={apiData.data.docs ?? strings.api.no_docs} />
|
<MarkdownCustom body={apiData.data.docs ?? strings.api.no_docs} />
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--space-4);
|
gap: var(--space-4);
|
||||||
|
|
||||||
.slug {
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--space-3);
|
gap: var(--space-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@ import {
|
|||||||
} from "../../hooks/useLocale";
|
} from "../../hooks/useLocale";
|
||||||
import { useStrings } from "../../hooks/useStrings";
|
import { useStrings } from "../../hooks/useStrings";
|
||||||
import { Button } from "../Button";
|
import { Button } from "../Button";
|
||||||
|
import { Code } from "../Code";
|
||||||
|
import { Heading } from "../Heading";
|
||||||
import { Link } from "../Link";
|
import { Link } from "../Link";
|
||||||
import { TextField } from "../TextField";
|
import { TextField } from "../TextField";
|
||||||
import styles from "./index.module.css";
|
import styles from "./index.module.css";
|
||||||
@@ -38,19 +40,36 @@ function Content({ path }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.tester}>
|
<div className={styles.tester}>
|
||||||
{slugs.map((slug) => (
|
<Heading size="3">
|
||||||
<div className={styles.slug}>
|
<Code className={styles.title}>
|
||||||
{slug}:{" "}
|
{path.split(slugPattern).map((text, index) => {
|
||||||
<TextField
|
const slug = slugs[index - 1];
|
||||||
value={values[slug]}
|
|
||||||
onChange={(event) => {
|
|
||||||
setValues((state) => ({ ...state, [slug]: event.target.value }));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<Link href={href} target="_blank">
|
return (
|
||||||
|
<>
|
||||||
|
{index > 0 && (
|
||||||
|
<TextField
|
||||||
|
className={styles.slug}
|
||||||
|
placeholder={`${slug}`}
|
||||||
|
monospace
|
||||||
|
align="center"
|
||||||
|
autoWidth
|
||||||
|
onChange={(event) => {
|
||||||
|
setValues((state) => ({
|
||||||
|
...state,
|
||||||
|
[slug]: event.target.value,
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span key={index}>{text}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Code>
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<Link underline="never" href={href} target="_blank">
|
||||||
<Button>{strings.api.test}</Button>
|
<Button>{strings.api.test}</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -53,8 +53,7 @@
|
|||||||
|
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
font-weight: medium;
|
font-weight: medium;
|
||||||
padding: var(--space-3) 0;
|
padding: var(--space-3) var(--space-4);
|
||||||
padding-left: var(--space-4);
|
|
||||||
|
|
||||||
color: var(--gray-12);
|
color: var(--gray-12);
|
||||||
|
|
||||||
@@ -65,5 +64,16 @@
|
|||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[data-align="center"] {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
&[data-align="right"] {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-monospace="true"] {
|
||||||
|
font-family: var(--font-family-mono);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
|
useCallback,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
useRef,
|
useRef,
|
||||||
|
type ChangeEvent,
|
||||||
type ComponentProps,
|
type ComponentProps,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
} from "react";
|
} from "react";
|
||||||
@@ -10,12 +12,40 @@ import "./index.css";
|
|||||||
|
|
||||||
export interface TextFieldProps extends ComponentProps<"input"> {
|
export interface TextFieldProps extends ComponentProps<"input"> {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
align?: "left" | "center" | "right";
|
||||||
|
monospace?: boolean;
|
||||||
|
autoWidth?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||||
({ children, className, placeholder, disabled, ...props }, ref) => {
|
(
|
||||||
|
{
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
monospace,
|
||||||
|
autoWidth,
|
||||||
|
placeholder,
|
||||||
|
align,
|
||||||
|
disabled,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
const input = useRef<HTMLInputElement>(null);
|
const input = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (autoWidth && input.current) {
|
||||||
|
input.current.style.width = `${event.target.value.length || event.target.placeholder.length}ch`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange?.(event);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => input.current!, []);
|
useImperativeHandle(ref, () => input.current!, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -26,8 +56,19 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
|||||||
data-disabled={disabled}
|
data-disabled={disabled}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<input disabled={disabled} ref={input} placeholder={placeholder} />
|
<input
|
||||||
|
data-align={align === "left" ? undefined : align}
|
||||||
|
data-monospace={monospace}
|
||||||
|
disabled={disabled}
|
||||||
|
ref={input}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={value}
|
||||||
|
style={{
|
||||||
|
width: `${value?.toString().length || placeholder?.length || 0}ch`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Reference in new issue
Block a user