Skip to content

Commit bd06e28

Browse files
committed
fix: use common color
1 parent 1f524bc commit bd06e28

File tree

4 files changed

+130
-38
lines changed

4 files changed

+130
-38
lines changed

app/components/OgImage/ShareCard.vue

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,24 @@
11
<script setup lang="ts">
2+
import { ACCENT_COLOR_TOKENS, SHARE_CARD_THEMES } from '#shared/utils/constants'
3+
import type { AccentColorId } from '#shared/utils/constants'
4+
25
const props = withDefaults(
36
defineProps<{
47
name: string
58
theme?: 'light' | 'dark'
6-
primaryColor?: string
9+
color?: string
710
}>(),
8-
{ theme: 'dark', primaryColor: '#5bc8e8' },
11+
{ theme: 'dark' },
912
)
1013
11-
const THEMES = {
12-
dark: {
13-
bg: '#0d0d0d',
14-
border: '#252525',
15-
divider: '#1a1a1a',
16-
text: '#f0f0f0',
17-
textMuted: '#9a9a9a',
18-
textSubtle: '#565656',
19-
footerBg: '#0d0d0d',
20-
},
21-
light: {
22-
bg: '#fafaf9',
23-
border: '#e0ddd8',
24-
divider: '#ebebea',
25-
text: '#1a1a1a',
26-
textMuted: '#606060',
27-
textSubtle: '#9a9898',
28-
footerBg: '#fafaf9',
29-
},
30-
} as const
31-
32-
const t = computed(() => THEMES[props.theme])
33-
// const primaryColor = computed(() => props.primaryColor || '#006fc2')
34-
const primaryColor = '#006fc2'
35-
console.log('color: ', props.primaryColor)
14+
const t = computed(() => SHARE_CARD_THEMES[props.theme])
15+
const primaryColor = computed(() => {
16+
const id = props.color as AccentColorId | undefined
17+
if (id && id in ACCENT_COLOR_TOKENS) {
18+
return ACCENT_COLOR_TOKENS[id][props.theme].hex
19+
}
20+
return ACCENT_COLOR_TOKENS.sky[props.theme].hex
21+
})
3622
3723
function withAlpha(color: string, alpha: number): string {
3824
if (color.startsWith('oklch(')) return color.replace(')', ` / ${alpha})`)
@@ -211,7 +197,7 @@ const sparklineAreaPoints = computed(() => {
211197
letterSpacing: '-1px',
212198
}"
213199
>
214-
<span :style="{ color: primaryColor, opacity: 0.6, marginRight: '-10px' }">.</span>/{{
200+
<span :style="{ color: primaryColor, marginRight: '-10px' }">.</span>/{{
215201
truncate(name, 24)
216202
}}
217203
</span>
@@ -251,7 +237,7 @@ const sparklineAreaPoints = computed(() => {
251237
marginBottom: '20px',
252238
}"
253239
>
254-
{{ truncate(description || 'No description.', 140) }}
240+
{{ truncate(description || 'No description.', 230) }}
255241
</div>
256242

257243
<!-- Tags -->
@@ -305,8 +291,8 @@ const sparklineAreaPoints = computed(() => {
305291
fontWeight: 300,
306292
padding: '4px 14px',
307293
borderRadius: '6px',
308-
border: `1px solid ${withAlpha(t.border, 0.4)}`,
309-
color: withAlpha(t.textSubtle, 0.6),
294+
border: `1px solid ${withAlpha(t.border, 0.5)}`,
295+
color: withAlpha(t.textSubtle, 0.8),
310296
lineHeight: '1.6',
311297
}"
312298
>{{ repoSlug }}</span
@@ -523,7 +509,7 @@ const sparklineAreaPoints = computed(() => {
523509
:style="{
524510
padding: '16px 40px 16px 32px',
525511
borderTop: `1px solid ${t.border}`,
526-
backgroundColor: t.footerBg,
512+
backgroundColor: t.bg,
527513
}"
528514
>
529515
<div class="flex flex-row items-center" :style="{ fontSize: '22px', fontWeight: 300 }">

app/components/Package/ShareModal.vue

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,26 @@ const props = defineProps<{
99
const { origin } = useRequestURL()
1010
const colorMode = useColorMode()
1111
const theme = computed(() => (colorMode.value === 'dark' ? 'dark' : 'light'))
12-
const { selectedAccentColor } = useAccentColor()
13-
const colorParam = computed(() =>
14-
selectedAccentColor.value ? `&color=${selectedAccentColor.value}` : '',
15-
)
12+
const { selectedAccentColor, accentColors } = useAccentColor()
13+
14+
function resolveColorToHex(color: string): string {
15+
const canvas = document.createElement('canvas')
16+
canvas.width = canvas.height = 1
17+
const ctx = canvas.getContext('2d')!
18+
ctx.fillStyle = color
19+
ctx.fillRect(0, 0, 1, 1)
20+
const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data
21+
return `#${r!.toString(16).padStart(2, '0')}${g!.toString(16).padStart(2, '0')}${b!.toString(16).padStart(2, '0')}`
22+
}
23+
24+
const colorParam = computed(() => {
25+
const id = selectedAccentColor.value
26+
if (!id) return ''
27+
const colorValue = accentColors.value.find(c => c.id === id)?.value
28+
if (!colorValue) return ''
29+
const hex = resolveColorToHex(colorValue)
30+
return `&color=${encodeURIComponent(hex)}`
31+
})
1632
1733
const cardUrl = computed(
1834
() => `/api/card/${props.packageName}.png?theme=${theme.value}${colorParam.value}`,
@@ -95,7 +111,7 @@ function handleCopyLink() {
95111
uses a bicubic/lanczos algorithm instead of nearest-neighbour.
96112
-->
97113
<div
98-
class="bg-bg-elevated rounded-lg mb-4 overflow-hidden ring-1 ring-white/10"
114+
class="bg-bg-elevated rounded-lg mb-4 overflow-hidden ring-1 ring-border"
99115
style="aspect-ratio: 1280/520"
100116
>
101117
<!-- Loading skeleton -->

app/pages/package/[[org]]/[name].vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
<script setup lang="ts">
22
import { assertValidPackageName } from '#shared/utils/npm'
3+
import { ACCENT_COLOR_TOKENS } from '#shared/utils/constants'
4+
import type { AccentColorId } from '#shared/utils/constants'
35
import { getDependencyCount } from '~/utils/npm/dependency-count'
46
7+
const { selectedAccentColor } = useAccentColor()
8+
const colorMode = useColorMode()
9+
510
defineOgImageComponent('Package', {
611
name: () => packageName.value,
712
version: () => requestedVersion.value ?? '',
8-
primaryColor: '#60a5fa',
13+
primaryColor: () => {
14+
const theme = colorMode.value === 'dark' ? 'dark' : 'light'
15+
const id = selectedAccentColor.value as AccentColorId | null
16+
return id ? ACCENT_COLOR_TOKENS[id][theme].hex : ACCENT_COLOR_TOKENS.sky[theme].hex
17+
},
918
})
1019
1120
const readmeHeader = useTemplateRef('readmeHeader')

shared/utils/constants.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,42 @@ export const ACCENT_COLORS = {
9292
},
9393
} as const satisfies Record<'light' | 'dark', Record<AccentColorId, string>>
9494

95+
export interface AccentColorToken {
96+
light: { oklch: string; hex: string }
97+
dark: { oklch: string; hex: string }
98+
}
99+
100+
export const ACCENT_COLOR_TOKENS = {
101+
sky: {
102+
light: { oklch: 'oklch(0.53 0.16 247.27)', hex: '#006fc2' },
103+
dark: { oklch: 'oklch(0.787 0.128 230.318)', hex: '#51c8fc' },
104+
},
105+
coral: {
106+
light: { oklch: 'oklch(0.56 0.17 10.75)', hex: '#c23d5c' },
107+
dark: { oklch: 'oklch(0.704 0.177 14.75)', hex: '#f9697c' },
108+
},
109+
amber: {
110+
light: { oklch: 'oklch(0.58 0.18 46.34)', hex: '#cb4c00' },
111+
dark: { oklch: 'oklch(0.828 0.165 84.429)', hex: '#f8bc1c' },
112+
},
113+
emerald: {
114+
light: { oklch: 'oklch(0.51 0.13 162.4)', hex: '#007c4f' },
115+
dark: { oklch: 'oklch(0.792 0.153 166.95)', hex: '#2edaa6' },
116+
},
117+
violet: {
118+
light: { oklch: 'oklch(0.56 0.13 282.067)', hex: '#6a68be' },
119+
dark: { oklch: 'oklch(0.78 0.148 286.067)', hex: '#b0a9ff' },
120+
},
121+
magenta: {
122+
light: { oklch: 'oklch(0.56 0.14 325)', hex: '#9c54a1' },
123+
dark: { oklch: 'oklch(0.78 0.15 330)', hex: '#ec92e5' },
124+
},
125+
neutral: {
126+
light: { oklch: 'oklch(0.145 0 0)', hex: '#0a0a0a' },
127+
dark: { oklch: 'oklch(1 0 0)', hex: '#ffffff' },
128+
},
129+
} as const satisfies Record<AccentColorId, AccentColorToken>
130+
95131
export const BACKGROUND_THEMES = {
96132
neutral: 'oklch(0.555 0 0)',
97133
stone: 'oklch(0.555 0.013 58.123)',
@@ -100,6 +136,51 @@ export const BACKGROUND_THEMES = {
100136
black: 'oklch(0.4 0 0)',
101137
} as const
102138

139+
export type BackgroundThemeId = 'neutral' | 'stone' | 'zinc' | 'slate' | 'black'
140+
141+
export interface BackgroundThemeToken {
142+
oklch: string
143+
hex: string
144+
}
145+
146+
export const BACKGROUND_THEME_TOKENS = {
147+
neutral: { oklch: 'oklch(0.555 0 0)', hex: '#737373' },
148+
stone: { oklch: 'oklch(0.555 0.013 58.123)', hex: '#79716c' },
149+
zinc: { oklch: 'oklch(0.555 0.016 285.931)', hex: '#72727c' },
150+
slate: { oklch: 'oklch(0.555 0.046 257.407)', hex: '#62748e' },
151+
black: { oklch: 'oklch(0.4 0 0)', hex: '#484848' },
152+
} as const satisfies Record<BackgroundThemeId, BackgroundThemeToken>
153+
154+
/**
155+
* Static theme tokens for the share card OG image.
156+
* Must use hex/rgb — satori (the OG image renderer) does not support oklch.
157+
* Background is not included here — use BACKGROUND_THEME_TOKENS for the card bg.
158+
* Values are hex equivalents of the corresponding CSS custom properties:
159+
* border → --border
160+
* divider → --border-subtle
161+
* text → --fg
162+
* textMuted → --fg-muted
163+
* textSubtle → --fg-subtle
164+
*/
165+
export const SHARE_CARD_THEMES = {
166+
dark: {
167+
bg: '#101010', // --bg: oklch(0.171 0 0)
168+
border: '#262626', // --border: oklch(0.269 0 0)
169+
divider: '#1f1f1f', // --border-subtle: oklch(0.239 0 0)
170+
text: '#f9f9f9', // --fg: oklch(0.982 0 0)
171+
textMuted: '#adadad', // --fg-muted: oklch(0.749 0 0)
172+
textSubtle: '#969696', // --fg-subtle: oklch(0.673 0 0)
173+
},
174+
light: {
175+
bg: '#ffffff', // --bg: oklch(1 0 0)
176+
border: '#cecece', // --border: oklch(0.8514 0 0)
177+
divider: '#e5e5e5', // --border-subtle: oklch(0.922 0 0)
178+
text: '#0a0a0a', // --fg: oklch(0.146 0 0)
179+
textMuted: '#474747', // --fg-muted: oklch(0.398 0 0)
180+
textSubtle: '#5d5d5d', // --fg-subtle: oklch(0.48 0 0)
181+
},
182+
} as const satisfies Record<'light' | 'dark', Record<string, string>>
183+
103184
// INFO: Regex for capture groups
104185
export const BLUESKY_URL_EXTRACT_REGEX = /profile\/([^/]+)\/post\/([^/]+)/
105186
export const BSKY_POST_AT_URI_REGEX =

0 commit comments

Comments
 (0)