about summary refs log tree commit diff
path: root/bskyogcard/src/components/StarterPack.tsx
diff options
context:
space:
mode:
authordevin ivy <devinivy@gmail.com>2024-06-20 17:45:52 -0400
committerGitHub <noreply@github.com>2024-06-20 17:45:52 -0400
commit51f5e6bf900685ef92191f22949d09035733c682 (patch)
tree7e613992c1b131f4fe082a794ae9c32555d87b12 /bskyogcard/src/components/StarterPack.tsx
parenteac4668d7312b35721e147e808c181b2be0256bf (diff)
downloadvoidsky-51f5e6bf900685ef92191f22949d09035733c682.tar.zst
Bsky link card service (#4547)
* setup bskycard

* quick proof of concept for png card generation

* bskycard: use jsx

* bskycard: 3x5 profile layout

* bskycard: add butterfly overlay

* bskycard: tidy

* bskycard: separate and reorganize

* bskycard: tidy

* bskycard: tidy

* bskycard: tidy

* bskycard: poc of transparent overlay and box shadow

* bskycard: reorg impl into src/ directory

* bskycard: use more standard app structure

* bskycard: setup dockerfile, fix build

* bskycard: support for x-origin-verify

* bskycard: card layout, filter images based on labels

* bskycard: tidy

* bskycard: support cluster mode

* bskycard: handle error fetching starter pack info

* bskycard: tidy

* bskycard: fix leak on failed image fetch

* bskycard: build workflow

* bskyogcard: rename from bskycard

* bskyogcard: fix some express plumbing

* bskyogcard: add cdn tags, tidy
Diffstat (limited to 'bskyogcard/src/components/StarterPack.tsx')
-rw-r--r--bskyogcard/src/components/StarterPack.tsx149
1 files changed, 149 insertions, 0 deletions
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>
+  )
+}