A social knowledge tool for researchers built on ATProto

feat: bookmarklet layout

Changed files
+97 -55
src
webapp
app
bookmarklet
+15
src/webapp/app/bookmarklet/layout.tsx
··· 1 + import type { Metadata } from 'next'; 2 + 3 + export const metadata: Metadata = { 4 + title: 'Semble bookmarklet', 5 + description: 6 + 'Learn how to add our bookmarklet to your browser to quickly open any webpage in Semble.', 7 + }; 8 + 9 + interface Props { 10 + children: React.ReactNode; 11 + } 12 + 13 + export default function Layout(props: Props) { 14 + return props.children; 15 + }
+82 -55
src/webapp/app/bookmarklet/page.tsx
··· 9 9 Code, 10 10 Alert, 11 11 Box, 12 + Badge, 13 + Image, 12 14 Group, 15 + Anchor, 16 + CopyButton, 13 17 } from '@mantine/core'; 14 18 import { useState } from 'react'; 15 19 import { BiInfoCircle } from 'react-icons/bi'; 20 + import SembleLogo from '@/assets/semble-logo.svg'; 21 + import Link from 'next/link'; 16 22 17 23 export default function BookmarkletPage() { 18 - const [copied, setCopied] = useState(false); 19 - 20 24 const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://127.0.0.1:4000'; 21 25 22 26 const bookmarkletCode = `javascript:(function(){ 23 27 const currentUrl = window.location.href; 24 28 const sembleUrl = '${appUrl}/url?id=' + currentUrl; 25 29 window.open(sembleUrl, '_blank'); 26 - })();`; 27 - 28 - const handleCopy = async () => { 29 - try { 30 - await navigator.clipboard.writeText(bookmarkletCode); 31 - setCopied(true); 32 - setTimeout(() => setCopied(false), 2000); 33 - } catch (err) { 34 - console.error('Failed to copy bookmarklet:', err); 35 - } 36 - }; 30 + })();`; 37 31 38 32 // Create the bookmarklet link using dangerouslySetInnerHTML to bypass React's security check 39 33 const createBookmarkletLink = () => { 40 34 return { 41 - __html: `<a href="${bookmarkletCode}" style="text-decoration: none; padding: 8px 16px; background-color: var(--mantine-color-orange-6); color: white; border-radius: 4px; display: inline-flex; align-items: center; gap: 8px;"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"/></svg>Open in Semble</a>`, 35 + __html: `<a href="${bookmarkletCode}" style="text-decoration: none; padding: 8px 16px; background-color: var(--mantine-color-tangerine-6); color: white; border-radius: 100px; display: inline-flex; align-items: center; gap: 8px; font-weight: 600;"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"/></svg>Open in Semble</a>`, 42 36 }; 43 37 }; 44 38 45 39 return ( 46 - <Container size="md" py="xl"> 40 + <Container size="sm" p="md"> 47 41 <Stack gap="xl"> 48 - <Stack gap="md"> 49 - <Title order={1}>Semble Bookmarklet</Title> 50 - <Text size="lg" c="dimmed"> 51 - Add this bookmarklet to your browser to quickly open any webpage in 52 - Semble. 53 - </Text> 42 + <Stack gap="xs" align="center"> 43 + <Stack align="center" gap={'xs'}> 44 + <Anchor component={Link} href={'/'}> 45 + <Image 46 + src={SembleLogo.src} 47 + alt="Semble logo" 48 + w={48} 49 + h={64.5} 50 + mx={'auto'} 51 + /> 52 + <Badge size="sm">Alpha</Badge> 53 + </Anchor> 54 + </Stack> 55 + <Stack gap={'xs'} align="center"> 56 + <Title order={1}>Semble Bookmarklet</Title> 57 + <Title 58 + order={2} 59 + size="xl" 60 + c="dimmed" 61 + fw={600} 62 + maw={500} 63 + ta={'center'} 64 + > 65 + Add this bookmarklet to your browser to quickly open any webpage 66 + in Semble. 67 + </Title> 68 + </Stack> 54 69 </Stack> 55 70 56 - <Alert icon={<BiInfoCircle />} title="How to install" color="orange"> 71 + <Alert title="How to install" color="grape"> 57 72 <Stack gap="sm"> 58 - <Text> 59 - 1. Copy the bookmarklet code below or drag the button to your 60 - bookmarks bar 61 - </Text> 62 - <Text> 63 - { 64 - "2. When you're on any webpage, click the bookmarklet to open it in Semble" 65 - } 66 - </Text> 73 + <Group gap={'xs'}> 74 + <Badge size="md" color="grape" circle> 75 + 1 76 + </Badge> 77 + <Text fw={500} c="grape"> 78 + Copy the bookmarklet code below or drag the button to your 79 + bookmarks bar 80 + </Text> 81 + </Group> 82 + <Group gap={'xs'}> 83 + <Badge size="md" color="grape" circle> 84 + 2 85 + </Badge> 86 + 87 + <Text fw={500} c={'grape'}> 88 + { 89 + "When you're on any webpage, click the bookmarklet to open it in Semble" 90 + } 91 + </Text> 92 + </Group> 67 93 </Stack> 68 94 </Alert> 69 95 70 96 <Stack gap="md"> 71 - <Title order={2} size="h3"> 72 - Method 1: Drag to Bookmarks Bar 73 - </Title> 74 - <Text c="dimmed"> 75 - {"Drag this button directly to your browser's bookmarks bar:"} 76 - </Text> 97 + <Stack gap={'xs'}> 98 + <Title order={3}>Method 1: Drag to Bookmarks Bar</Title> 99 + <Text c="dimmed" fw={500}> 100 + {"Drag this button directly to your browser's bookmarks bar:"} 101 + </Text> 102 + </Stack> 77 103 <Group> 78 104 <Box dangerouslySetInnerHTML={createBookmarkletLink()} /> 79 105 </Group> 80 106 </Stack> 81 107 82 108 <Stack gap="md"> 83 - <Title order={2} size="h3"> 84 - Method 2: Copy Code 85 - </Title> 86 - <Text c="dimmed"> 87 - Copy this code and create a new bookmark with it as the URL: 88 - </Text> 109 + <Stack gap={'xs'}> 110 + <Title order={3}>Method 2: Copy Code</Title> 111 + <Text c="dimmed" fw={500}> 112 + Copy this code and create a new bookmark with it as the URL: 113 + </Text> 114 + </Stack> 89 115 <Box pos="relative"> 90 116 <Code 91 117 block ··· 98 124 > 99 125 {bookmarkletCode} 100 126 </Code> 101 - <Button 102 - size="xs" 103 - variant="light" 104 - onClick={handleCopy} 105 - style={{ 106 - position: 'absolute', 107 - top: '8px', 108 - right: '8px', 109 - }} 110 - > 111 - {copied ? 'Copied!' : 'Copy'} 112 - </Button> 127 + <CopyButton value={bookmarkletCode}> 128 + {({ copied, copy }) => ( 129 + <Button 130 + color="dark" 131 + pos={'absolute'} 132 + top={12} 133 + right={12} 134 + onClick={copy} 135 + > 136 + {copied ? 'Copied!' : 'Copy'} 137 + </Button> 138 + )} 139 + </CopyButton> 113 140 </Box> 114 141 </Stack> 115 142 </Stack>