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