about summary refs log tree commit diff
path: root/bskyogcard/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'bskyogcard/src/components')
-rw-r--r--bskyogcard/src/components/Butterfly.tsx16
-rw-r--r--bskyogcard/src/components/Img.tsx10
-rw-r--r--bskyogcard/src/components/StarterPack.tsx149
3 files changed, 175 insertions, 0 deletions
diff --git a/bskyogcard/src/components/Butterfly.tsx b/bskyogcard/src/components/Butterfly.tsx
new file mode 100644
index 000000000..5a4124975
--- /dev/null
+++ b/bskyogcard/src/components/Butterfly.tsx
@@ -0,0 +1,16 @@
+import React from 'react'
+
+export function Butterfly(props: React.SVGAttributes<SVGSVGElement>) {
+  return (
+    <svg
+      xmlns="http://www.w3.org/2000/svg"
+      fill="none"
+      viewBox="0 0 568 501"
+      {...props}>
+      <path
+        fill="currentColor"
+        d="M123.121 33.664C188.241 82.553 258.281 181.68 284 234.873c25.719-53.192 95.759-152.32 160.879-201.21C491.866-1.611 568-28.906 568 57.947c0 17.346-9.945 145.713-15.778 166.555-20.275 72.453-94.155 90.933-159.875 79.748C507.222 323.8 536.444 388.56 473.333 453.32c-119.86 122.992-172.272-30.859-185.702-70.281-2.462-7.227-3.614-10.608-3.631-7.733-.017-2.875-1.169.506-3.631 7.733-13.43 39.422-65.842 193.273-185.702 70.281-63.111-64.76-33.89-129.52 80.986-149.071-65.72 11.185-139.6-7.295-159.875-79.748C9.945 203.659 0 75.291 0 57.946 0-28.906 76.135-1.612 123.121 33.664Z"
+      />
+    </svg>
+  )
+}
diff --git a/bskyogcard/src/components/Img.tsx b/bskyogcard/src/components/Img.tsx
new file mode 100644
index 000000000..dac223180
--- /dev/null
+++ b/bskyogcard/src/components/Img.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+
+export function Img(
+  props: Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'src'> & {src: Buffer},
+) {
+  const {src, ...others} = props
+  return (
+    <img {...others} src={`data:image/jpeg;base64,${src.toString('base64')}`} />
+  )
+}
diff --git a/bskyogcard/src/components/StarterPack.tsx b/bskyogcard/src/components/StarterPack.tsx
new file mode 100644
index 000000000..f73442190
--- /dev/null
+++ b/bskyogcard/src/components/StarterPack.tsx
@@ -0,0 +1,149 @@
+/* eslint-disable bsky-internal/avoid-unwrapped-text */
+import React from 'react'
+import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
+
+import {Butterfly} from './Butterfly.js'
+import {Img} from './Img.js'
+
+export const STARTERPACK_HEIGHT = 630
+export const STARTERPACK_WIDTH = 1200
+export const TILE_SIZE = STARTERPACK_HEIGHT / 3
+
+const GRADIENT_TOP = '#0A7AFF'
+const GRADIENT_BOTTOM = '#59B9FF'
+const IMAGE_STROKE = '#359CFF'
+
+export function StarterPack(props: {
+  starterPack: AppBskyGraphDefs.StarterPackView
+  images: Map<string, Buffer>
+}) {
+  const {starterPack, images} = props
+  const record = AppBskyGraphStarterpack.isRecord(starterPack.record)
+    ? starterPack.record
+    : null
+  const imagesArray = [...images.values()]
+  const imageOfCreator = images.get(starterPack.creator.did)
+  const imagesExceptCreator = [...images.entries()]
+    .filter(([did]) => did !== starterPack.creator.did)
+    .map(([, image]) => image)
+  const imagesAcross: Buffer[] = []
+  if (imageOfCreator) {
+    if (imagesExceptCreator.length >= 6) {
+      imagesAcross.push(...imagesExceptCreator.slice(0, 3))
+      imagesAcross.push(imageOfCreator)
+      imagesAcross.push(...imagesExceptCreator.slice(3, 6))
+    } else {
+      const firstHalf = Math.floor(imagesExceptCreator.length / 2)
+      imagesAcross.push(...imagesExceptCreator.slice(0, firstHalf))
+      imagesAcross.push(imageOfCreator)
+      imagesAcross.push(
+        ...imagesExceptCreator.slice(firstHalf, imagesExceptCreator.length),
+      )
+    }
+  } else {
+    imagesAcross.push(...imagesExceptCreator.slice(0, 7))
+  }
+  return (
+    <div
+      style={{
+        display: 'flex',
+        justifyContent: 'center',
+        width: STARTERPACK_WIDTH,
+        height: STARTERPACK_HEIGHT,
+        backgroundColor: 'black',
+        color: 'white',
+        fontFamily: 'Inter',
+      }}>
+      {/* image tiles */}
+      <div
+        style={{
+          display: 'flex',
+          flexWrap: 'wrap',
+          alignItems: 'stretch',
+          width: TILE_SIZE * 6,
+          height: TILE_SIZE * 3,
+        }}>
+        {[...Array(18)].map((_, i) => {
+          const image = imagesArray.at(i % imagesArray.length)
+          return (
+            <div
+              key={i}
+              style={{
+                display: 'flex',
+                height: TILE_SIZE,
+                width: TILE_SIZE,
+              }}>
+              {image && <Img height="100%" width="100%" src={image} />}
+            </div>
+          )
+        })}
+        {/* background overlay */}
+        <div
+          style={{
+            display: 'flex',
+            width: '100%',
+            height: '100%',
+            position: 'absolute',
+            backgroundImage: `linear-gradient(to bottom, ${GRADIENT_TOP}, ${GRADIENT_BOTTOM})`,
+            opacity: 0.9,
+          }}
+        />
+      </div>
+      {/* foreground text & images */}
+      <div
+        style={{
+          display: 'flex',
+          alignItems: 'center',
+          flexDirection: 'column',
+          width: '100%',
+          height: '100%',
+          position: 'absolute',
+          color: 'white',
+        }}>
+        <div
+          style={{
+            color: 'white',
+            padding: 60,
+            fontSize: 40,
+          }}>
+          JOIN THE CONVERSATION
+        </div>
+        <div style={{display: 'flex'}}>
+          {imagesAcross.map((image, i) => {
+            return (
+              <div
+                key={i}
+                style={{
+                  display: 'flex',
+                  height: 172 + 15 * 2,
+                  width: 172 + 15 * 2,
+                  margin: -15,
+                  border: `15px solid ${IMAGE_STROKE}`,
+                  borderRadius: '50%',
+                  overflow: 'hidden',
+                }}>
+                <Img height="100%" width="100%" src={image} />
+              </div>
+            )
+          })}
+        </div>
+        <div
+          style={{
+            padding: '75px 30px 0px',
+            fontSize: 65,
+          }}>
+          {record?.name || 'Starter Pack'}
+        </div>
+        <div
+          style={{
+            display: 'flex',
+            fontSize: 40,
+            justifyContent: 'center',
+            padding: '30px 30px 10px',
+          }}>
+          on <Butterfly width="65" style={{margin: '-7px 10px 0'}} /> Bluesky
+        </div>
+      </div>
+    </div>
+  )
+}