forked from mirror/codesnap.nvim
[Feat] finished preview page
parent
8f535dc24e
commit
f8773e538e
|
@ -16,6 +16,7 @@
|
||||||
"@types/node": "^16.18.81",
|
"@types/node": "^16.18.81",
|
||||||
"@types/react": "^18.2.55",
|
"@types/react": "^18.2.55",
|
||||||
"@types/react-dom": "^18.2.19",
|
"@types/react-dom": "^18.2.19",
|
||||||
|
"downloadjs": "^1.4.7",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
"html-to-image": "^1.11.11",
|
"html-to-image": "^1.11.11",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/downloadjs": "^1.4.6",
|
||||||
"daisyui": "^3.9.4",
|
"daisyui": "^3.9.4",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
|
@ -4084,6 +4086,12 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/downloadjs": {
|
||||||
|
"version": "1.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/downloadjs/-/downloadjs-1.4.6.tgz",
|
||||||
|
"integrity": "sha512-mp3w70vsaiLRT9ix92fmI9Ob2yJAPZm6tShJtofo2uHbN11G2i6a0ApIEjBl/kv3e9V7Pv7jMjk1bUwYWvMHvA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "8.56.2",
|
"version": "8.56.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
||||||
|
@ -6990,6 +6998,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
||||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/downloadjs": {
|
||||||
|
"version": "1.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz",
|
||||||
|
"integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q=="
|
||||||
|
},
|
||||||
"node_modules/duplexer": {
|
"node_modules/duplexer": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||||
|
@ -20848,6 +20861,12 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/downloadjs": {
|
||||||
|
"version": "1.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/downloadjs/-/downloadjs-1.4.6.tgz",
|
||||||
|
"integrity": "sha512-mp3w70vsaiLRT9ix92fmI9Ob2yJAPZm6tShJtofo2uHbN11G2i6a0ApIEjBl/kv3e9V7Pv7jMjk1bUwYWvMHvA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/eslint": {
|
"@types/eslint": {
|
||||||
"version": "8.56.2",
|
"version": "8.56.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
||||||
|
@ -23009,6 +23028,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
||||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
||||||
},
|
},
|
||||||
|
"downloadjs": {
|
||||||
|
"version": "1.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz",
|
||||||
|
"integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q=="
|
||||||
|
},
|
||||||
"duplexer": {
|
"duplexer": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"@types/node": "^16.18.81",
|
"@types/node": "^16.18.81",
|
||||||
"@types/react": "^18.2.55",
|
"@types/react": "^18.2.55",
|
||||||
"@types/react-dom": "^18.2.19",
|
"@types/react-dom": "^18.2.19",
|
||||||
|
"downloadjs": "^1.4.7",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
"html-to-image": "^1.11.11",
|
"html-to-image": "^1.11.11",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/downloadjs": "^1.4.6",
|
||||||
"daisyui": "^3.9.4",
|
"daisyui": "^3.9.4",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,13 @@ import useWebSocket, { ReadyState } from "react-use-websocket";
|
||||||
import { ControlBar, Editor, Frame, Panel } from "./components";
|
import { ControlBar, Editor, Frame, Panel } from "./components";
|
||||||
import { useConfig, useEvent } from "./hooks";
|
import { useConfig, useEvent } from "./hooks";
|
||||||
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from "html-to-image";
|
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from "html-to-image";
|
||||||
|
import download from "downloadjs";
|
||||||
|
|
||||||
const CODE_EMPTY_PLACEHOLDER = `print "Hello, CodeSnap.nvim!"`;
|
const CODE_EMPTY_PLACEHOLDER = `print "Hello, CodeSnap.nvim!"`;
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [socketUrl] = useState("ws://127.0.0.1:8080/ws");
|
const [socketUrl] = useState("ws://127.0.0.1:8080/ws");
|
||||||
const { sendMessage, lastMessage } = useWebSocket(socketUrl);
|
const { sendMessage, lastMessage, readyState } = useWebSocket(socketUrl);
|
||||||
const event = useEvent(lastMessage);
|
const event = useEvent(lastMessage);
|
||||||
const config = useConfig(event?.config_setup);
|
const config = useConfig(event?.config_setup);
|
||||||
const frameRef = useRef<HTMLDivElement | null>(null);
|
const frameRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
@ -30,13 +31,27 @@ function App() {
|
||||||
navigator.clipboard.write([clipboardItem]);
|
navigator.clipboard.write([clipboardItem]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleExportClick = useCallback(async () => {
|
||||||
|
if (!frameRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataURL = await toPng(frameRef.current);
|
||||||
|
|
||||||
|
download(dataURL, "codesnap.png");
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full flex flex-col items-center bg-deep-gray">
|
<div className="w-full h-full flex flex-col items-center bg-deep-gray">
|
||||||
<p className="rainbow-text text-4xl font-extrabold mt-20">
|
<p className="rainbow-text text-4xl font-extrabold mt-20">
|
||||||
CodeSnap.nvim
|
CodeSnap.nvim
|
||||||
</p>
|
</p>
|
||||||
<Panel>
|
<Panel>
|
||||||
<ControlBar onCopyClick={handleCopyButtonClick}></ControlBar>
|
<ControlBar
|
||||||
|
onExportClick={handleExportClick}
|
||||||
|
onCopyClick={handleCopyButtonClick}
|
||||||
|
readyState={readyState}
|
||||||
|
/>
|
||||||
<div className="rounded-xl overflow-hidden">
|
<div className="rounded-xl overflow-hidden">
|
||||||
<Frame ref={frameRef} watermark={config?.watermark}>
|
<Frame ref={frameRef} watermark={config?.watermark}>
|
||||||
<Editor
|
<Editor
|
||||||
|
@ -48,6 +63,17 @@ function App() {
|
||||||
</Frame>
|
</Frame>
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
<a href="https://github.com/mistricky/codesnap.nvim">
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
className="w-10 h-10 mt-10 fill-white opacity-50"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<title>GitHub</title>
|
||||||
|
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export const ColorPicker = () => {
|
|
||||||
return <div className="btn flex-grow mr-1"></div>;
|
|
||||||
};
|
|
|
@ -1,18 +1,26 @@
|
||||||
import { ColorPicker } from "./color-picker";
|
import { ConnectionStatus } from "./connection-status";
|
||||||
|
import { ReadyState } from "react-use-websocket";
|
||||||
|
|
||||||
interface ControlBarProps {
|
interface ControlBarProps {
|
||||||
onCopyClick(): void;
|
onCopyClick(): void;
|
||||||
|
onExportClick(): void;
|
||||||
|
readyState: ReadyState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ControlBar = ({ onCopyClick }: ControlBarProps) => {
|
export const ControlBar = ({
|
||||||
|
onCopyClick,
|
||||||
|
onExportClick,
|
||||||
|
readyState,
|
||||||
|
}: ControlBarProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="bg-neutral rounded-xl mb-2 p-1 flex flex-row items-center"
|
className="bg-neutral rounded-xl mb-2 p-1 flex flex-row items-center"
|
||||||
onClick={onCopyClick}
|
onClick={onCopyClick}
|
||||||
>
|
>
|
||||||
<ColorPicker></ColorPicker>
|
<ConnectionStatus readyState={readyState} />
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<button className="btn mr-1">
|
{/*
|
||||||
|
* <button className="btn mr-1">
|
||||||
<svg
|
<svg
|
||||||
role="img"
|
role="img"
|
||||||
className="h-4 w-4 fill-neutral-500"
|
className="h-4 w-4 fill-neutral-500"
|
||||||
|
@ -23,7 +31,8 @@ export const ControlBar = ({ onCopyClick }: ControlBarProps) => {
|
||||||
<path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z" />
|
<path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button className="btn mr-1">
|
*/}
|
||||||
|
<button className="btn mr-1" onClick={onExportClick}>
|
||||||
Export
|
Export
|
||||||
<svg
|
<svg
|
||||||
className="fill-neutral-content"
|
className="fill-neutral-content"
|
||||||
|
|
|
@ -6,7 +6,7 @@ export interface FrameProps {
|
||||||
|
|
||||||
export const Frame = forwardRef<HTMLDivElement, PropsWithChildren<FrameProps>>(
|
export const Frame = forwardRef<HTMLDivElement, PropsWithChildren<FrameProps>>(
|
||||||
({ children, watermark }, ref) => (
|
({ children, watermark }, ref) => (
|
||||||
<div ref={ref} className="bg-stripe min-w-[800px] p-20">
|
<div ref={ref} className="bg-relay min-w-[800px] p-20">
|
||||||
{children}
|
{children}
|
||||||
{watermark && (
|
{watermark && (
|
||||||
<p className="pacifico-regular text-xl opacity-50 font-bold text-white text-center w-full mt-14">
|
<p className="pacifico-regular text-xl opacity-50 font-bold text-white text-center w-full mt-14">
|
||||||
|
|
Loading…
Reference in New Issue