Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ add snippet #583

Merged
merged 1 commit into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quick-moles-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"kitchn": minor
---

Add Snippet
12 changes: 11 additions & 1 deletion docs/components/Landing/Featured/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Container, Link, Text, Image } from "kitchn";
import kitchn, { Button, Container, Link, Text, Image, Snippet } from "kitchn";
import Balancer from "react-wrap-balancer";

const Featured: React.FC = () => {
Expand Down Expand Up @@ -53,8 +53,18 @@ const Featured: React.FC = () => {
<Button type={"dark"}>{"Contribute"}</Button>
</Link>
</Container>
<Container mt={"large"} align={"center"}>
<CustomSnippet text={"npm install kitchn"} prompt={false} />
</Container>
</Container>
);
};

export const CustomSnippet = kitchn(Snippet)`
${Text} {
padding-left: 0;
padding-right: 0;
}
`;

export default Featured;
2 changes: 1 addition & 1 deletion packages/kitchn/src/components/Badge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const BadgeComponent = styled(({ children, ...props }: BadgeProps) => {
return theme.colors.layout.light;
case "primary":
default:
return theme.colors.layout.dark;
return theme.colors.layout.darkest;
}
}};
`;
Expand Down
2 changes: 2 additions & 0 deletions packages/kitchn/src/components/Container/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Props = {
form?: boolean;
label?: boolean;
wrap?: "nowrap" | "wrap" | "wrap-reverse" | "inherit" | "initial" | "unset";
transform?: string;
};

export type ContainerProps = Props & React.ComponentPropsWithRef<"div">;
Expand Down Expand Up @@ -68,6 +69,7 @@ const ContainerComponent = styled(ForwardedContainer)<ContainerProps>`
justify-content: ${(props) => props.justify || "flex-start"};
align-items: ${(props) => props.align || "stretch"};
${(props) => props.wrap && `flex-wrap: ${props.wrap};`}
${(props) => props.transform && `transform: ${props.transform};`}

${(props) =>
props.gap &&
Expand Down
161 changes: 161 additions & 0 deletions packages/kitchn/src/components/Snippet/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import React from "react";
import { RiCheckLine, RiFileCopyLine } from "react-icons/ri";
import styled from "styled-components";

import { withDecorator } from "../../hoc";
import { useClipboard, useToasts } from "../../hooks";
import { AccentColors, KitchnComponent } from "../../types";
import Container, { ContainerProps } from "../Container";
import Icon from "../Icon";
import Text from "../Text";

type Props = {
text: string | string[];
prompt?: boolean;
type?: keyof AccentColors;
onCopy?: (text: string) => void;
};

export type SnippetProps = KitchnComponent<Props, ContainerProps>;

const SnippetComponent = styled(
({ text, prompt = true, onCopy, ...props }: SnippetProps) => {
const { copy } = useClipboard();
const { setToast } = useToasts();
const [isCopied, setIsCopied] = React.useState(false);

const copyHandler = (event: React.MouseEvent) => {
event.stopPropagation();
event.preventDefault();
copy(Array.isArray(text) ? text.join("\n") : text);
onCopy && onCopy(Array.isArray(text) ? text.join("\n") : text);
setToast({ text: "Code copied." });
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};

return (
<Container
py={"small"}
pl={"small"}
pr={32 + 15}
br={"square"}
{...props}
position={"relative"}
>
{Array.isArray(text) ? (
text.map((t, i) => (
<SnippetLine
pre
monospace
size={"compact"}
prompt={prompt}
color={"inherit"}
lineHeight={1.5}
key={i}
>
{t}
</SnippetLine>
))
) : (
<SnippetLine
pre
monospace
size={"compact"}
prompt={prompt}
color={"inherit"}
lineHeight={1.5}
>
{text}
</SnippetLine>
)}

<Container
position={"absolute"}
cursor={"pointer"}
h={32}
w={32}
top={"50%"}
right={"tiny"}
align={"center"}
justify={"center"}
transform={"translateY(-50%)"}
onClick={copyHandler}
title={"Copy Code"}
>
<Text span>
{isCopied ? (
<Icon icon={RiCheckLine} />
) : (
<Icon icon={RiFileCopyLine} />
)}
</Text>
</Container>
</Container>
);
},
)`
color: ${({ theme, type }) => {
switch (type) {
case "danger":
case "warning":
case "info":
case "success":
case "secondary":
return theme.colors.accent.light;
case "primary":
default:
return theme.colors.text.lightest;
}
}};

background-color: ${({ theme, type }) => {
switch (type) {
case "danger":
return theme.colors.accent.danger;
case "warning":
return theme.colors.accent.warning;
case "info":
return theme.colors.accent.info;
case "success":
return theme.colors.accent.success;
case "secondary":
return theme.colors.layout.light;
case "primary":
default:
return theme.colors.layout.darkest;
}
}};

border: 1px solid
${({ theme, type }) => {
switch (type) {
case "danger":
return theme.colors.accent.danger;
case "warning":
return theme.colors.accent.warning;
case "info":
return theme.colors.accent.info;
case "success":
return theme.colors.accent.success;
case "secondary":
return theme.colors.layout.light;
case "primary":
default:
return theme.colors.layout.dark;
}
}};
`;

export const SnippetLine = styled(Text)<{
prompt?: SnippetProps["prompt"];
}>`
&::before {
content: "${(props) => (props.prompt ? "$ " : "")}";
user-select: none;
}
`;

SnippetComponent.displayName = "KitchnSnippet";
export const Snippet = withDecorator(SnippetComponent);
export default Snippet;
5 changes: 4 additions & 1 deletion packages/kitchn/src/components/Text/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Props = {
i?: boolean;
span?: boolean;
em?: boolean;
pre?: boolean;
/**
* The font size.
*/
Expand Down Expand Up @@ -117,7 +118,9 @@ const TextComponent = styled(({ children, ...props }: TextProps) => {
? "span"
: props.em
? "em"
: "p";
: props.pre
? "pre"
: "p";

return (
<Component role={"text"} {...props}>
Expand Down
1 change: 1 addition & 0 deletions packages/kitchn/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export * from "./Progress";
export * from "./Scroller";
export * from "./Select";
export * from "./Skeleton";
export * from "./Snippet";
export * from "./Spacer";
export * from "./Spinner";
export * from "./Switch";
Expand Down
52 changes: 52 additions & 0 deletions workshop/pages/snippet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Container, Snippet, Text } from "kitchn";
import { NextPage } from "next";
import React from "react";

const SnippetPage: NextPage = () => {
return (
<>
<Container gap={"small"} maxW={700} mx={"auto"}>
<Text>{"default"}</Text>
<Container>
<Snippet text={"npm install kitchn"} width={"300px"} />
</Container>

<Text>{"type"}</Text>
<Container>
<Snippet
text={"npm install kitchn"}
type={"danger"}
width={"300px"}
/>
</Container>

<Text>{"muli-line"}</Text>
<Container>
<Snippet
text={[
"npm install kitchn",
"npm install kitchn",
"npm install kitchn",
]}
/>
</Container>

<Text>{"no prompt"}</Text>
<Container>
<Snippet w={300} text={"npm install kitchn"} prompt={false} />
</Container>

<Text>{"callback"}</Text>
<Container>
<Snippet
w={300}
text={"npm install kitchn"}
onCopy={() => alert("copied")}
/>
</Container>
</Container>
</>
);
};

export default SnippetPage;
Loading