chore: init

This commit is contained in:
Anthony Fu 2022-11-13 13:34:43 +08:00
commit 8424b7b98b
27 changed files with 7424 additions and 0 deletions

3
.eslintrc Normal file
View file

@ -0,0 +1,3 @@
{
"extends": "@antfu"
}

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
node_modules
*.log
dist
.output
.nuxt
.env

2
.npmrc Normal file
View file

@ -0,0 +1,2 @@
shamefully-hoist=true
strict-peer-dependencies=false

4
.stackblitzrc Normal file
View file

@ -0,0 +1,4 @@
{
"installDependencies": true,
"startCommand": "npm run dev"
}

10
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
"recommendations": [
"antfu.iconify",
"antfu.unocss",
"antfu.goto-alias",
"csstools.postcss",
"dbaeumer.vscode-eslint",
"vue.volar"
]
}

10
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
"prettier.enable": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"files.associations": {
"*.css": "postcss"
},
"editor.formatOnSave": false
}

80
README.md Normal file
View file

@ -0,0 +1,80 @@
<p align="center">
<img src="https://user-images.githubusercontent.com/11247099/140462375-7b7ac4db-35b7-453c-8a05-13d8d20282c4.png" width="600"/>
</p>
<h2 align="center">
<a href="https://github.com/antfu/vitesse">Vitesse</a> for Nuxt 3
</h2><br>
<pre align="center">
🧪 Working in Progress
</pre>
<p align="center">
<br>
<a href="https://vitesse-nuxt3.netlify.app/">🖥 Online Preview</a>
<br><br>
<a href="https://stackblitz.com/github/antfu/vitesse-nuxt3"><img src="https://developer.stackblitz.com/img/open_in_stackblitz.svg" alt=""></a>
</p>
## Features
- [💚 Nuxt 3](https://v3.nuxtjs.org) - SSR, ESR, File-based routing, components auto importing, modules, etc.
- ⚡️ Vite - Instant HMR
- 🎨 [UnoCSS](https://github.com/antfu/unocss) - The instant on-demand atomic CSS engine.
- 😃 Use icons from any icon sets in Pure CSS, powered by [UnoCSS](https://github.com/antfu/unocss)
- 🔥 The `<script setup>` syntax
- 🍍 [State Management via Pinia](https://pinia.esm.dev), see [./composables/user.ts](./composables/user.ts)
- 📑 [Layout system](./layouts)
- 📥 APIs auto importing - for Composition API, VueUse and custom composables.
- 🏎 Zero-config cloud functions and deploy
- 🦾 TypeScript, of course
## Plugins
### Nuxt Modules
- [VueUse](https://github.com/vueuse/vueuse) - collection of useful composition APIs.
- [ColorMode](https://github.com/nuxt-community/color-mode-module) - dark and Light mode with auto detection made easy with Nuxt.
- [UnoCSS](https://github.com/antfu/unocss) - the instant on-demand atomic CSS engine.
- [Pinia](https://pinia.esm.dev/) - intuitive, type safe, light and flexible Store for Vue.
## IDE
We recommend using [VS Code](https://code.visualstudio.com/) with [Volar](https://github.com/johnsoncodehk/volar) to get the best experience (You might want to disable Vetur if you have it).
## Variations
- [vitesse](https://github.com/antfu/vitesse) - Opinionated Vite Starter Template
- [vitesse-lite](https://github.com/antfu/vitesse-lite) - Lightweight version of Vitesse
- [vitesse-nuxt-bridge](https://github.com/antfu/vitesse-nuxt-bridge) - Vitesse for Nuxt 2 with Bridge
- [vitesse-webext](https://github.com/antfu/vitesse-webext) - WebExtension Vite starter template
## Try it now!
### Online
<a href="https://stackblitz.com/github/antfu/vitesse-nuxt3"><img src="https://developer.stackblitz.com/img/open_in_stackblitz.svg" alt=""></a>
### GitHub Template
[Create a repo from this template on GitHub](https://github.com/antfu/vitesse-nuxt3/generate).
### Clone to local
If you prefer to do it manually with the cleaner git history
```bash
npx degit antfu/vitesse-nuxt3 my-nuxt3-app
cd my-nuxt3-app
pnpm i # If you don't have pnpm installed, run: npm install -g pnpm
```

24
api-client/index.ts Normal file
View file

@ -0,0 +1,24 @@
import { Headers, createFetch, fetch } from 'ohmyfetch'
import type { Post } from './types'
export interface MastodonClientOptions {
host: string
}
export class Client {
$fetch: ReturnType<typeof createFetch> = undefined!
constructor(public options: MastodonClientOptions) {
this.$fetch = createFetch({
defaults: {
baseURL: options.host,
},
fetch,
Headers,
})
}
getPublicTimeline(): Promise<Post[]> {
return this.$fetch('/api/v1/timelines/public')
}
}

114
api-client/types.ts Normal file
View file

@ -0,0 +1,114 @@
export interface Post {
id: string
created_at: Date
in_reply_to_id: null | string
in_reply_to_account_id: null | string
sensitive: boolean
spoiler_text: string
visibility: Visibility
language: string
uri: string
url: string
replies_count: number
reblogs_count: number
favourites_count: number
edited_at: null
favourited: boolean
reblogged: boolean
muted: boolean
bookmarked: boolean
content: string
filtered: any[]
reblog: null
account: Account
media_attachments: MediaAttachment[]
mentions: any[]
tags: Tag[]
emojis: Emoji[]
card: null
poll: null
application?: Application
}
export interface Account {
id: string
username: string
acct: string
display_name: string
locked: boolean
bot: boolean
discoverable: boolean
group: boolean
created_at: Date
note: string
url: string
avatar: string
avatar_static: string
header: string
header_static: string
followers_count: number
following_count: number
statuses_count: number
last_status_at: Date
emojis: Emoji[]
fields: Field[]
noindex?: boolean
}
export interface Emoji {
shortcode: string
url: string
static_url: string
visible_in_picker: boolean
}
export interface Field {
name: string
value: string
verified_at: Date | null
}
export interface Application {
name: string
website: null | string
}
export interface MediaAttachment {
id: string
type: string
url: string
preview_url: string
remote_url: string
preview_remote_url: null
text_url: null
meta: Meta
description: null | string
blurhash: string
}
export interface Meta {
focus?: Focus
original: Original
small: Original
}
export interface Focus {
x: number
y: number
}
export interface Original {
width: number
height: number
size: string
aspect: number
}
export interface Tag {
name: string
url: string
}
export enum Visibility {
Public = 'public',
}

29
app.vue Normal file
View file

@ -0,0 +1,29 @@
<script setup>
useHead({
title: 'Vitesse Nuxt 3',
link: [
{
rel: 'icon', type: 'image/png', href: '/nuxt.png',
},
],
})
</script>
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
<style>
html, body , #__nuxt{
height: 100vh;
margin: 0;
padding: 0;
}
html.dark {
background: #222;
color: white;
}
</style>

View file

@ -0,0 +1,23 @@
<script setup lang="ts">
import type { Account } from '~/api-client/types'
const props = defineProps<{
account: Account
}>()
</script>
<template>
<div flex gap-2>
<div p1>
<img :src="account.avatar" rounded w-10 h-10>
</div>
<div flex flex-col>
<h4 font-bold>
{{ account.display_name }}
</h4>
<p op50>
@{{ account.acct }}
</p>
</div>
</div>
</template>

View file

@ -0,0 +1,24 @@
<script setup lang="ts">
import type { Post } from '~/api-client/types'
const props = defineProps<{
post: Post
}>()
</script>
<template>
<div flex justify-around px-2>
<button flex gap-1 items-center>
<div i-ri:chat-3-line />
<span>{{ post.replies_count }}</span>
</button>
<button flex gap-1 items-center>
<div i-ri:repeat-fill />
<span>{{ post.reblogs_count }}</span>
</button>
<button flex gap-1 items-center>
<div i-ri:heart-3-line />
<span>{{ post.favourites_count }}</span>
</button>
</div>
</template>

15
components/PostCard.vue Normal file
View file

@ -0,0 +1,15 @@
<script setup lang="ts">
import type { Post } from '~/api-client/types'
const props = defineProps<{
post: Post
}>()
</script>
<template>
<div flex flex-col gap-4 mb-5>
<AccountInfo :account="post.account" />
<div v-html="post.content" />
<PostActions :post="post" />
</div>
</template>

9
composables/client.ts Normal file
View file

@ -0,0 +1,9 @@
import { Client } from '~/api-client'
const client = new Client({
host: 'https://mas.to',
})
export function useClient() {
return client
}

13
html.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
// for UnoCSS attributify mode compact in Volar
// refer: https://github.com/johnsoncodehk/volar/issues/1077#issuecomment-1145361472
declare module '@vue/runtime-dom' {
interface HTMLAttributes {
[key: string]: any
}
}
declare module '@vue/runtime-core' {
interface AllowedComponentProps {
[key: string]: any
}
}
export {}

15
layouts/README.md Normal file
View file

@ -0,0 +1,15 @@
## Layouts
Vue components in this dir are used as layouts.
By default, `default.vue` will be used unless an alternative is specified in the route meta.
```html
<script setup lang="ts">
definePageMeta({
layout: 'home',
})
</script>
```
Learn more on https://v3.nuxtjs.org/guide/directory-structure/layouts

5
layouts/default.vue Normal file
View file

@ -0,0 +1,5 @@
<template>
<main class="py-20 px-10">
<slot />
</main>
</template>

9
layouts/home.vue Normal file
View file

@ -0,0 +1,9 @@
<template>
<main class="py-20 px-10 text-center">
<slot />
<Footer />
<div class="mt-5 mx-auto text-center opacity-25 text-sm">
[Home Layout]
</div>
</main>
</template>

12
netlify.toml Executable file
View file

@ -0,0 +1,12 @@
[build.environment]
NPM_FLAGS = "--version"
NODE_VERSION = "16"
[build]
publish = "dist"
command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm run build"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

18
nuxt.config.ts Normal file
View file

@ -0,0 +1,18 @@
export default defineNuxtConfig({
modules: [
'@vueuse/nuxt',
'@unocss/nuxt',
'@pinia/nuxt',
'@nuxtjs/color-mode',
],
experimental: {
reactivityTransform: true,
inlineSSRStyles: false,
},
css: [
'@unocss/reset/tailwind.css',
],
colorMode: {
classSuffix: '',
},
})

26
package.json Normal file
View file

@ -0,0 +1,26 @@
{
"private": true,
"packageManager": "pnpm@7.9.0",
"scripts": {
"build": "nuxi build",
"dev": "nuxi dev",
"start": "node .output/server/index.mjs",
"lint": "eslint .",
"postinstall": "nuxi prepare",
"generate": "nuxi generate"
},
"devDependencies": {
"@antfu/eslint-config": "^0.30.1",
"@iconify-json/carbon": "^1.1.9",
"@iconify-json/ri": "^1.1.3",
"@iconify-json/twemoji": "^1.1.5",
"@nuxtjs/color-mode": "^3.1.8",
"@pinia/nuxt": "^0.4.3",
"@unocss/nuxt": "^0.46.5",
"@vueuse/nuxt": "^9.5.0",
"eslint": "^8.27.0",
"nuxt": "^3.0.0-rc.13",
"pinia": "^2.0.23",
"typescript": "^4.8.4"
}
}

17
pages/404.vue Normal file
View file

@ -0,0 +1,17 @@
<script setup lang="ts">
const router = useRouter()
</script>
<template>
<main p="x4 y10" text="center teal-700 dark:gray-200">
<div text-4xl>
<div i-carbon-warning inline-block />
</div>
<div>Not found</div>
<div>
<button btn text-sm m="3 t8" @click="router.back()">
Back
</button>
</div>
</main>
</template>

12
pages/index.vue Normal file
View file

@ -0,0 +1,12 @@
<script setup lang="ts">
const client = useClient()
const posts = await client.getPublicTimeline()
</script>
<template>
<div w-150>
<template v-for="post in posts" :key="post.id">
<PostCard :post="post" />
</template>
</div>
</template>

6897
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load diff

7
server/api/pageview.ts Normal file
View file

@ -0,0 +1,7 @@
const startAt = Date.now()
let count = 0
export default defineEventHandler(() => ({
pageview: count++,
startAt,
}))

6
tsconfig.json Normal file
View file

@ -0,0 +1,6 @@
{
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"strict": true
}
}

34
unocss.config.ts Normal file
View file

@ -0,0 +1,34 @@
import {
defineConfig,
presetAttributify,
presetIcons,
presetTypography,
presetUno,
presetWebFonts,
transformerDirectives,
transformerVariantGroup,
} from 'unocss'
export default defineConfig({
shortcuts: [
],
presets: [
presetUno(),
presetAttributify(),
presetIcons({
scale: 1.2,
}),
presetTypography(),
presetWebFonts({
fonts: {
sans: 'DM Sans',
serif: 'DM Serif Display',
mono: 'DM Mono',
},
}),
],
transformers: [
transformerDirectives(),
transformerVariantGroup(),
],
})