A social knowledge tool for researchers built on ATProto

Merge pull request #26 from cosmik-network/feature/semble-landing-page

Feature/semble landing page

authored by

Wesley Finck and committed by
GitHub
b9892931 661fbf6a

+512 -24
+2 -24
src/webapp/app/page.tsx
··· 3 3 import { useAuth } from '@/hooks/useAuth'; 4 4 import { useEffect } from 'react'; 5 5 import { useRouter } from 'next/navigation'; 6 - import { Title, Text, Stack, Button, Center } from '@mantine/core'; 7 - import { FaBluesky } from 'react-icons/fa6'; 6 + import LandingPage from '@/components/LandingPage'; 8 7 9 8 export default function Home() { 10 9 const { isAuthenticated, isLoading } = useAuth(); ··· 16 15 } 17 16 }, [isAuthenticated, isLoading, router]); 18 17 19 - if (isLoading) { 20 - return <>Loading...</>; 21 - } 22 - 23 - return ( 24 - <Center h={'100svh'}> 25 - <Stack align="center"> 26 - <Stack align="center" gap={0}> 27 - <Title order={1}>Welcome to Semble</Title> 28 - <Text fw={600} fz={'xl'} c={'dark.4'}> 29 - A social knowledge tool for researchers 30 - </Text> 31 - </Stack> 32 - 33 - <Stack align="center"> 34 - <Button component="a" href="/login" leftSection={<FaBluesky />}> 35 - Sign in with Bluesky 36 - </Button> 37 - </Stack> 38 - </Stack> 39 - </Center> 40 - ); 18 + return <LandingPage />; 41 19 }
+116
src/webapp/app/signup/page.tsx
··· 1 + 'use client'; 2 + 3 + import { 4 + Title, 5 + Text, 6 + Stack, 7 + Button, 8 + Center, 9 + Card, 10 + Box, 11 + Group, 12 + } from '@mantine/core'; 13 + import { FaExternalLinkAlt } from 'react-icons/fa'; 14 + 15 + export default function SignupPage() { 16 + return ( 17 + <Center h={'100svh'}> 18 + <Card withBorder w={500} p="xl"> 19 + <Stack align="center" gap="lg"> 20 + <Title order={1} ta="center"> 21 + Welcome to Semble 22 + </Title> 23 + 24 + <Text ta="center" c="dimmed" fz="lg"> 25 + A social knowledge tool for researchers 26 + </Text> 27 + 28 + <Box 29 + style={{ 30 + backgroundColor: '#f8f9fa', 31 + padding: '1.5rem', 32 + borderRadius: '8px', 33 + border: '1px solid #e9ecef', 34 + }} 35 + > 36 + <Stack gap="md"> 37 + <Text fw={500} ta="center"> 38 + Bluesky Account Required 39 + </Text> 40 + <Text fz="sm" ta="center" c="dimmed"> 41 + Semble is built on ATProto and requires a Bluesky account to 42 + use. This ensures you own your data and can take it with you 43 + anywhere. 44 + </Text> 45 + </Stack> 46 + </Box> 47 + 48 + <Stack gap="sm" w="100%"> 49 + <Text fw={500} ta="center"> 50 + Already have a Bluesky account? 51 + </Text> 52 + <Button 53 + component="a" 54 + href="/login" 55 + size="lg" 56 + fullWidth 57 + style={{ 58 + backgroundColor: '#FF4500', 59 + color: '#FFF', 60 + }} 61 + > 62 + Sign in to Semble 63 + </Button> 64 + </Stack> 65 + 66 + <Stack gap="sm" w="100%"> 67 + <Text fw={500} ta="center"> 68 + Need a Bluesky account? 69 + </Text> 70 + <Button 71 + component="a" 72 + href="https://bsky.app" 73 + target="_blank" 74 + rel="noopener noreferrer" 75 + size="lg" 76 + variant="outline" 77 + fullWidth 78 + rightSection={<FaExternalLinkAlt size={14} />} 79 + style={{ 80 + borderColor: '#0085ff', 81 + color: '#0085ff', 82 + }} 83 + > 84 + Create account on Bluesky 85 + </Button> 86 + </Stack> 87 + 88 + <Group gap="xs" mt="md"> 89 + <Text fz="sm" c="dimmed"> 90 + Already have an account? 91 + </Text> 92 + <Text 93 + component="a" 94 + href="/login" 95 + fz="sm" 96 + c="#FF4500" 97 + style={{ 98 + textDecoration: 'none', 99 + cursor: 'pointer', 100 + }} 101 + styles={{ 102 + root: { 103 + '&:hover': { 104 + textDecoration: 'underline', 105 + }, 106 + }, 107 + }} 108 + > 109 + Sign in here 110 + </Text> 111 + </Group> 112 + </Stack> 113 + </Card> 114 + </Center> 115 + ); 116 + }
+394
src/webapp/components/LandingPage.tsx
··· 1 + 'use client'; 2 + 3 + import { 4 + Title, 5 + Text, 6 + Stack, 7 + Button, 8 + Box, 9 + Container, 10 + Group, 11 + Flex, 12 + } from '@mantine/core'; 13 + import { FaGithub, FaDiscord } from 'react-icons/fa6'; 14 + 15 + // Simple icon components 16 + const GridIcon = () => ( 17 + <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"> 18 + <rect x="3" y="3" width="7" height="7" /> 19 + <rect x="14" y="3" width="7" height="7" /> 20 + <rect x="3" y="14" width="7" height="7" /> 21 + <rect x="14" y="14" width="7" height="7" /> 22 + </svg> 23 + ); 24 + 25 + const NetworkIcon = () => ( 26 + <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"> 27 + <circle cx="6" cy="6" r="3" /> 28 + <circle cx="18" cy="6" r="3" /> 29 + <circle cx="12" cy="18" r="3" /> 30 + <path 31 + d="M9 6h6M10.5 15l3-9M13.5 15l-3-9" 32 + stroke="currentColor" 33 + strokeWidth="2" 34 + fill="none" 35 + /> 36 + </svg> 37 + ); 38 + 39 + const DatabaseIcon = () => ( 40 + <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"> 41 + <ellipse cx="12" cy="5" rx="9" ry="3" /> 42 + <path 43 + d="M3 5v14c0 1.66 4.03 3 9 3s9-1.34 9-3V5" 44 + stroke="currentColor" 45 + strokeWidth="2" 46 + fill="none" 47 + /> 48 + <path 49 + d="M3 12c0 1.66 4.03 3 9 3s9-1.34 9-3" 50 + stroke="currentColor" 51 + strokeWidth="2" 52 + fill="none" 53 + /> 54 + </svg> 55 + ); 56 + 57 + const LinkIcon = () => ( 58 + <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"> 59 + <path 60 + d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" 61 + stroke="currentColor" 62 + strokeWidth="2" 63 + fill="none" 64 + /> 65 + <path 66 + d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" 67 + stroke="currentColor" 68 + strokeWidth="2" 69 + fill="none" 70 + /> 71 + </svg> 72 + ); 73 + 74 + const CosmikIcon = () => ( 75 + <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"> 76 + <circle cx="12" cy="12" r="10" /> 77 + </svg> 78 + ); 79 + 80 + const ButterflyIcon = () => ( 81 + <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"> 82 + <path d="M12 2C8 2 5 5 5 9c0 2 1 4 3 5-2 1-3 3-3 5 0 4 3 7 7 7s7-3 7-7c0-2-1-4-3-5 2-1 3-3 3-5 0-4-3-7-7-7z" /> 83 + </svg> 84 + ); 85 + 86 + export default function LandingPage() { 87 + return ( 88 + <Box 89 + style={{ 90 + minHeight: '100vh', 91 + backgroundImage: 'url(/riverbed-background.jpg)', // You'll need to add this image 92 + backgroundSize: 'cover', 93 + backgroundPosition: 'center', 94 + position: 'relative', 95 + }} 96 + > 97 + {/* Semi-transparent overlay */} 98 + <Box 99 + style={{ 100 + position: 'absolute', 101 + top: 0, 102 + left: 0, 103 + right: 0, 104 + bottom: 0, 105 + backgroundColor: 'rgba(76, 175, 80, 0.55)', // Greenish tint 106 + }} 107 + /> 108 + 109 + {/* Content */} 110 + <Box style={{ position: 'relative', zIndex: 1 }}> 111 + {/* Header */} 112 + <Container size="xl"> 113 + <Flex 114 + justify="space-between" 115 + align="center" 116 + style={{ padding: '1rem 2rem' }} 117 + > 118 + <Text 119 + fw={700} 120 + fz="1.25rem" 121 + tt="uppercase" 122 + c="#FF4500" 123 + style={{ fontFamily: 'sans-serif' }} 124 + > 125 + SEMBLE 126 + </Text> 127 + <Group gap="sm"> 128 + <Button 129 + component="a" 130 + href="/signup" 131 + radius="xl" 132 + style={{ 133 + backgroundColor: '#FF4500', 134 + color: '#FFF', 135 + padding: '0.5rem 1rem', 136 + fontSize: '0.9rem', 137 + }} 138 + > 139 + Sign Up 140 + </Button> 141 + <Button 142 + component="a" 143 + href="/login" 144 + radius="xl" 145 + variant="outline" 146 + style={{ 147 + borderColor: '#333', 148 + color: '#333', 149 + padding: '0.5rem 1rem', 150 + fontSize: '0.9rem', 151 + }} 152 + > 153 + Login 154 + </Button> 155 + </Group> 156 + </Flex> 157 + </Container> 158 + 159 + {/* Hero Section */} 160 + <Container size="md" style={{ marginTop: '4rem' }}> 161 + <Stack align="center" gap="xl" style={{ padding: '4rem 0' }}> 162 + <Box maw={600}> 163 + <Title 164 + order={1} 165 + fw={700} 166 + c="#000" 167 + ta="center" 168 + style={{ 169 + fontSize: '3.5rem', 170 + lineHeight: 1.1, 171 + fontFamily: 'sans-serif', 172 + }} 173 + > 174 + A social knowledge tool 175 + <br /> 176 + for researchers 177 + </Title> 178 + <Text 179 + fz="1.125rem" 180 + c="#222" 181 + ta="center" 182 + mt="1rem" 183 + style={{ 184 + fontFamily: 'sans-serif', 185 + fontWeight: 400, 186 + }} 187 + > 188 + {`Follow your peers' research trails. Surface and discover new 189 + connections. Built on ATProto so you own your data.`} 190 + </Text> 191 + </Box> 192 + </Stack> 193 + </Container> 194 + 195 + {/* Features Section */} 196 + <Container size="xl" style={{ marginTop: '6rem' }}> 197 + <Flex 198 + justify="space-between" 199 + wrap="wrap" 200 + gap="2rem" 201 + style={{ marginBottom: '4rem' }} 202 + > 203 + {/* Feature 1 */} 204 + <Box style={{ width: '22%', minWidth: '200px' }}> 205 + <Stack align="flex-start" gap="0.5rem"> 206 + <Box c="#FF4500" mb="0.5rem"> 207 + <GridIcon /> 208 + </Box> 209 + <Text 210 + fw={700} 211 + fz="1rem" 212 + mb="0.25rem" 213 + style={{ fontFamily: 'sans-serif' }} 214 + > 215 + Curate your research trails. 216 + </Text> 217 + <Text 218 + fz="0.9rem" 219 + c="#333" 220 + style={{ 221 + fontFamily: 'sans-serif', 222 + lineHeight: 1.4, 223 + fontWeight: 400, 224 + }} 225 + > 226 + Collect interesting links and add context with reviews and 227 + annotations. Organize them into collections others can follow 228 + and collaborate on. 229 + </Text> 230 + </Stack> 231 + </Box> 232 + 233 + {/* Feature 2 */} 234 + <Box style={{ width: '22%', minWidth: '200px' }}> 235 + <Stack align="flex-start" gap="0.5rem"> 236 + <Box c="#FF4500" mb="0.5rem"> 237 + <NetworkIcon /> 238 + </Box> 239 + <Text 240 + fw={700} 241 + fz="1rem" 242 + mb="0.25rem" 243 + style={{ fontFamily: 'sans-serif' }} 244 + > 245 + Follow and grow your network. 246 + </Text> 247 + <Text 248 + fz="0.9rem" 249 + c="#333" 250 + style={{ 251 + fontFamily: 'sans-serif', 252 + lineHeight: 1.4, 253 + fontWeight: 400, 254 + }} 255 + > 256 + {`See what your peers are sharing and find new collaborators 257 + with shared interests. Experience research rabbit holes, 258 + together.`} 259 + </Text> 260 + </Stack> 261 + </Box> 262 + 263 + {/* Feature 3 */} 264 + <Box style={{ width: '22%', minWidth: '200px' }}> 265 + <Stack align="flex-start" gap="0.5rem"> 266 + <Box c="#FF4500" mb="0.5rem"> 267 + <DatabaseIcon /> 268 + </Box> 269 + <Text 270 + fw={700} 271 + fz="1rem" 272 + mb="0.25rem" 273 + style={{ fontFamily: 'sans-serif' }} 274 + > 275 + Own your data. 276 + </Text> 277 + <Text 278 + fz="0.9rem" 279 + c="#333" 280 + style={{ 281 + fontFamily: 'sans-serif', 282 + lineHeight: 1.4, 283 + fontWeight: 400, 284 + }} 285 + > 286 + {`Built on ATProto so you own your data. New apps will come to 287 + you – no more rebuilding your social graph and data when apps 288 + pivot and shut down.`} 289 + </Text> 290 + </Stack> 291 + </Box> 292 + 293 + {/* Feature 4 */} 294 + <Box style={{ width: '22%', minWidth: '200px' }}> 295 + <Stack align="flex-start" gap="0.5rem"> 296 + <Box c="#FF4500" mb="0.5rem"> 297 + <LinkIcon /> 298 + </Box> 299 + <Text 300 + fw={700} 301 + fz="1rem" 302 + mb="0.25rem" 303 + style={{ fontFamily: 'sans-serif' }} 304 + > 305 + Discover relevant context and connections. 306 + </Text> 307 + <Text 308 + fz="0.9rem" 309 + c="#333" 310 + style={{ 311 + fontFamily: 'sans-serif', 312 + lineHeight: 1.4, 313 + fontWeight: 400, 314 + }} 315 + > 316 + {`Easily find and filter for relevant research based on your 317 + network. See the big picture and get the extra context that 318 + matters before you dive into a long read.`} 319 + </Text> 320 + </Stack> 321 + </Box> 322 + </Flex> 323 + </Container> 324 + 325 + {/* Footer */} 326 + <Container size="xl"> 327 + <Flex 328 + justify="space-between" 329 + align="center" 330 + style={{ 331 + padding: '2rem', 332 + borderTop: '1px solid rgba(0,0,0,0.1)', 333 + }} 334 + > 335 + {/* Left side */} 336 + <Group gap="0.5rem"> 337 + <Text fz="0.875rem" c="#555" style={{ fontFamily: 'sans-serif' }}> 338 + Made by 339 + </Text> 340 + <Group gap="0.25rem"> 341 + <CosmikIcon /> 342 + <Text 343 + fz="0.875rem" 344 + c="purple" 345 + style={{ fontFamily: 'sans-serif' }} 346 + > 347 + Cosmik 348 + </Text> 349 + </Group> 350 + <Text fz="0.875rem" c="#555" style={{ fontFamily: 'sans-serif' }}> 351 + with support from Open Philanthropy and Astera 352 + </Text> 353 + <Text fz="0.875rem" c="#555" style={{ fontFamily: 'sans-serif' }}> 354 + · 355 + </Text> 356 + <Text 357 + component="a" 358 + href="#" 359 + fz="0.875rem" 360 + c="#000" 361 + style={{ 362 + fontFamily: 'sans-serif', 363 + textDecoration: 'none', 364 + }} 365 + styles={{ 366 + root: { 367 + '&:hover': { 368 + textDecoration: 'underline', 369 + }, 370 + }, 371 + }} 372 + > 373 + Privacy Policy 374 + </Text> 375 + </Group> 376 + 377 + {/* Right side */} 378 + <Group gap="0.75rem"> 379 + <Box component="a" href="#" c="#333"> 380 + <FaGithub size={24} /> 381 + </Box> 382 + <Box component="a" href="#" c="#333"> 383 + <ButterflyIcon /> 384 + </Box> 385 + <Box component="a" href="#" c="#333"> 386 + <FaDiscord size={24} /> 387 + </Box> 388 + </Group> 389 + </Flex> 390 + </Container> 391 + </Box> 392 + </Box> 393 + ); 394 + }