diff --git a/chickenscratch.txt b/chickenscratch.txt index e69de29..60d4557 100644 --- a/chickenscratch.txt +++ b/chickenscratch.txt @@ -0,0 +1,85 @@ +import React, { useState } from 'react'; +import { useAppDispatch, useAppSelector } from '../app/hooks'; +import { + shortenUrl, + selectShortUrl, + selectUrlStatus, + selectUrlError, + clearShortUrl, +} from '../features/url/urlSlice'; + +const Home: React.FC = () => { + // Component-level state + const [longUrl, setLongUrl] = useState(''); + + // Redux state + const dispatch = useAppDispatch(); + const shortUrl = useAppSelector(selectShortUrl); + const status = useAppSelector(selectUrlStatus); + const error = useAppSelector(selectUrlError); + + // Methods + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && longUrl.trim() !== '') { + dispatch(shortenUrl(longUrl)); + } + }; + + const handleCopy = () => { + if (shortUrl) { + navigator.clipboard.writeText(shortUrl); + } + }; + + return ( +
+
+

minxa.lol

+ + setLongUrl(e.target.value)} + onKeyDown={handleKeyDown} + className="w-full p-3 rounded-md text-lg border border-gray-300 shadow-sm focus:outline-none focus:ring-2 focus:ring-orange-400" + /> + + {/* Loading State */} + {status === 'loading' && ( +

Shortening your URL...

+ )} + + {/* Error Message */} + {status === 'failed' && error && ( +

{error}

+ )} + + {/* Short URL Display */} + {status === 'succeeded' && shortUrl && ( +
+

+ Your short URL: + + {shortUrl} + +

+ +
+ )} +
+
+ ); +}; + +export default Home; \ No newline at end of file diff --git a/public/manifest.json b/public/manifest.json index f503cf2..70a56ec 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,5 +1,5 @@ { - "short_name": "minxa", + "short_name": "minxa.lol", "name": "minxa.lol - URL Shortener", "description": "A fun and minimalist URL shortener", "icons": [ diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index a4ec3dc..97db98a 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import { useAppDispatch, useAppSelector } from '../app/hooks'; +import { copyToClipboard } from '../utils/clipboard'; import { shortenUrl, selectShortUrl, @@ -26,21 +27,63 @@ const Home: React.FC = () => { } }; + const handleCopy = () => { + if (shortUrl) { + copyToClipboard(shortUrl) + .then(() => console.log('Copied!')) + .catch((err) => console.error('Copy failed', err)); + } + }; + return (

minxa.lol

+ setLongUrl(e.target.value)} - onKeyDown={handleKeyDown} - className="w-80 p-3 rounded-md text-lg border border-gray-300 shadow-sm focus:outline-none focus:ring-2 focus:ring-orange-400" + type="text" + placeholder="Enter your long URL here" + value={longUrl} + onChange={(e) => setLongUrl(e.target.value)} + onKeyDown={handleKeyDown} + className="w-80 p-3 rounded-md text-lg border border-gray-300 shadow-sm focus:outline-none focus:ring-2 focus:ring-orange-400" /> + + {/* Loading State */} + {status === 'loading' && ( +

Shortening your URL...

+ )} + + {/* Error Message */} + {status === 'failed' && ( +

{error}

+ )} + + {/* Short URL Display */} + {status === 'succeeded' && shortUrl && ( +
+

+ Your short URL: + + {shortUrl} + +

+ +
+ )}
); }; -export default Home; \ No newline at end of file +export default Home; + diff --git a/src/utils/clipboard.ts b/src/utils/clipboard.ts new file mode 100644 index 0000000..c6d4689 --- /dev/null +++ b/src/utils/clipboard.ts @@ -0,0 +1,36 @@ + +export function copyToClipboard(text: string): Promise { + if (navigator.clipboard && window.isSecureContext) { + // ✅ Modern way + return navigator.clipboard.writeText(text); + } else { + // 🚨 Fallback for insecure context or unsupported browsers + const textArea = document.createElement('textarea'); + textArea.value = text; + + // Avoid scrolling to bottom + textArea.style.position = 'fixed'; + textArea.style.top = '0'; + textArea.style.left = '0'; + textArea.style.width = '2em'; + textArea.style.height = '2em'; + textArea.style.padding = '0'; + textArea.style.border = 'none'; + textArea.style.outline = 'none'; + textArea.style.boxShadow = 'none'; + textArea.style.background = 'transparent'; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + } catch (err) { + console.error('Fallback: Oops, unable to copy', err); + } + + document.body.removeChild(textArea); + return Promise.resolve(); + } +} \ No newline at end of file