Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions site/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,7 @@ const mobileDocsNav = computed(

<UColorModeButton />

<UButton
color="neutral"
variant="ghost"
to="https://github.com/AutoFixture"
target="_blank"
icon="i-lucide-github"
aria-label="GitHub"
class="hidden sm:inline-flex"
/>
<AppGitHubButton class="hidden sm:inline-flex" />
</template>

<template #body>
Expand Down Expand Up @@ -199,7 +191,11 @@ const mobileDocsNav = computed(
</template>
</UHeader>

<UMain>
<UMain class="relative">
<AppTopGlow
class="absolute inset-x-0 -top-px -z-10 w-full shrink-0 text-primary opacity-40"
/>

<NuxtLayout>
<NuxtPage />
</NuxtLayout>
Expand Down
9 changes: 9 additions & 0 deletions site/app/assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@
border-radius: 0.5rem;
}

.landing-code {
border-color: color-mix(in oklab, var(--ui-primary) 40%, transparent);
box-shadow:
0 0 0 1px color-mix(in oklab, var(--ui-primary) 54%, transparent),
0 0 14px color-mix(in oklab, var(--ui-primary) 45%, transparent),
0 0 36px color-mix(in oklab, var(--ui-primary) 29%, transparent),
0 0 72px color-mix(in oklab, var(--ui-primary) 16%, transparent);
}

.landing-code :where(pre) {
overflow-x: auto;
margin: 0;
Expand Down
22 changes: 22 additions & 0 deletions site/app/components/AppGitHubButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
const { repoUrl, formattedStarCount } = useGitHubStars()

const accessibleLabel = computed(() => {
if (!formattedStarCount.value) return 'GitHub'
return `GitHub, ${formattedStarCount.value} stars`
})
</script>

<template>
<UButton
color="neutral"
variant="ghost"
:to="repoUrl"
target="_blank"
icon="i-lucide-github"
:aria-label="accessibleLabel"
class="tabular-nums"
>
{{ formattedStarCount }}
</UButton>
</template>
2 changes: 1 addition & 1 deletion site/app/components/AppLogo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const props = defineProps({
font-weight="700"
letter-spacing="-0.03em"
>
<tspan fill="var(--ui-primary)">Auto</tspan><tspan fill="currentColor">Fixture</tspan>
<tspan fill="currentColor">Auto</tspan><tspan fill="var(--ui-primary)">Fixture</tspan>
</text>
</svg>
</template>
65 changes: 65 additions & 0 deletions site/app/components/AppTopGlow.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<svg
viewBox="0 0 1440 120"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="pointer-events-none"
aria-hidden="true"
>
<mask
id="app-top-glow-mask"
fill="white"
>
<path d="M0 0H1440V120H0V0Z" />
</mask>
<path
d="M0 0H1440V120H0V0Z"
fill="url(#app-top-glow-fade)"
fill-opacity="0.22"
/>
<path
d="M0 2H1440V-2H0V2Z"
fill="url(#app-top-glow-edge)"
mask="url(#app-top-glow-mask)"
/>
<defs>
<linearGradient
id="app-top-glow-fade"
x1="720"
y1="0"
x2="720"
y2="120"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="currentColor" />
<stop
offset="1"
stop-color="currentColor"
stop-opacity="0"
/>
</linearGradient>
<linearGradient
id="app-top-glow-edge"
x1="0"
y1="60"
x2="1440"
y2="60"
gradientUnits="userSpaceOnUse"
>
<stop
stop-color="currentColor"
stop-opacity="0"
/>
<stop
offset="0.395"
stop-color="currentColor"
/>
<stop
offset="1"
stop-color="currentColor"
stop-opacity="0"
/>
</linearGradient>
</defs>
</svg>
</template>
21 changes: 21 additions & 0 deletions site/app/composables/useGitHubStars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export function useGitHubStars() {
const { data } = useFetch(GITHUB_REPO_API, {
key: 'github-stars',
server: false,
lazy: true,
headers: {
Accept: 'application/vnd.github+json',
},
transform: (repo: { stargazers_count: number }) => repo.stargazers_count,
})

const formattedStarCount = computed(() => {
if (data.value == null) return undefined
return formatCompactCount(data.value)
})

return {
repoUrl: GITHUB_REPO_URL,
formattedStarCount,
}
}
2 changes: 1 addition & 1 deletion site/app/composables/usePageSeo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function usePageSeo(options: PageSeoOptions = {}) {
const route = useRoute()
const { public: { siteUrl } } = useRuntimeConfig()

const title = computed(() => toValue(options.title) ?? 'AutoFixture')
const title = computed(() => formatDocumentTitle(toValue(options.title)))
const description = computed(() => toValue(options.description) ?? DEFAULT_DESCRIPTION)
const image = computed(() => `${siteUrl}${toValue(options.image) ?? DEFAULT_OG_IMAGE}`)
const url = computed(() => `${siteUrl}${route.path}`)
Expand Down
21 changes: 21 additions & 0 deletions site/app/plugins/favicon-color-scheme.client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default defineNuxtPlugin(() => {
const media = window.matchMedia('(prefers-color-scheme: dark)')
const prefersDark = ref(media.matches)

function syncPrefersDark(event?: MediaQueryListEvent) {
prefersDark.value = event?.matches ?? media.matches
}

media.addEventListener('change', syncPrefersDark)

useHead({
link: computed(() => [
{
key: 'app-favicon',
rel: 'icon',
type: 'image/svg+xml',
href: faviconHref(prefersDark.value ? 'dark' : 'light'),
},
]),
})
})
8 changes: 8 additions & 0 deletions site/app/utils/favicon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const FAVICON_VERSION = '2'

export type FaviconColorScheme = 'light' | 'dark'

export function faviconHref(colorScheme: FaviconColorScheme) {
const fileName = colorScheme === 'dark' ? 'favicon-dark.svg' : 'favicon-light.svg'
return `/${fileName}?v=${FAVICON_VERSION}`
}
17 changes: 17 additions & 0 deletions site/app/utils/formatCompactCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export function formatCompactCount(count: number): string {
if (count < 1000) {
return String(Math.round(count))
}

if (count < 1_000_000) {
return `${compactWithSuffix(count / 1000)}K`
}

return `${compactWithSuffix(count / 1_000_000)}M`
}

function compactWithSuffix(value: number): string {
const rounded = Math.round(value * 10) / 10
if (Number.isInteger(rounded)) return String(rounded)
return rounded.toFixed(1)
}
6 changes: 6 additions & 0 deletions site/app/utils/formatDocumentTitle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const SITE_NAME = 'AutoFixture'

export function formatDocumentTitle(pageTitle?: string | null): string {
if (!pageTitle || pageTitle === SITE_NAME) return SITE_NAME
return `${pageTitle} · ${SITE_NAME}`
}
2 changes: 2 additions & 0 deletions site/app/utils/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const GITHUB_REPO_URL = 'https://github.com/AutoFixture/AutoFixture'
export const GITHUB_REPO_API = 'https://api.github.com/repos/AutoFixture/AutoFixture'
11 changes: 10 additions & 1 deletion site/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export default defineNuxtConfig({
'@nuxt/content',
'@nuxt/fonts',
],
colorMode: {
preference: 'system',
fallback: 'dark',
},
css: ['~/assets/css/main.css'],
fonts: {
families: [
Expand All @@ -63,7 +67,12 @@ export default defineNuxtConfig({
{ name: 'twitter:image', content: ogImage, tagPriority: seoTagPriority },
],
link: [
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
{
key: 'app-favicon',
rel: 'icon',
type: 'image/svg+xml',
href: '/favicon.svg?v=2',
},
],
},
},
Expand Down
3 changes: 2 additions & 1 deletion site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"prepare-agent-assets": "node scripts/prepare-agent-assets.mjs",
"pregenerate": "node scripts/prepare-agent-assets.mjs",
"generate": "nuxt generate",
"preview": "nuxt preview"
"preview": "nuxt preview",
"test": "node --experimental-strip-types --test tests/*.test.ts"
},
"dependencies": {
"@nuxt/content": "^3.15.2",
Expand Down
7 changes: 7 additions & 0 deletions site/public/favicon-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions site/public/favicon-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion site/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified site/public/og-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 43 additions & 1 deletion site/public/og-image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions site/tests/formatCompactCount.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import { formatCompactCount } from '../app/utils/formatCompactCount.ts'

describe('formatCompactCount', () => {
it('formatCompactCount_WhenBelowOneThousand_ReturnsExactCount', () => {
assert.equal(formatCompactCount(0), '0')
assert.equal(formatCompactCount(999), '999')
})

it('formatCompactCount_WhenExactlyOneThousand_Returns1K', () => {
assert.equal(formatCompactCount(1000), '1K')
})

it('formatCompactCount_When3600_Returns3Point6K', () => {
assert.equal(formatCompactCount(3600), '3.6K')
})

it('formatCompactCount_When3537_Returns3Point5K', () => {
assert.equal(formatCompactCount(3537), '3.5K')
})

it('formatCompactCount_WhenExactlyThreeThousand_Returns3K', () => {
assert.equal(formatCompactCount(3000), '3K')
})

it('formatCompactCount_WhenOnePointFiveMillion_Returns1Point5M', () => {
assert.equal(formatCompactCount(1_500_000), '1.5M')
})
})
20 changes: 20 additions & 0 deletions site/tests/formatDocumentTitle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import { formatDocumentTitle } from '../app/utils/formatDocumentTitle.ts'

describe('formatDocumentTitle', () => {
it('formatDocumentTitle_WhenMissing_ReturnsAutoFixture', () => {
assert.equal(formatDocumentTitle(undefined), 'AutoFixture')
assert.equal(formatDocumentTitle(null), 'AutoFixture')
assert.equal(formatDocumentTitle(''), 'AutoFixture')
})

it('formatDocumentTitle_WhenAlreadySiteName_ReturnsAutoFixture', () => {
assert.equal(formatDocumentTitle('AutoFixture'), 'AutoFixture')
})

it('formatDocumentTitle_WhenPageTitle_AppendsAutoFixture', () => {
assert.equal(formatDocumentTitle('Introduction'), 'Introduction · AutoFixture')
assert.equal(formatDocumentTitle('Fixture'), 'Fixture · AutoFixture')
})
})