Skip to content

Commit acf0f90

Browse files
committed
Add share button and relocate copy button
1 parent 64852db commit acf0f90

File tree

8 files changed

+108
-43
lines changed

8 files changed

+108
-43
lines changed

CONTRIBUTING.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ Expected file structure:
161161
```md
162162
/snippets
163163
|- language
164-
|- category-name
165-
|- your-snippet-here.md
164+
|- category-name
165+
|- your-snippet-here.md
166166
```
167167

168168
> Please do **NOT** add or edit anything in `/public` folder. It will be used for consolidating snippets.
@@ -221,9 +221,9 @@ Example structure:
221221
```md
222222
/snippets
223223
|- python
224-
|- file-handling
225-
|- list-manipulation
226-
|- ....
224+
|- file-handling
225+
|- list-manipulation
226+
|- ....
227227
```
228228

229229
### Adding a New Language

src/components/CodePreview.tsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ import {
55
oneLight,
66
} from "react-syntax-highlighter/dist/esm/styles/prism";
77

8+
import { slugify } from "@utils/slugify";
9+
810
import CopyToClipboard from "./CopyToClipboard";
11+
import CopyURLButton from "./CopyURLButton";
912

1013
type Props = {
11-
language: string;
14+
extension: string;
15+
languageName: string;
1216
code: string;
1317
};
1418

15-
const CodePreview = ({ language = "markdown", code }: Props) => {
19+
const CodePreview = ({ extension = "markdown", languageName, code }: Props) => {
1620
const [theme, setTheme] = useState<"dark" | "light">("dark");
1721

1822
useEffect(() => {
@@ -35,15 +39,23 @@ const CodePreview = ({ language = "markdown", code }: Props) => {
3539

3640
return (
3741
<div className="code-preview">
38-
<CopyToClipboard text={code} className="modal__copy" />
39-
<SyntaxHighlighter
40-
language={language}
41-
style={theme === "dark" ? oneDark : oneLight}
42-
wrapLines={true}
43-
customStyle={{ margin: "0", maxHeight: "32rem" }}
44-
>
45-
{code}
46-
</SyntaxHighlighter>
42+
<div className="code-preview__header">
43+
<p>{slugify(languageName)}</p>
44+
<div className="code-preview__buttons">
45+
<CopyToClipboard text={code} />
46+
<CopyURLButton />
47+
</div>
48+
</div>
49+
<div className="code-preview__body">
50+
<SyntaxHighlighter
51+
language={extension}
52+
style={theme === "dark" ? oneDark : oneLight}
53+
wrapLines={true}
54+
customStyle={{ margin: "0", maxHeight: "32rem" }}
55+
>
56+
{code}
57+
</SyntaxHighlighter>
58+
</div>
4759
</div>
4860
);
4961
};

src/components/CopyToClipboard.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ const CopyToClipboard = ({ text, ...props }: Props) => {
2222

2323
return (
2424
<Button isIcon={true} onClick={copyText} {...props}>
25-
{isCopied ? "Copied!" : <CopyIcon />}
25+
<CopyIcon />
26+
<span>{isCopied ? "Copied!" : "Copy"}</span>
2627
</Button>
2728
);
2829
};

src/components/CopyURLButton.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useState } from "react";
2+
import { useLocation } from "react-router-dom";
3+
4+
import Button from "./Button";
5+
import { ShareIcon } from "./Icons";
6+
7+
type Props = {} & React.ButtonHTMLAttributes<HTMLButtonElement>;
8+
9+
const CopyURLButton = ({ ...props }: Props) => {
10+
const location = useLocation();
11+
const [isCopied, setIsCopied] = useState(false);
12+
13+
const copyText = () => {
14+
const fullURL =
15+
window.location.origin + location.pathname + location.search;
16+
navigator.clipboard
17+
.writeText(fullURL)
18+
.then(() => {
19+
setIsCopied(true);
20+
setTimeout(() => setIsCopied(false), 2000);
21+
})
22+
.catch((err) => alert("Error occurred: " + err));
23+
};
24+
25+
return (
26+
<Button isIcon={true} onClick={copyText} {...props}>
27+
<ShareIcon />
28+
<span>{isCopied ? "Shared!" : "Share"}</span>
29+
</Button>
30+
);
31+
};
32+
33+
export default CopyURLButton;

src/components/Icons.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,21 @@ export const CopyIcon: FC<IconProps> = ({ fillColor = ACCENT_ICON_COLOR }) => (
157157
</svg>
158158
);
159159

160+
export const ShareIcon: FC<IconProps> = ({ fillColor = ACCENT_ICON_COLOR }) => (
161+
<svg
162+
width="20"
163+
height="20"
164+
viewBox="0 0 20 20"
165+
fill="none"
166+
xmlns="http://www.w3.org/2000/svg"
167+
>
168+
<path
169+
d="M17.9167 3.75C17.9168 4.3204 17.7497 4.87833 17.436 5.35474C17.1224 5.83115 16.6759 6.20513 16.1518 6.43039C15.6278 6.65565 15.0492 6.72231 14.4877 6.62211C13.9261 6.52191 13.4063 6.25926 12.9925 5.86666L7.00416 9.32333C7.11027 9.7682 7.11027 10.2318 7.00416 10.6767L12.9925 14.1342C13.501 13.6522 14.166 13.3694 14.8659 13.3375C15.5657 13.3056 16.2537 13.5266 16.804 13.9602C17.3543 14.3938 17.7301 15.011 17.8628 15.6989C17.9954 16.3869 17.876 17.0996 17.5264 17.7067C17.1767 18.3138 16.6202 18.7748 15.9587 19.0053C15.2971 19.2359 14.5746 19.2206 13.9234 18.9623C13.2722 18.704 12.7357 18.2199 12.412 17.5985C12.0884 16.9771 11.9992 16.26 12.1608 15.5783L6.17 12.12C5.75586 12.5115 5.23611 12.773 4.67496 12.8724C4.11382 12.9718 3.53585 12.9046 3.01248 12.6791C2.4891 12.4536 2.04323 12.0798 1.72997 11.6037C1.4167 11.1277 1.24976 10.5703 1.24976 10.0004C1.24976 9.43053 1.4167 8.87314 1.72997 8.39709C2.04323 7.92104 2.4891 7.54719 3.01248 7.32173C3.53585 7.09626 4.11382 7.02906 4.67496 7.12842C5.23611 7.22778 5.75586 7.48936 6.17 7.88083L12.1617 4.42166C12.0669 4.02118 12.058 3.60518 12.1355 3.20101C12.213 2.79683 12.3752 2.41364 12.6113 2.0766C12.8474 1.73956 13.1522 1.45631 13.5057 1.24546C13.8591 1.03461 14.2531 0.900943 14.6619 0.853236C15.0706 0.80553 15.4849 0.844866 15.8774 0.968659C16.2698 1.09245 16.6317 1.2979 16.9391 1.5715C17.2465 1.8451 17.4925 2.18066 17.661 2.55612C17.8295 2.93159 17.9166 3.33846 17.9167 3.75Z"
170+
fill={fillColor}
171+
/>
172+
</svg>
173+
);
174+
160175
export const LeftAngleArrowIcon: FC<IconProps> = ({
161176
fillColor = ACCENT_ICON_COLOR,
162177
}) => (

src/components/SnippetList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ const SnippetList = () => {
130130
<SnippetModal
131131
snippet={snippet}
132132
handleCloseModal={handleCloseModal}
133-
language={snippet.extension}
133+
extension={snippet.extension}
134134
/>
135135
)}
136136
</AnimatePresence>

src/components/SnippetModal.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,28 @@ import { motion, useReducedMotion } from "motion/react";
22
import React from "react";
33
import ReactDOM from "react-dom";
44

5+
import { useAppContext } from "@contexts/AppContext";
56
import { useEscapeKey } from "@hooks/useEscapeKey";
67
import { SnippetType } from "@types";
7-
import { slugify } from "@utils/slugify";
88

99
import Button from "./Button";
1010
import CodePreview from "./CodePreview";
1111
import { CloseIcon } from "./Icons";
1212

1313
type Props = {
1414
snippet: SnippetType;
15-
language: string;
15+
extension: string;
1616
handleCloseModal: () => void;
1717
};
1818

1919
const SnippetModal: React.FC<Props> = ({
2020
snippet,
21-
language,
21+
extension,
2222
handleCloseModal,
2323
}) => {
2424
const modalRoot = document.getElementById("modal-root");
2525

26+
const { language, subLanguage } = useAppContext();
2627
const shouldReduceMotion = useReducedMotion();
2728

2829
useEscapeKey(handleCloseModal);
@@ -49,7 +50,7 @@ const SnippetModal: React.FC<Props> = ({
4950
key="modal-content"
5051
className="modal | flow"
5152
data-flow-space="lg"
52-
layoutId={`${language}-${snippet.title}`}
53+
layoutId={`${extension}-${snippet.title}`}
5354
transition={{
5455
ease: [0, 0.75, 0.25, 1],
5556
duration: shouldReduceMotion ? 0 : 0.3,
@@ -62,7 +63,14 @@ const SnippetModal: React.FC<Props> = ({
6263
</Button>
6364
</div>
6465
<div className="modal__body | flow">
65-
<CodePreview language={slugify(language)} code={snippet.code} />
66+
{/* TODO: update the language name and remove all-sub-languages */}
67+
<CodePreview
68+
languageName={
69+
subLanguage === "all-sub-languages" ? language.name : subLanguage
70+
}
71+
extension={extension}
72+
code={snippet.code}
73+
/>
6674
<p>
6775
<b>Description: </b>
6876
{snippet.description}

src/styles/main.css

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ abbr {
297297
.button--icon {
298298
min-height: unset;
299299
display: inline-flex;
300+
gap: 0.35em;
300301
align-items: center;
301302
justify-content: center;
302303
background-color: transparent;
@@ -490,11 +491,6 @@ abbr {
490491
transform: rotate(-90deg);
491492
transition: transform 100ms ease;
492493
cursor: pointer;
493-
transition: all 200ms ease;
494-
}
495-
496-
.sublanguage__arrow:hover {
497-
border-top-color: var(--clr-accent);
498494
}
499495

500496
[aria-expanded="true"] .sublanguage__arrow {
@@ -505,10 +501,6 @@ abbr {
505501
border-top-color: var(--clr-text-tertiary);
506502
}
507503

508-
.selector__item.selected .sublanguage__arrow:hover {
509-
border-top-color: var(--clr-text-primary);
510-
}
511-
512504
.selector__item label {
513505
width: 100%;
514506
padding: 0.25em 0.75em;
@@ -763,22 +755,26 @@ body:has(.modal-overlay) {
763755
border: 1px solid var(--clr-border-primary);
764756
border-radius: var(--br-md);
765757
width: 100%;
766-
overflow-x: auto;
758+
overflow: hidden;
767759
position: relative;
768760
}
769761

770-
.modal__copy {
771-
position: absolute;
772-
top: 0.5em;
773-
right: 1.2em;
774-
z-index: 10;
775-
isolation: isolate;
776-
background-color: var(--clr-bg-secondary);
777-
border: 1px solid var(--clr-border-primary);
762+
.code-preview__header {
763+
display: flex;
764+
gap: 1rem;
765+
justify-content: space-between;
766+
align-items: center;
767+
padding: 0.25em 1em;
778768
}
779769

780-
.modal__copy:hover {
781-
background-color: var(--clr-bg-primary);
770+
.code-preview__body {
771+
width: 100%;
772+
overflow-x: auto;
773+
}
774+
775+
.code-preview__buttons {
776+
display: flex;
777+
gap: 0.5em;
782778
}
783779

784780
.modal__tags {

0 commit comments

Comments
 (0)