Skip to content
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@heroui/input": "^2.4.25",
"@heroui/kbd": "^2.2.19",
"@heroui/link": "^2.2.21",
"@heroui/modal": "^2.2.21",
"@heroui/navbar": "^2.2.22",
"@heroui/snippet": "^2.2.25",
"@heroui/switch": "^2.2.22",
Expand Down
108 changes: 104 additions & 4 deletions src/components/editor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useEffect, useRef, useState } from "react";
import { Button } from "@heroui/button";
import { Card, CardBody } from "@heroui/card";
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure } from "@heroui/modal";
import { Input } from "@heroui/input";
import { useTheme } from "@heroui/use-theme";

import { vietnameseInput, InputMethod } from "@/utils/vietnamese-input";
Expand Down Expand Up @@ -31,7 +33,9 @@ export default function Editor({
const [isVietnameseEnabled, setIsVietnameseEnabled] = useState(true);
const [editorInstance, setEditorInstance] = useState<any>(null);
const [content, setContent] = useState(initialContent);
const [filename, setFilename] = useState("vinakey-document");
const { theme } = useTheme();
const { isOpen, onOpen, onOpenChange } = useDisclosure();

// Check if user is visiting for the first time
const isFirstVisit = !localStorage.getItem("vinakey2-visited");
Expand Down Expand Up @@ -190,6 +194,40 @@ export default function Editor({
}
};

const handlePaste = async () => {
try {
const clipboardText = await navigator.clipboard.readText();
if (editorInstance && clipboardText) {
editorInstance.setValue(clipboardText);
setContent(clipboardText);
console.log("Content pasted from clipboard");
}
} catch (err) {
console.error("Failed to paste content:", err);
}
};

const handleDownload = () => {
if (content) {
onOpen(); // Open modal for filename input
}
};

const handleConfirmDownload = () => {
const finalFilename = filename.trim() || "vinakey-document";
const blob = new Blob([content], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `${finalFilename}.md`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
console.log(`Content downloaded as ${finalFilename}.md`);
onOpenChange(); // Close modal
};

return (
<div className="w-full max-w-6xl mx-auto">
{/* Consolidated card with controls and editor */}
Expand Down Expand Up @@ -230,7 +268,16 @@ export default function Editor({
</div>

{/* Second row: Action buttons (hidden on small screens when in single row, shown on mobile) */}
<div className="!flex !flex-row !items-center !justify-start sm:!justify-end !gap-2 sm:!flex-grow">
<div className="!flex !flex-row !items-center !justify-start sm:!justify-end !gap-2 sm:!flex-grow !flex-wrap">
<Button
color="warning"
size="sm"
variant="bordered"
onClick={handleClear}
className="!px-2 !py-1 !min-w-0 !text-xs !font-medium !whitespace-nowrap !flex-shrink-0"
>
Clear
</Button>
<Button
color="primary"
disabled={!content}
Expand All @@ -242,13 +289,23 @@ export default function Editor({
Copy
</Button>
<Button
color="warning"
color="secondary"
size="sm"
variant="bordered"
onClick={handleClear}
onClick={handlePaste}
className="!px-2 !py-1 !min-w-0 !text-xs !font-medium !whitespace-nowrap !flex-shrink-0"
>
Clear
Paste
</Button>
<Button
color="success"
disabled={!content}
size="sm"
variant="bordered"
onClick={handleDownload}
className="!px-2 !py-1 !min-w-0 !text-xs !font-medium !whitespace-nowrap !flex-shrink-0"
>
Download
</Button>
</div>
</CardBody>
Expand All @@ -262,6 +319,49 @@ export default function Editor({
/>
</Card>
</div>

{/* Download filename modal */}
<Modal
isOpen={isOpen}
onOpenChange={onOpenChange}
placement="top-center"
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">Download File</ModalHeader>
<ModalBody>
<p className="text-sm text-default-500 mb-3">
Enter a filename for your markdown document:
</p>
<Input
autoFocus
label="Filename"
placeholder="vinakey-document"
value={filename}
onValueChange={setFilename}
variant="bordered"
description="The file will be saved as .md format"
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleConfirmDownload();
}
}}
/>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="light" onPress={onClose}>
Cancel
</Button>
<Button color="primary" onPress={handleConfirmDownload}>
Download
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
</div>
);
}
2 changes: 1 addition & 1 deletion src/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function Provider({ children }: { children: React.ReactNode }) {
const navigate = useNavigate();

return (
<HeroUIProvider navigate={navigate} useHref={useHref}>
<HeroUIProvider navigate={navigate} useHref={useHref} defaultTheme="light">
{children}
</HeroUIProvider>
);
Expand Down
51 changes: 51 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,26 @@
"@react-types/menu" "3.10.3"
"@react-types/shared" "3.31.0"

"@heroui/modal@^2.2.21":
version "2.2.21"
resolved "https://registry.yarnpkg.com/@heroui/modal/-/modal-2.2.21.tgz#a4871a286f4a684d31c52ccfcf43ac143dc66830"
integrity sha512-VZDwDS+UnYrpCYvqkGTIlm9ADy7s8vvQo1ueLts7WCSYpMxWu6YDnJpkHnth2AyhEzdXGIskbMm96TZW5jwdAQ==
dependencies:
"@heroui/dom-animation" "2.1.10"
"@heroui/framer-utils" "2.1.20"
"@heroui/react-utils" "2.1.12"
"@heroui/shared-icons" "2.1.10"
"@heroui/shared-utils" "2.1.10"
"@heroui/use-aria-button" "2.2.18"
"@heroui/use-aria-modal-overlay" "2.2.17"
"@heroui/use-disclosure" "2.2.15"
"@heroui/use-draggable" "2.1.16"
"@heroui/use-viewport-size" "2.0.1"
"@react-aria/dialog" "3.5.28"
"@react-aria/focus" "3.21.0"
"@react-aria/overlays" "3.28.0"
"@react-stately/overlays" "3.6.18"

"@heroui/navbar@^2.2.22":
version "2.2.22"
resolved "https://registry.yarnpkg.com/@heroui/navbar/-/navbar-2.2.22.tgz#6c632964ea1219a0115355b6f875a795d07f98c6"
Expand Down Expand Up @@ -814,6 +834,16 @@
"@react-types/link" "3.6.3"
"@react-types/shared" "3.31.0"

"@heroui/use-aria-modal-overlay@2.2.17":
version "2.2.17"
resolved "https://registry.yarnpkg.com/@heroui/use-aria-modal-overlay/-/use-aria-modal-overlay-2.2.17.tgz#389b85f5e489571ec7bab0d4320355da70b95647"
integrity sha512-exLtnPX31BUJ7Iq6IH7d/Z8MfoCm9GpQ03B332KBLRbHMM+pye3P1h74lNtdQzIf0OHFSMstJ4gLSs4jx3t6KQ==
dependencies:
"@heroui/use-aria-overlay" "2.0.2"
"@react-aria/overlays" "3.28.0"
"@react-aria/utils" "3.30.0"
"@react-stately/overlays" "3.6.18"

"@heroui/use-aria-overlay@2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@heroui/use-aria-overlay/-/use-aria-overlay-2.0.2.tgz#1d244d943dcbde1f8bafe5fe3351eac01c297054"
Expand All @@ -836,6 +866,22 @@
resolved "https://registry.yarnpkg.com/@heroui/use-clipboard/-/use-clipboard-2.1.9.tgz#09654698b929560f8dd68d2d87cfaa37ffa0ea55"
integrity sha512-lkBq5RpXHiPvk1BXKJG8gMM0f7jRMIGnxAXDjAUzZyXKBuWLoM+XlaUWmZHtmkkjVFMX1L4vzA+vxi9rZbenEQ==

"@heroui/use-disclosure@2.2.15":
version "2.2.15"
resolved "https://registry.yarnpkg.com/@heroui/use-disclosure/-/use-disclosure-2.2.15.tgz#c49c97d47c5d277eeab302b010655cf0a1a83b0e"
integrity sha512-a29HObRfjb6pQ7lvv/WZbvXhGv4BLI4fDrEnVnybfFdC3pCmwyoZxOuqraiDT8IXvVFIiuIcX6719ezruo64kQ==
dependencies:
"@heroui/use-callback-ref" "2.1.8"
"@react-aria/utils" "3.30.0"
"@react-stately/utils" "3.10.8"

"@heroui/use-draggable@2.1.16":
version "2.1.16"
resolved "https://registry.yarnpkg.com/@heroui/use-draggable/-/use-draggable-2.1.16.tgz#1c9f6355e06ca45b2fdc34536da7351dd561744f"
integrity sha512-IcpdnMLmcIDeo7EG41VHSE2jBbYP5dEyNThFirReNh8fMZ6rW2hAd0lf0M0/R5kgTSKUxdNhecY6csDedP+8gA==
dependencies:
"@react-aria/interactions" "3.25.4"

"@heroui/use-is-mobile@2.2.12":
version "2.2.12"
resolved "https://registry.yarnpkg.com/@heroui/use-is-mobile/-/use-is-mobile-2.2.12.tgz#a00a7c543a90d7e26fdccd7a199806d26f8c32a2"
Expand Down Expand Up @@ -868,6 +914,11 @@
resolved "https://registry.yarnpkg.com/@heroui/use-theme/-/use-theme-2.1.10.tgz#1bbb763437dbcda69c222cdc8c6b710e03fe7727"
integrity sha512-JM9Y56bzHMU0rEz1K86Tnli2oRqQY3/NYNOHXbVXQtP+ZB2eabm9Cbl15bPZzSskpEsD5oKnbccFV4dCYhenmw==

"@heroui/use-viewport-size@2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@heroui/use-viewport-size/-/use-viewport-size-2.0.1.tgz#3a2a5029b33b11bf6f4c7eb96b7580996f08b860"
integrity sha512-blv8BEB/QdLePLWODPRzRS2eELJ2eyHbdOIADbL0KcfLzOUEg9EiuVk90hcSUDAFqYiJ3YZ5Z0up8sdPcR8Y7g==

"@humanfs/core@^0.19.1":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
Expand Down
Loading