parent
4f81d8ac53
commit
3f43af42bc
8 changed files with 272 additions and 97 deletions
@ -0,0 +1,15 @@ |
|||||||
|
export function GithubReadmeBanner() { |
||||||
|
return ( |
||||||
|
<p className="mt-3 rounded-md border p-2 text-sm"> |
||||||
|
Add this badge to your{' '} |
||||||
|
<a |
||||||
|
href="https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme" |
||||||
|
target="_blank" |
||||||
|
rel="noopener noreferrer" |
||||||
|
className="text-blue-600 underline hover:text-blue-800" |
||||||
|
> |
||||||
|
GitHub profile readme. |
||||||
|
</a> |
||||||
|
</p> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
import { useState } from 'preact/hooks'; |
||||||
|
import { LongBadge } from './LongBadge'; |
||||||
|
import { Editor, getBadgeLink } from './RoadCardPage'; |
||||||
|
import { GithubReadmeBanner } from './GithubReadmeBanner'; |
||||||
|
import { useAuth } from '../../hooks/use-auth'; |
||||||
|
|
||||||
|
export function LongBadgeTab() { |
||||||
|
const [selectedVariant, setSelectedVariant] = useState<'dark' | 'light'>( |
||||||
|
'dark' |
||||||
|
); |
||||||
|
const user = useAuth(); |
||||||
|
|
||||||
|
if (!user) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
const { badgeUrl, textareaContent, markdownSnippet } = getBadgeLink({ |
||||||
|
user, |
||||||
|
variant: selectedVariant, |
||||||
|
badge: 'long', |
||||||
|
}); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="grid gap-6 sm:grid-cols-5"> |
||||||
|
<LongBadge badgeUrl={badgeUrl} /> |
||||||
|
|
||||||
|
<div className="sm:col-span-3"> |
||||||
|
<div> |
||||||
|
<span className="text-xs uppercase leading-none text-gray-400"> |
||||||
|
Variation |
||||||
|
</span> |
||||||
|
|
||||||
|
<div className="mt-2 flex items-center gap-2"> |
||||||
|
<button |
||||||
|
className={`flex h-7 items-center justify-center rounded-lg border border-gray-200 px-3 text-sm leading-none hover:opacity-80 ${ |
||||||
|
selectedVariant === 'dark' && 'border-gray-300 bg-gray-100' |
||||||
|
}`}
|
||||||
|
onClick={() => setSelectedVariant('dark')} |
||||||
|
> |
||||||
|
Dark |
||||||
|
</button> |
||||||
|
|
||||||
|
<button |
||||||
|
className={`flex h-7 items-center justify-center rounded-lg border border-gray-200 px-3 text-sm leading-none hover:opacity-80 ${ |
||||||
|
selectedVariant === 'light' && 'border-gray-300 bg-gray-100' |
||||||
|
}`}
|
||||||
|
onClick={() => setSelectedVariant('light')} |
||||||
|
> |
||||||
|
Light |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div className="mt-4 flex flex-col gap-2"> |
||||||
|
<Editor title={'HTML'} text={textareaContent} /> |
||||||
|
<Editor title={'Markdown'} text={markdownSnippet} /> |
||||||
|
</div> |
||||||
|
|
||||||
|
<GithubReadmeBanner /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
import { useState } from 'preact/hooks'; |
||||||
|
import { useAuth } from '../../hooks/use-auth'; |
||||||
|
import { WideBadge } from './WideBadge'; |
||||||
|
import { Editor, getBadgeLink } from './RoadCardPage'; |
||||||
|
import { GithubReadmeBanner } from './GithubReadmeBanner'; |
||||||
|
|
||||||
|
export default function WideBadgeTab() { |
||||||
|
const [selectedVariant, setSelectedVariant] = useState<'dark' | 'light'>( |
||||||
|
'dark' |
||||||
|
); |
||||||
|
const user = useAuth(); |
||||||
|
if (!user) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
const { badgeUrl, textareaContent, markdownSnippet } = getBadgeLink({ |
||||||
|
user, |
||||||
|
variant: selectedVariant, |
||||||
|
badge: 'wide', |
||||||
|
}); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="flex flex-col gap-6"> |
||||||
|
<WideBadge badgeUrl={badgeUrl} /> |
||||||
|
|
||||||
|
<div> |
||||||
|
<div> |
||||||
|
<span className="text-xs uppercase leading-none text-gray-400"> |
||||||
|
Variation |
||||||
|
</span> |
||||||
|
|
||||||
|
<div className="mt-2 flex items-center gap-2"> |
||||||
|
<button |
||||||
|
className={`flex h-7 items-center justify-center rounded-lg border border-gray-200 px-3 text-sm leading-none hover:opacity-80 ${ |
||||||
|
selectedVariant === 'dark' && 'border-gray-300 bg-gray-100' |
||||||
|
}`}
|
||||||
|
onClick={() => setSelectedVariant('dark')} |
||||||
|
> |
||||||
|
Dark |
||||||
|
</button> |
||||||
|
|
||||||
|
<button |
||||||
|
className={`flex h-7 items-center justify-center rounded-lg border border-gray-200 px-3 text-sm leading-none hover:opacity-80 ${ |
||||||
|
selectedVariant === 'light' && 'border-gray-300 bg-gray-100' |
||||||
|
}`}
|
||||||
|
onClick={() => setSelectedVariant('light')} |
||||||
|
> |
||||||
|
Light |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div className={`mt-4 flex gap-2`}> |
||||||
|
<Editor title={'HTML'} text={textareaContent} /> |
||||||
|
<Editor title={'Markdown'} text={markdownSnippet} /> |
||||||
|
</div> |
||||||
|
|
||||||
|
<GithubReadmeBanner /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
type DownloadImageProps = { |
||||||
|
url: string; |
||||||
|
name: string; |
||||||
|
extension?: 'png' | 'jpg'; |
||||||
|
scale?: number; |
||||||
|
}; |
||||||
|
|
||||||
|
export async function downloadImage({ |
||||||
|
url, |
||||||
|
name, |
||||||
|
extension = 'png', |
||||||
|
scale = 1, |
||||||
|
}: DownloadImageProps) { |
||||||
|
try { |
||||||
|
const res = await fetch(url); |
||||||
|
const svg = await res.text(); |
||||||
|
|
||||||
|
const image = `data:image/svg+xml;base64,${window.btoa(svg)}`; |
||||||
|
const img = new Image(); |
||||||
|
img.src = image; |
||||||
|
img.onload = () => { |
||||||
|
const canvas = document.createElement('canvas'); |
||||||
|
canvas.width = img.width * scale; |
||||||
|
canvas.height = img.height * scale; |
||||||
|
const ctx = canvas.getContext('2d'); |
||||||
|
ctx?.drawImage(img, 0, 0, canvas.width, canvas.height); |
||||||
|
const png = canvas.toDataURL('image/png', 1.0); // Increase the quality by setting a higher value (0.0 - 1.0)
|
||||||
|
const a = document.createElement('a'); |
||||||
|
a.href = png; |
||||||
|
a.download = `${name}.${extension}`; |
||||||
|
a.click(); |
||||||
|
}; |
||||||
|
} catch (error) { |
||||||
|
alert('Error downloading image'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
import Cookies from 'js-cookie'; |
||||||
|
import { TOKEN_COOKIE_NAME, decodeToken } from '../lib/jwt'; |
||||||
|
|
||||||
|
export function useAuth() { |
||||||
|
const token = Cookies.get(TOKEN_COOKIE_NAME); |
||||||
|
if (!token) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
const user = decodeToken(token); |
||||||
|
|
||||||
|
return user; |
||||||
|
} |
Loading…
Reference in new issue