chore: init
commit
8424b7b98b
|
@ -0,0 +1,6 @@
|
|||
node_modules
|
||||
*.log
|
||||
dist
|
||||
.output
|
||||
.nuxt
|
||||
.env
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"installDependencies": true,
|
||||
"startCommand": "npm run dev"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"antfu.iconify",
|
||||
"antfu.unocss",
|
||||
"antfu.goto-alias",
|
||||
"csstools.postcss",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"vue.volar"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"prettier.enable": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"files.associations": {
|
||||
"*.css": "postcss"
|
||||
},
|
||||
"editor.formatOnSave": false
|
||||
}
|
|
@ -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
|
||||
```
|
|
@ -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')
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,9 @@
|
|||
import { Client } from '~/api-client'
|
||||
|
||||
const client = new Client({
|
||||
host: 'https://mas.to',
|
||||
})
|
||||
|
||||
export function useClient() {
|
||||
return client
|
||||
}
|
|
@ -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 {}
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<main class="py-20 px-10">
|
||||
<slot />
|
||||
</main>
|
||||
</template>
|
|
@ -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>
|
|
@ -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
|
|
@ -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: '',
|
||||
},
|
||||
})
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
const startAt = Date.now()
|
||||
let count = 0
|
||||
|
||||
export default defineEventHandler(() => ({
|
||||
pageview: count++,
|
||||
startAt,
|
||||
}))
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "./.nuxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
}
|
|
@ -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(),
|
||||
],
|
||||
})
|
Loading…
Reference in New Issue