11import React , { useState } from 'react' ;
22import { Link } from 'react-router-dom' ;
3- import { ArrowLeftIcon , SkullIcon } from '@phosphor-icons/react' ;
3+ import { ArrowLeftIcon , SkullIcon , CopySimple } from '@phosphor-icons/react' ;
44import colors from '../../config/colors' ;
55import useSeo from '../../hooks/useSeo' ;
6+ import { useToast } from '../../hooks/useToast' ;
67
78const pirateDictionary = {
89 "hello" : "ahoy" ,
@@ -90,20 +91,7 @@ const pirateDictionary = {
9091 "forward" : "fore" ,
9192} ;
9293
93- const piratePhrases = [
94- " Arrr!" ,
95- " Shiver me timbers!" ,
96- " Walk the plank!" ,
97- " Yo ho ho!" ,
98- " Avast ye!" ,
99- " Dead men tell no tales." ,
100- " By Blackbeard's ghost!" ,
101- " Blow me down!" ,
102- " Savvy?" ,
103- " ...and a bottle of rum!" ,
104- " Weigh anchor!" ,
105- " Batten down the hatches!" ,
106- ] ;
94+ const piratePhrases = [ " Arrr!" , " Shiver me timbers!" , " Walk the plank!" , " Yo ho ho!" , " Avast ye!" , " Dead men tell no tales." , " By Blackbeard's ghost!" , " Blow me down!" , " Savvy?" , " ...and a bottle of rum!" , " Weigh anchor!" , " Batten down the hatches!" , ] ;
10795
10896const PirateTranslatorPage = ( ) => {
10997 useSeo ( {
@@ -118,33 +106,34 @@ const PirateTranslatorPage = () => {
118106 twitterDescription : 'Translate yer landlubber words into proper Pirate speak!' ,
119107 twitterImage : 'https://fezcode.github.io/logo512.png' ,
120108 } ) ;
121-
109+ const { addToast } = useToast ( ) ;
122110 const [ inputText , setInputText ] = useState ( '' ) ;
123111 const [ translatedText , setTranslatedText ] = useState ( '' ) ;
124-
125112 const translate = ( ) => {
126113 let text = inputText . toLowerCase ( ) ;
127114 // Dictionary replacements
128115 Object . keys ( pirateDictionary ) . forEach ( key => {
129116 const regex = new RegExp ( `\\b${ key } \\b` , 'g' ) ;
130117 text = text . replace ( regex , pirateDictionary [ key ] ) ;
131118 } ) ;
132-
133119 // Grammar tweaks: replacing 'ing' at the end of words with "in'"
134120 text = text . replace ( / i n g \b / g, "in'" ) ;
135-
136121 // Capitalize first letter of sentences
137122 text = text . replace ( / ( ^ \w | \. \s \w ) / g, c => c . toUpperCase ( ) ) ;
138-
139123 // Add some pirate flair randomly
140124 if ( text . length > 0 ) {
141125 const randomPhrase = piratePhrases [ Math . floor ( Math . random ( ) * piratePhrases . length ) ] ;
142126 text += randomPhrase ;
143127 }
144-
145128 setTranslatedText ( text ) ;
146129 } ;
147-
130+ const copyToClipboard = ( ) => {
131+ navigator . clipboard . writeText ( translatedText ) . then ( ( ) => {
132+ addToast ( { title : 'Copied!' , message : 'Translated text copied to clipboard.' , duration : 2000 } ) ;
133+ } ) . catch ( ( ) => {
134+ addToast ( { title : 'Error' , message : 'Failed to copy translated text!' , duration : 2000 } ) ;
135+ } ) ;
136+ } ;
148137 const cardStyle = {
149138 backgroundColor : colors [ 'app-alpha-10' ] ,
150139 borderColor : colors [ 'app-alpha-50' ] ,
@@ -176,8 +165,7 @@ const PirateTranslatorPage = () => {
176165 < div
177166 className = "absolute top-0 left-0 w-full h-full opacity-10"
178167 style = { {
179- backgroundImage :
180- 'radial-gradient(circle, white 1px, transparent 1px)' ,
168+ backgroundImage : 'radial-gradient(circle, white 1px, transparent 1px)' ,
181169 backgroundSize : '10px 10px' ,
182170 } }
183171 > </ div >
@@ -186,29 +174,37 @@ const PirateTranslatorPage = () => {
186174 < SkullIcon size = { 32 } /> Pirate Speak Translator
187175 </ h1 >
188176 < hr className = "border-gray-700 mb-6" />
189-
190177 < div className = "flex flex-col gap-4 mb-6" >
191178 < textarea
192179 value = { inputText }
193180 onChange = { ( e ) => setInputText ( e . target . value ) }
194181 placeholder = "Type yer message here, matey..."
195182 className = "w-full h-32 bg-black/20 border border-gray-600 rounded px-3 py-2 focus:outline-none focus:border-red-500 transition-colors resize-none"
196183 />
197- < button
198- onClick = { translate }
199- className = "px-6 py-2 rounded-md font-arvo font-normal border transition-colors duration-300 hover:bg-red-500/20 text-red-500 border-red-500"
200- >
201- Translate, Yarr!
202- </ button >
184+ < div className = "flex justify-center gap-4" >
185+ < button
186+ onClick = { translate }
187+ className = "px-6 py-2 rounded-md font-arvo font-normal border transition-colors duration-300 hover:bg-red-500/20 text-red-500 border-red-500"
188+ >
189+ Translate, Yarr!
190+ </ button >
191+ < button
192+ onClick = { copyToClipboard }
193+ disabled = { ! translatedText }
194+ className = { `px-6 py-2 rounded-md font-arvo font-normal border transition-colors duration-300 text-blue-500 border-blue-500 hover:bg-blue-500 hover:text-white ${
195+ ! translatedText ? 'opacity-50 cursor-not-allowed' : ''
196+ } `}
197+ >
198+ < CopySimple size = { 24 } className = "inline-block mr-2" /> Copy
199+ </ button >
200+ </ div >
203201 </ div >
204-
205202 { translatedText && (
206203 < div
207204 className = "bg-black/30 p-4 rounded border border-gray-700 min-h-[80px] text-left font-serif italic text-lg text-gray-200" >
208205 { translatedText }
209206 </ div >
210207 ) }
211-
212208 </ div >
213209 </ div >
214210 </ div >
0 commit comments