Initial commit 🚀
13
.editorconfig
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
17
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# Fetch and update latest `npm` packages
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: '/'
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
time: '00:00'
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
reviewers:
|
||||||
|
- arthurdanjou
|
||||||
|
assignees:
|
||||||
|
- arthurdanjou
|
||||||
|
commit-message:
|
||||||
|
prefix: fix
|
||||||
|
prefix-development: chore
|
||||||
|
include: scope
|
||||||
47
.gitignore
vendored
@@ -1,13 +1,11 @@
|
|||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Node template
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
/logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
# Runtime data
|
||||||
pids
|
pids
|
||||||
@@ -20,12 +18,11 @@ lib-cov
|
|||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
# Coverage directory used by tools like istanbul
|
||||||
coverage
|
coverage
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
# nyc test coverage
|
||||||
.nyc_output
|
.nyc_output
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
.grunt
|
.grunt
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
# Bower dependency directory (https://bower.io/)
|
||||||
@@ -53,12 +50,6 @@ typings/
|
|||||||
# Optional eslint cache
|
# Optional eslint cache
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
# Optional REPL history
|
||||||
.node_repl_history
|
.node_repl_history
|
||||||
|
|
||||||
@@ -70,35 +61,33 @@ typings/
|
|||||||
|
|
||||||
# dotenv environment variables file
|
# dotenv environment variables file
|
||||||
.env
|
.env
|
||||||
.env.test
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.cache
|
.cache
|
||||||
|
|
||||||
# Next.js build output
|
# next.js build output
|
||||||
.next
|
.next
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
# nuxt.js build output
|
||||||
.nuxt
|
.nuxt
|
||||||
dist
|
|
||||||
|
|
||||||
# Gatsby files
|
# Nuxt generate
|
||||||
.cache/
|
dist
|
||||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
# vuepress build output
|
||||||
.vuepress/dist
|
.vuepress/dist
|
||||||
|
|
||||||
# Serverless directories
|
# Serverless directories
|
||||||
.serverless/
|
.serverless
|
||||||
|
|
||||||
# FuseBox cache
|
# IDE / Editor
|
||||||
.fusebox/
|
.idea
|
||||||
|
|
||||||
# DynamoDB Local files
|
# Service worker
|
||||||
.dynamodb/
|
sw.*
|
||||||
|
|
||||||
# TernJS port file
|
# macOS
|
||||||
.tern-port
|
.DS_Store
|
||||||
|
|
||||||
|
# Vim swap files
|
||||||
|
*.swp
|
||||||
|
|||||||
205
build/App.js
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
import { getMatchedComponentsInstances, getChildrenComponentInstancesUsingFetch, promisify, globalHandleError, urlJoin, sanitizeComponent } from './utils'
|
||||||
|
import NuxtError from '..\\src\\templates\\layouts\\error.vue'
|
||||||
|
import NuxtLoading from './components/nuxt-loading.vue'
|
||||||
|
import NuxtBuildIndicator from './components/nuxt-build-indicator'
|
||||||
|
|
||||||
|
import '..\\src\\assets\\css\\tailwind.css'
|
||||||
|
|
||||||
|
import _6f6c098b from '..\\src\\templates\\layouts\\default.vue'
|
||||||
|
|
||||||
|
const layouts = { "_default": sanitizeComponent(_6f6c098b) }
|
||||||
|
|
||||||
|
export default {
|
||||||
|
render (h, props) {
|
||||||
|
const loadingEl = h('NuxtLoading', { ref: 'loading' })
|
||||||
|
|
||||||
|
const layoutEl = h(this.layout || 'nuxt')
|
||||||
|
const templateEl = h('div', {
|
||||||
|
domProps: {
|
||||||
|
id: '__layout'
|
||||||
|
},
|
||||||
|
key: this.layoutName
|
||||||
|
}, [layoutEl])
|
||||||
|
|
||||||
|
const transitionEl = h('transition', {
|
||||||
|
props: {
|
||||||
|
name: 'layout',
|
||||||
|
mode: 'out-in'
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
beforeEnter (el) {
|
||||||
|
// Ensure to trigger scroll event after calling scrollBehavior
|
||||||
|
window.$nuxt.$nextTick(() => {
|
||||||
|
window.$nuxt.$emit('triggerScroll')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [templateEl])
|
||||||
|
|
||||||
|
return h('div', {
|
||||||
|
domProps: {
|
||||||
|
id: '__nuxt'
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
loadingEl,
|
||||||
|
h(NuxtBuildIndicator),
|
||||||
|
transitionEl
|
||||||
|
])
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
isOnline: true,
|
||||||
|
|
||||||
|
layout: null,
|
||||||
|
layoutName: '',
|
||||||
|
|
||||||
|
nbFetching: 0
|
||||||
|
}),
|
||||||
|
|
||||||
|
beforeCreate () {
|
||||||
|
Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt)
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
// Add this.$nuxt in child instances
|
||||||
|
this.$root.$options.$nuxt = this
|
||||||
|
|
||||||
|
if (process.client) {
|
||||||
|
// add to window so we can listen when ready
|
||||||
|
window.$nuxt = this
|
||||||
|
|
||||||
|
this.refreshOnlineStatus()
|
||||||
|
// Setup the listeners
|
||||||
|
window.addEventListener('online', this.refreshOnlineStatus)
|
||||||
|
window.addEventListener('offline', this.refreshOnlineStatus)
|
||||||
|
}
|
||||||
|
// Add $nuxt.error()
|
||||||
|
this.error = this.nuxt.error
|
||||||
|
// Add $nuxt.context
|
||||||
|
this.context = this.$options.context
|
||||||
|
},
|
||||||
|
|
||||||
|
async mounted () {
|
||||||
|
this.$loading = this.$refs.loading
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
'nuxt.err': 'errorChanged'
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isOffline () {
|
||||||
|
return !this.isOnline
|
||||||
|
},
|
||||||
|
|
||||||
|
isFetching () {
|
||||||
|
return this.nbFetching > 0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
refreshOnlineStatus () {
|
||||||
|
if (process.client) {
|
||||||
|
if (typeof window.navigator.onLine === 'undefined') {
|
||||||
|
// If the browser doesn't support connection status reports
|
||||||
|
// assume that we are online because most apps' only react
|
||||||
|
// when they now that the connection has been interrupted
|
||||||
|
this.isOnline = true
|
||||||
|
} else {
|
||||||
|
this.isOnline = window.navigator.onLine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async refresh () {
|
||||||
|
const pages = getMatchedComponentsInstances(this.$route)
|
||||||
|
|
||||||
|
if (!pages.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$loading.start()
|
||||||
|
|
||||||
|
const promises = pages.map((page) => {
|
||||||
|
const p = []
|
||||||
|
|
||||||
|
// Old fetch
|
||||||
|
if (page.$options.fetch && page.$options.fetch.length) {
|
||||||
|
p.push(promisify(page.$options.fetch, this.context))
|
||||||
|
}
|
||||||
|
if (page.$fetch) {
|
||||||
|
p.push(page.$fetch())
|
||||||
|
} else {
|
||||||
|
// Get all component instance to call $fetch
|
||||||
|
for (const component of getChildrenComponentInstancesUsingFetch(page.$vnode.componentInstance)) {
|
||||||
|
p.push(component.$fetch())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page.$options.asyncData) {
|
||||||
|
p.push(
|
||||||
|
promisify(page.$options.asyncData, this.context)
|
||||||
|
.then((newData) => {
|
||||||
|
for (const key in newData) {
|
||||||
|
Vue.set(page.$data, key, newData[key])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(p)
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
await Promise.all(promises)
|
||||||
|
} catch (error) {
|
||||||
|
this.$loading.fail(error)
|
||||||
|
globalHandleError(error)
|
||||||
|
this.error(error)
|
||||||
|
}
|
||||||
|
this.$loading.finish()
|
||||||
|
},
|
||||||
|
errorChanged () {
|
||||||
|
if (this.nuxt.err) {
|
||||||
|
if (this.$loading) {
|
||||||
|
if (this.$loading.fail) {
|
||||||
|
this.$loading.fail(this.nuxt.err)
|
||||||
|
}
|
||||||
|
if (this.$loading.finish) {
|
||||||
|
this.$loading.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let errorLayout = (NuxtError.options || NuxtError).layout;
|
||||||
|
|
||||||
|
if (typeof errorLayout === 'function') {
|
||||||
|
errorLayout = errorLayout(this.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setLayout(errorLayout)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setLayout (layout) {
|
||||||
|
if(layout && typeof layout !== 'string') {
|
||||||
|
throw new Error('[nuxt] Avoid using non-string value as layout property.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!layout || !layouts['_' + layout]) {
|
||||||
|
layout = 'default'
|
||||||
|
}
|
||||||
|
this.layoutName = layout
|
||||||
|
this.layout = layouts['_' + layout]
|
||||||
|
return this.layout
|
||||||
|
},
|
||||||
|
loadLayout (layout) {
|
||||||
|
if (!layout || !layouts['_' + layout]) {
|
||||||
|
layout = 'default'
|
||||||
|
}
|
||||||
|
return Promise.resolve(layouts['_' + layout])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
NuxtLoading
|
||||||
|
}
|
||||||
|
}
|
||||||
200
build/axios.js
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
import Axios from 'axios'
|
||||||
|
import defu from 'defu'
|
||||||
|
|
||||||
|
// Axios.prototype cannot be modified
|
||||||
|
const axiosExtra = {
|
||||||
|
setBaseURL (baseURL) {
|
||||||
|
this.defaults.baseURL = baseURL
|
||||||
|
},
|
||||||
|
setHeader (name, value, scopes = 'common') {
|
||||||
|
for (const scope of Array.isArray(scopes) ? scopes : [ scopes ]) {
|
||||||
|
if (!value) {
|
||||||
|
delete this.defaults.headers[scope][name];
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.defaults.headers[scope][name] = value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setToken (token, type, scopes = 'common') {
|
||||||
|
const value = !token ? null : (type ? type + ' ' : '') + token
|
||||||
|
this.setHeader('Authorization', value, scopes)
|
||||||
|
},
|
||||||
|
onRequest(fn) {
|
||||||
|
this.interceptors.request.use(config => fn(config) || config)
|
||||||
|
},
|
||||||
|
onResponse(fn) {
|
||||||
|
this.interceptors.response.use(response => fn(response) || response)
|
||||||
|
},
|
||||||
|
onRequestError(fn) {
|
||||||
|
this.interceptors.request.use(undefined, error => fn(error) || Promise.reject(error))
|
||||||
|
},
|
||||||
|
onResponseError(fn) {
|
||||||
|
this.interceptors.response.use(undefined, error => fn(error) || Promise.reject(error))
|
||||||
|
},
|
||||||
|
onError(fn) {
|
||||||
|
this.onRequestError(fn)
|
||||||
|
this.onResponseError(fn)
|
||||||
|
},
|
||||||
|
create(options) {
|
||||||
|
return createAxiosInstance(defu(options, this.defaults))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request helpers ($get, $post, ...)
|
||||||
|
for (const method of ['request', 'delete', 'get', 'head', 'options', 'post', 'put', 'patch']) {
|
||||||
|
axiosExtra['$' + method] = function () { return this[method].apply(this, arguments).then(res => res && res.data) }
|
||||||
|
}
|
||||||
|
|
||||||
|
const extendAxiosInstance = axios => {
|
||||||
|
for (const key in axiosExtra) {
|
||||||
|
axios[key] = axiosExtra[key].bind(axios)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createAxiosInstance = axiosOptions => {
|
||||||
|
// Create new axios instance
|
||||||
|
const axios = Axios.create(axiosOptions)
|
||||||
|
axios.CancelToken = Axios.CancelToken
|
||||||
|
axios.isCancel = Axios.isCancel
|
||||||
|
|
||||||
|
// Extend axios proto
|
||||||
|
extendAxiosInstance(axios)
|
||||||
|
|
||||||
|
// Setup interceptors
|
||||||
|
|
||||||
|
setupCredentialsInterceptor(axios)
|
||||||
|
setupProgress(axios)
|
||||||
|
|
||||||
|
return axios
|
||||||
|
}
|
||||||
|
|
||||||
|
const setupCredentialsInterceptor = axios => {
|
||||||
|
// Send credentials only to relative and API Backend requests
|
||||||
|
axios.onRequest(config => {
|
||||||
|
if (config.withCredentials === undefined) {
|
||||||
|
if (!/^https?:\/\//i.test(config.url) || config.url.indexOf(config.baseURL) === 0) {
|
||||||
|
config.withCredentials = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const setupProgress = (axios) => {
|
||||||
|
if (process.server) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// A noop loading inteterface for when $nuxt is not yet ready
|
||||||
|
const noopLoading = {
|
||||||
|
finish: () => { },
|
||||||
|
start: () => { },
|
||||||
|
fail: () => { },
|
||||||
|
set: () => { }
|
||||||
|
}
|
||||||
|
|
||||||
|
const $loading = () => {
|
||||||
|
const $nuxt = typeof window !== 'undefined' && window['$nuxt']
|
||||||
|
return ($nuxt && $nuxt.$loading && $nuxt.$loading.set) ? $nuxt.$loading : noopLoading
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentRequests = 0
|
||||||
|
|
||||||
|
axios.onRequest(config => {
|
||||||
|
if (config && config.progress === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRequests++
|
||||||
|
})
|
||||||
|
|
||||||
|
axios.onResponse(response => {
|
||||||
|
if (response && response.config && response.config.progress === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRequests--
|
||||||
|
if (currentRequests <= 0) {
|
||||||
|
currentRequests = 0
|
||||||
|
$loading().finish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
axios.onError(error => {
|
||||||
|
if (error && error.config && error.config.progress === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRequests--
|
||||||
|
|
||||||
|
if (Axios.isCancel(error)) {
|
||||||
|
if (currentRequests <= 0) {
|
||||||
|
currentRequests = 0
|
||||||
|
$loading().finish()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$loading().fail()
|
||||||
|
$loading().finish()
|
||||||
|
})
|
||||||
|
|
||||||
|
const onProgress = e => {
|
||||||
|
if (!currentRequests) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const progress = ((e.loaded * 100) / (e.total * currentRequests))
|
||||||
|
$loading().set(Math.min(100, progress))
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.defaults.onUploadProgress = onProgress
|
||||||
|
axios.defaults.onDownloadProgress = onProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (ctx, inject) => {
|
||||||
|
// runtimeConfig
|
||||||
|
const runtimeConfig = ctx.$config && ctx.$config.axios || {}
|
||||||
|
// baseURL
|
||||||
|
const baseURL = process.browser
|
||||||
|
? (runtimeConfig.browserBaseURL || runtimeConfig.baseURL || 'http://localhost:3333/')
|
||||||
|
: (runtimeConfig.baseURL || process.env._AXIOS_BASE_URL_ || 'http://localhost:3333/')
|
||||||
|
|
||||||
|
// Create fresh objects for all default header scopes
|
||||||
|
// Axios creates only one which is shared across SSR requests!
|
||||||
|
// https://github.com/mzabriskie/axios/blob/master/lib/defaults.js
|
||||||
|
const headers = {
|
||||||
|
"common": {
|
||||||
|
"Accept": "application/json, text/plain, */*"
|
||||||
|
},
|
||||||
|
"delete": {},
|
||||||
|
"get": {},
|
||||||
|
"head": {},
|
||||||
|
"post": {},
|
||||||
|
"put": {},
|
||||||
|
"patch": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const axiosOptions = {
|
||||||
|
baseURL,
|
||||||
|
headers
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy SSR request headers headers
|
||||||
|
if (process.server && ctx.req && ctx.req.headers) {
|
||||||
|
const reqHeaders = { ...ctx.req.headers }
|
||||||
|
for (const h of ["accept","host","cf-ray","cf-connecting-ip","content-length","content-md5","content-type"]) {
|
||||||
|
delete reqHeaders[h]
|
||||||
|
}
|
||||||
|
axiosOptions.headers.common = { ...reqHeaders, ...axiosOptions.headers.common }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.server) {
|
||||||
|
// Don't accept brotli encoding because Node can't parse it
|
||||||
|
axiosOptions.headers.common['accept-encoding'] = 'gzip, deflate'
|
||||||
|
}
|
||||||
|
|
||||||
|
const axios = createAxiosInstance(axiosOptions)
|
||||||
|
|
||||||
|
// Inject axios to the context as $axios
|
||||||
|
ctx.$axios = axios
|
||||||
|
inject('axios', axios)
|
||||||
|
}
|
||||||
809
build/client.js
Normal file
@@ -0,0 +1,809 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import fetch from 'unfetch'
|
||||||
|
import middleware from './middleware.js'
|
||||||
|
import {
|
||||||
|
applyAsyncData,
|
||||||
|
promisify,
|
||||||
|
middlewareSeries,
|
||||||
|
sanitizeComponent,
|
||||||
|
resolveRouteComponents,
|
||||||
|
getMatchedComponents,
|
||||||
|
getMatchedComponentsInstances,
|
||||||
|
flatMapComponents,
|
||||||
|
setContext,
|
||||||
|
getLocation,
|
||||||
|
compile,
|
||||||
|
getQueryDiff,
|
||||||
|
globalHandleError,
|
||||||
|
isSamePath
|
||||||
|
} from './utils.js'
|
||||||
|
import { createApp, NuxtError } from './index.js'
|
||||||
|
import fetchMixin from './mixins/fetch.client'
|
||||||
|
import NuxtLink from './components/nuxt-link.client.js' // should be included after ./index.js
|
||||||
|
|
||||||
|
// Fetch mixin
|
||||||
|
if (!Vue.__nuxt__fetch__mixin__) {
|
||||||
|
Vue.mixin(fetchMixin)
|
||||||
|
Vue.__nuxt__fetch__mixin__ = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component: <NuxtLink>
|
||||||
|
Vue.component(NuxtLink.name, NuxtLink)
|
||||||
|
Vue.component('NLink', NuxtLink)
|
||||||
|
|
||||||
|
if (!global.fetch) { global.fetch = fetch }
|
||||||
|
|
||||||
|
// Global shared references
|
||||||
|
let _lastPaths = []
|
||||||
|
let app
|
||||||
|
let router
|
||||||
|
|
||||||
|
// Try to rehydrate SSR data from window
|
||||||
|
const NUXT = window.__NUXT__ || {}
|
||||||
|
|
||||||
|
Object.assign(Vue.config, {"silent":false,"performance":true})
|
||||||
|
|
||||||
|
const logs = NUXT.logs || []
|
||||||
|
if (logs.length > 0) {
|
||||||
|
const ssrLogStyle = 'background: #2E495E;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em;'
|
||||||
|
console.group && console.group ('%cNuxt SSR', ssrLogStyle)
|
||||||
|
logs.forEach(logObj => (console[logObj.type] || console.log)(...logObj.args))
|
||||||
|
delete NUXT.logs
|
||||||
|
console.groupEnd && console.groupEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup global Vue error handler
|
||||||
|
if (!Vue.config.$nuxt) {
|
||||||
|
const defaultErrorHandler = Vue.config.errorHandler
|
||||||
|
Vue.config.errorHandler = async (err, vm, info, ...rest) => {
|
||||||
|
// Call other handler if exist
|
||||||
|
let handled = null
|
||||||
|
if (typeof defaultErrorHandler === 'function') {
|
||||||
|
handled = defaultErrorHandler(err, vm, info, ...rest)
|
||||||
|
}
|
||||||
|
if (handled === true) {
|
||||||
|
return handled
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm && vm.$root) {
|
||||||
|
const nuxtApp = Object.keys(Vue.config.$nuxt)
|
||||||
|
.find(nuxtInstance => vm.$root[nuxtInstance])
|
||||||
|
|
||||||
|
// Show Nuxt Error Page
|
||||||
|
if (nuxtApp && vm.$root[nuxtApp].error && info !== 'render function') {
|
||||||
|
const currentApp = vm.$root[nuxtApp]
|
||||||
|
|
||||||
|
// Load error layout
|
||||||
|
let layout = (NuxtError.options || NuxtError).layout
|
||||||
|
if (typeof layout === 'function') {
|
||||||
|
layout = layout(currentApp.context)
|
||||||
|
}
|
||||||
|
if (layout) {
|
||||||
|
await currentApp.loadLayout(layout).catch(() => {})
|
||||||
|
}
|
||||||
|
currentApp.setLayout(layout)
|
||||||
|
|
||||||
|
currentApp.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof defaultErrorHandler === 'function') {
|
||||||
|
return handled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log to console
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
console.error(err)
|
||||||
|
} else {
|
||||||
|
console.error(err.message || err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vue.config.$nuxt = {}
|
||||||
|
}
|
||||||
|
Vue.config.$nuxt.$nuxt = true
|
||||||
|
|
||||||
|
const errorHandler = Vue.config.errorHandler || console.error
|
||||||
|
|
||||||
|
// Create and mount App
|
||||||
|
createApp(null, NUXT.config).then(mountApp).catch(errorHandler)
|
||||||
|
|
||||||
|
function componentOption (component, key, ...args) {
|
||||||
|
if (!component || !component.options || !component.options[key]) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
const option = component.options[key]
|
||||||
|
if (typeof option === 'function') {
|
||||||
|
return option(...args)
|
||||||
|
}
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapTransitions (toComponents, to, from) {
|
||||||
|
const componentTransitions = (component) => {
|
||||||
|
const transition = componentOption(component, 'transition', to, from) || {}
|
||||||
|
return (typeof transition === 'string' ? { name: transition } : transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromComponents = from ? getMatchedComponents(from) : []
|
||||||
|
const maxDepth = Math.max(toComponents.length, fromComponents.length)
|
||||||
|
|
||||||
|
const mergedTransitions = []
|
||||||
|
for (let i=0; i<maxDepth; i++) {
|
||||||
|
// Clone original objects to prevent overrides
|
||||||
|
const toTransitions = Object.assign({}, componentTransitions(toComponents[i]))
|
||||||
|
const transitions = Object.assign({}, componentTransitions(fromComponents[i]))
|
||||||
|
|
||||||
|
// Combine transitions & prefer `leave` properties of "from" route
|
||||||
|
Object.keys(toTransitions)
|
||||||
|
.filter(key => typeof toTransitions[key] !== 'undefined' && !key.toLowerCase().includes('leave'))
|
||||||
|
.forEach((key) => { transitions[key] = toTransitions[key] })
|
||||||
|
|
||||||
|
mergedTransitions.push(transitions)
|
||||||
|
}
|
||||||
|
return mergedTransitions
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadAsyncComponents (to, from, next) {
|
||||||
|
// Check if route changed (this._routeChanged), only if the page is not an error (for validate())
|
||||||
|
this._routeChanged = Boolean(app.nuxt.err) || from.name !== to.name
|
||||||
|
this._paramChanged = !this._routeChanged && from.path !== to.path
|
||||||
|
this._queryChanged = !this._paramChanged && from.fullPath !== to.fullPath
|
||||||
|
this._diffQuery = (this._queryChanged ? getQueryDiff(to.query, from.query) : [])
|
||||||
|
|
||||||
|
if ((this._routeChanged || this._paramChanged) && this.$loading.start && !this.$loading.manual) {
|
||||||
|
this.$loading.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this._queryChanged) {
|
||||||
|
const Components = await resolveRouteComponents(
|
||||||
|
to,
|
||||||
|
(Component, instance) => ({ Component, instance })
|
||||||
|
)
|
||||||
|
// Add a marker on each component that it needs to refresh or not
|
||||||
|
const startLoader = Components.some(({ Component, instance }) => {
|
||||||
|
const watchQuery = Component.options.watchQuery
|
||||||
|
if (watchQuery === true) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (Array.isArray(watchQuery)) {
|
||||||
|
return watchQuery.some(key => this._diffQuery[key])
|
||||||
|
}
|
||||||
|
if (typeof watchQuery === 'function') {
|
||||||
|
return watchQuery.apply(instance, [to.query, from.query])
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (startLoader && this.$loading.start && !this.$loading.manual) {
|
||||||
|
this.$loading.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Call next()
|
||||||
|
next()
|
||||||
|
} catch (error) {
|
||||||
|
const err = error || {}
|
||||||
|
const statusCode = err.statusCode || err.status || (err.response && err.response.status) || 500
|
||||||
|
const message = err.message || ''
|
||||||
|
|
||||||
|
// Handle chunk loading errors
|
||||||
|
// This may be due to a new deployment or a network problem
|
||||||
|
if (/^Loading( CSS)? chunk (\d)+ failed\./.test(message)) {
|
||||||
|
window.location.reload(true /* skip cache */)
|
||||||
|
return // prevent error page blinking for user
|
||||||
|
}
|
||||||
|
|
||||||
|
this.error({ statusCode, message })
|
||||||
|
this.$nuxt.$emit('routeChanged', to, from, err)
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applySSRData (Component, ssrData) {
|
||||||
|
if (NUXT.serverRendered && ssrData) {
|
||||||
|
applyAsyncData(Component, ssrData)
|
||||||
|
}
|
||||||
|
|
||||||
|
Component._Ctor = Component
|
||||||
|
return Component
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get matched components
|
||||||
|
function resolveComponents (router) {
|
||||||
|
const path = getLocation(router.options.base, router.options.mode)
|
||||||
|
|
||||||
|
return flatMapComponents(router.match(path), async (Component, _, match, key, index) => {
|
||||||
|
// If component is not resolved yet, resolve it
|
||||||
|
if (typeof Component === 'function' && !Component.options) {
|
||||||
|
Component = await Component()
|
||||||
|
}
|
||||||
|
// Sanitize it and save it
|
||||||
|
const _Component = applySSRData(sanitizeComponent(Component), NUXT.data ? NUXT.data[index] : null)
|
||||||
|
match.components[key] = _Component
|
||||||
|
return _Component
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function callMiddleware (Components, context, layout) {
|
||||||
|
let midd = []
|
||||||
|
let unknownMiddleware = false
|
||||||
|
|
||||||
|
// If layout is undefined, only call global middleware
|
||||||
|
if (typeof layout !== 'undefined') {
|
||||||
|
midd = [] // Exclude global middleware if layout defined (already called before)
|
||||||
|
layout = sanitizeComponent(layout)
|
||||||
|
if (layout.options.middleware) {
|
||||||
|
midd = midd.concat(layout.options.middleware)
|
||||||
|
}
|
||||||
|
Components.forEach((Component) => {
|
||||||
|
if (Component.options.middleware) {
|
||||||
|
midd = midd.concat(Component.options.middleware)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
midd = midd.map((name) => {
|
||||||
|
if (typeof name === 'function') {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
if (typeof middleware[name] !== 'function') {
|
||||||
|
unknownMiddleware = true
|
||||||
|
this.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||||
|
}
|
||||||
|
return middleware[name]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (unknownMiddleware) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return middlewareSeries(midd, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function render (to, from, next) {
|
||||||
|
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
// Handle first render on SPA mode
|
||||||
|
let spaFallback = false
|
||||||
|
if (to === from) {
|
||||||
|
_lastPaths = []
|
||||||
|
spaFallback = true
|
||||||
|
} else {
|
||||||
|
const fromMatches = []
|
||||||
|
_lastPaths = getMatchedComponents(from, fromMatches).map((Component, i) => {
|
||||||
|
return compile(from.matched[fromMatches[i]].path)(from.params)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// nextCalled is true when redirected
|
||||||
|
let nextCalled = false
|
||||||
|
const _next = (path) => {
|
||||||
|
if (from.path === path.path && this.$loading.finish) {
|
||||||
|
this.$loading.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from.path !== path.path && this.$loading.pause) {
|
||||||
|
this.$loading.pause()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextCalled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nextCalled = true
|
||||||
|
next(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update context
|
||||||
|
await setContext(app, {
|
||||||
|
route: to,
|
||||||
|
from,
|
||||||
|
next: _next.bind(this)
|
||||||
|
})
|
||||||
|
this._dateLastError = app.nuxt.dateErr
|
||||||
|
this._hadError = Boolean(app.nuxt.err)
|
||||||
|
|
||||||
|
// Get route's matched components
|
||||||
|
const matches = []
|
||||||
|
const Components = getMatchedComponents(to, matches)
|
||||||
|
|
||||||
|
// If no Components matched, generate 404
|
||||||
|
if (!Components.length) {
|
||||||
|
// Default layout
|
||||||
|
await callMiddleware.call(this, Components, app.context)
|
||||||
|
if (nextCalled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load layout for error page
|
||||||
|
const errorLayout = (NuxtError.options || NuxtError).layout
|
||||||
|
const layout = await this.loadLayout(
|
||||||
|
typeof errorLayout === 'function'
|
||||||
|
? errorLayout.call(NuxtError, app.context)
|
||||||
|
: errorLayout
|
||||||
|
)
|
||||||
|
|
||||||
|
await callMiddleware.call(this, Components, app.context, layout)
|
||||||
|
if (nextCalled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show error page
|
||||||
|
app.context.error({ statusCode: 404, message: 'This page could not be found' })
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ._data and other properties if hot reloaded
|
||||||
|
Components.forEach((Component) => {
|
||||||
|
if (Component._Ctor && Component._Ctor.options) {
|
||||||
|
Component.options.asyncData = Component._Ctor.options.asyncData
|
||||||
|
Component.options.fetch = Component._Ctor.options.fetch
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Apply transitions
|
||||||
|
this.setTransitions(mapTransitions(Components, to, from))
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Call middleware
|
||||||
|
await callMiddleware.call(this, Components, app.context)
|
||||||
|
if (nextCalled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (app.context._errored) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set layout
|
||||||
|
let layout = Components[0].options.layout
|
||||||
|
if (typeof layout === 'function') {
|
||||||
|
layout = layout(app.context)
|
||||||
|
}
|
||||||
|
layout = await this.loadLayout(layout)
|
||||||
|
|
||||||
|
// Call middleware for layout
|
||||||
|
await callMiddleware.call(this, Components, app.context, layout)
|
||||||
|
if (nextCalled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (app.context._errored) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call .validate()
|
||||||
|
let isValid = true
|
||||||
|
try {
|
||||||
|
for (const Component of Components) {
|
||||||
|
if (typeof Component.options.validate !== 'function') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid = await Component.options.validate(app.context)
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (validationError) {
|
||||||
|
// ...If .validate() threw an error
|
||||||
|
this.error({
|
||||||
|
statusCode: validationError.statusCode || '500',
|
||||||
|
message: validationError.message
|
||||||
|
})
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...If .validate() returned false
|
||||||
|
if (!isValid) {
|
||||||
|
this.error({ statusCode: 404, message: 'This page could not be found' })
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
let instances
|
||||||
|
// Call asyncData & fetch hooks on components matched by the route.
|
||||||
|
await Promise.all(Components.map(async (Component, i) => {
|
||||||
|
// Check if only children route changed
|
||||||
|
Component._path = compile(to.matched[matches[i]].path)(to.params)
|
||||||
|
Component._dataRefresh = false
|
||||||
|
const childPathChanged = Component._path !== _lastPaths[i]
|
||||||
|
// Refresh component (call asyncData & fetch) when:
|
||||||
|
// Route path changed part includes current component
|
||||||
|
// Or route param changed part includes current component and watchParam is not `false`
|
||||||
|
// Or route query is changed and watchQuery returns `true`
|
||||||
|
if (this._routeChanged && childPathChanged) {
|
||||||
|
Component._dataRefresh = true
|
||||||
|
} else if (this._paramChanged && childPathChanged) {
|
||||||
|
const watchParam = Component.options.watchParam
|
||||||
|
Component._dataRefresh = watchParam !== false
|
||||||
|
} else if (this._queryChanged) {
|
||||||
|
const watchQuery = Component.options.watchQuery
|
||||||
|
if (watchQuery === true) {
|
||||||
|
Component._dataRefresh = true
|
||||||
|
} else if (Array.isArray(watchQuery)) {
|
||||||
|
Component._dataRefresh = watchQuery.some(key => this._diffQuery[key])
|
||||||
|
} else if (typeof watchQuery === 'function') {
|
||||||
|
if (!instances) {
|
||||||
|
instances = getMatchedComponentsInstances(to)
|
||||||
|
}
|
||||||
|
Component._dataRefresh = watchQuery.apply(instances[i], [to.query, from.query])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this._hadError && this._isMounted && !Component._dataRefresh) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const promises = []
|
||||||
|
|
||||||
|
const hasAsyncData = (
|
||||||
|
Component.options.asyncData &&
|
||||||
|
typeof Component.options.asyncData === 'function'
|
||||||
|
)
|
||||||
|
|
||||||
|
const hasFetch = Boolean(Component.options.fetch) && Component.options.fetch.length
|
||||||
|
|
||||||
|
const loadingIncrease = (hasAsyncData && hasFetch) ? 30 : 45
|
||||||
|
|
||||||
|
// Call asyncData(context)
|
||||||
|
if (hasAsyncData) {
|
||||||
|
const promise = promisify(Component.options.asyncData, app.context)
|
||||||
|
|
||||||
|
promise.then((asyncDataResult) => {
|
||||||
|
applyAsyncData(Component, asyncDataResult)
|
||||||
|
|
||||||
|
if (this.$loading.increase) {
|
||||||
|
this.$loading.increase(loadingIncrease)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
promises.push(promise)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check disabled page loading
|
||||||
|
this.$loading.manual = Component.options.loading === false
|
||||||
|
|
||||||
|
// Call fetch(context)
|
||||||
|
if (hasFetch) {
|
||||||
|
let p = Component.options.fetch(app.context)
|
||||||
|
if (!p || (!(p instanceof Promise) && (typeof p.then !== 'function'))) {
|
||||||
|
p = Promise.resolve(p)
|
||||||
|
}
|
||||||
|
p.then((fetchResult) => {
|
||||||
|
if (this.$loading.increase) {
|
||||||
|
this.$loading.increase(loadingIncrease)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
promises.push(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// If not redirected
|
||||||
|
if (!nextCalled) {
|
||||||
|
if (this.$loading.finish && !this.$loading.manual) {
|
||||||
|
this.$loading.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const error = err || {}
|
||||||
|
if (error.message === 'ERR_REDIRECT') {
|
||||||
|
return this.$nuxt.$emit('routeChanged', to, from, error)
|
||||||
|
}
|
||||||
|
_lastPaths = []
|
||||||
|
|
||||||
|
globalHandleError(error)
|
||||||
|
|
||||||
|
// Load error layout
|
||||||
|
let layout = (NuxtError.options || NuxtError).layout
|
||||||
|
if (typeof layout === 'function') {
|
||||||
|
layout = layout(app.context)
|
||||||
|
}
|
||||||
|
await this.loadLayout(layout)
|
||||||
|
|
||||||
|
this.error(error)
|
||||||
|
this.$nuxt.$emit('routeChanged', to, from, error)
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix components format in matched, it's due to code-splitting of vue-router
|
||||||
|
function normalizeComponents (to, ___) {
|
||||||
|
flatMapComponents(to, (Component, _, match, key) => {
|
||||||
|
if (typeof Component === 'object' && !Component.options) {
|
||||||
|
// Updated via vue-router resolveAsyncComponents()
|
||||||
|
Component = Vue.extend(Component)
|
||||||
|
Component._Ctor = Component
|
||||||
|
match.components[key] = Component
|
||||||
|
}
|
||||||
|
return Component
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLayoutForNextPage (to) {
|
||||||
|
// Set layout
|
||||||
|
let hasError = Boolean(this.$options.nuxt.err)
|
||||||
|
if (this._hadError && this._dateLastError === this.$options.nuxt.dateErr) {
|
||||||
|
hasError = false
|
||||||
|
}
|
||||||
|
let layout = hasError
|
||||||
|
? (NuxtError.options || NuxtError).layout
|
||||||
|
: to.matched[0].components.default.options.layout
|
||||||
|
|
||||||
|
if (typeof layout === 'function') {
|
||||||
|
layout = layout(app.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setLayout(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForErrors (app) {
|
||||||
|
// Hide error component if no error
|
||||||
|
if (app._hadError && app._dateLastError === app.$options.nuxt.dateErr) {
|
||||||
|
app.error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When navigating on a different route but the same component is used, Vue.js
|
||||||
|
// Will not update the instance data, so we have to update $data ourselves
|
||||||
|
function fixPrepatch (to, ___) {
|
||||||
|
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const instances = getMatchedComponentsInstances(to)
|
||||||
|
const Components = getMatchedComponents(to)
|
||||||
|
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
instances.forEach((instance, i) => {
|
||||||
|
if (!instance || instance._isDestroyed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
instance.constructor._dataRefresh &&
|
||||||
|
Components[i] === instance.constructor &&
|
||||||
|
instance.$vnode.data.keepAlive !== true &&
|
||||||
|
typeof instance.constructor.options.data === 'function'
|
||||||
|
) {
|
||||||
|
const newData = instance.constructor.options.data.call(instance)
|
||||||
|
for (const key in newData) {
|
||||||
|
Vue.set(instance.$data, key, newData[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure to trigger scroll event after calling scrollBehavior
|
||||||
|
window.$nuxt.$nextTick(() => {
|
||||||
|
window.$nuxt.$emit('triggerScroll')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
checkForErrors(this)
|
||||||
|
|
||||||
|
// Hot reloading
|
||||||
|
setTimeout(() => hotReloadAPI(this), 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function nuxtReady (_app) {
|
||||||
|
window.onNuxtReadyCbs.forEach((cb) => {
|
||||||
|
if (typeof cb === 'function') {
|
||||||
|
cb(_app)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// Special JSDOM
|
||||||
|
if (typeof window._onNuxtLoaded === 'function') {
|
||||||
|
window._onNuxtLoaded(_app)
|
||||||
|
}
|
||||||
|
// Add router hooks
|
||||||
|
router.afterEach((to, from) => {
|
||||||
|
// Wait for fixPrepatch + $data updates
|
||||||
|
Vue.nextTick(() => _app.$nuxt.$emit('routeChanged', to, from))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const noopData = () => { return {} }
|
||||||
|
const noopFetch = () => {}
|
||||||
|
|
||||||
|
// Special hot reload with asyncData(context)
|
||||||
|
function getNuxtChildComponents ($parent, $components = []) {
|
||||||
|
$parent.$children.forEach(($child) => {
|
||||||
|
if ($child.$vnode && $child.$vnode.data.nuxtChild && !$components.find(c =>(c.$options.__file === $child.$options.__file))) {
|
||||||
|
$components.push($child)
|
||||||
|
}
|
||||||
|
if ($child.$children && $child.$children.length) {
|
||||||
|
getNuxtChildComponents($child, $components)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return $components
|
||||||
|
}
|
||||||
|
|
||||||
|
function hotReloadAPI(_app) {
|
||||||
|
if (!module.hot) return
|
||||||
|
|
||||||
|
let $components = getNuxtChildComponents(_app.$nuxt, [])
|
||||||
|
|
||||||
|
$components.forEach(addHotReload.bind(_app))
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHotReload ($component, depth) {
|
||||||
|
if ($component.$vnode.data._hasHotReload) return
|
||||||
|
$component.$vnode.data._hasHotReload = true
|
||||||
|
|
||||||
|
var _forceUpdate = $component.$forceUpdate.bind($component.$parent)
|
||||||
|
|
||||||
|
$component.$vnode.context.$forceUpdate = async () => {
|
||||||
|
let Components = getMatchedComponents(router.currentRoute)
|
||||||
|
let Component = Components[depth]
|
||||||
|
if (!Component) {
|
||||||
|
return _forceUpdate()
|
||||||
|
}
|
||||||
|
if (typeof Component === 'object' && !Component.options) {
|
||||||
|
// Updated via vue-router resolveAsyncComponents()
|
||||||
|
Component = Vue.extend(Component)
|
||||||
|
Component._Ctor = Component
|
||||||
|
}
|
||||||
|
this.error()
|
||||||
|
let promises = []
|
||||||
|
const next = function (path) {
|
||||||
|
this.$loading.finish && this.$loading.finish()
|
||||||
|
router.push(path)
|
||||||
|
}
|
||||||
|
await setContext(app, {
|
||||||
|
route: router.currentRoute,
|
||||||
|
isHMR: true,
|
||||||
|
next: next.bind(this)
|
||||||
|
})
|
||||||
|
const context = app.context
|
||||||
|
|
||||||
|
if (this.$loading.start && !this.$loading.manual) {
|
||||||
|
this.$loading.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
callMiddleware.call(this, Components, context)
|
||||||
|
.then(() => {
|
||||||
|
// If layout changed
|
||||||
|
if (depth !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout = Component.options.layout || 'default'
|
||||||
|
if (typeof layout === 'function') {
|
||||||
|
layout = layout(context)
|
||||||
|
}
|
||||||
|
if (this.layoutName === layout) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let promise = this.loadLayout(layout)
|
||||||
|
promise.then(() => {
|
||||||
|
this.setLayout(layout)
|
||||||
|
Vue.nextTick(() => hotReloadAPI(this))
|
||||||
|
})
|
||||||
|
return promise
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(() => {
|
||||||
|
return callMiddleware.call(this, Components, context, this.layout)
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(() => {
|
||||||
|
// Call asyncData(context)
|
||||||
|
let pAsyncData = promisify(Component.options.asyncData || noopData, context)
|
||||||
|
pAsyncData.then((asyncDataResult) => {
|
||||||
|
applyAsyncData(Component, asyncDataResult)
|
||||||
|
this.$loading.increase && this.$loading.increase(30)
|
||||||
|
})
|
||||||
|
promises.push(pAsyncData)
|
||||||
|
|
||||||
|
// Call fetch()
|
||||||
|
Component.options.fetch = Component.options.fetch || noopFetch
|
||||||
|
let pFetch = Component.options.fetch.length && Component.options.fetch(context)
|
||||||
|
if (!pFetch || (!(pFetch instanceof Promise) && (typeof pFetch.then !== 'function'))) { pFetch = Promise.resolve(pFetch) }
|
||||||
|
pFetch.then(() => this.$loading.increase && this.$loading.increase(30))
|
||||||
|
promises.push(pFetch)
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$loading.finish && this.$loading.finish()
|
||||||
|
_forceUpdate()
|
||||||
|
setTimeout(() => hotReloadAPI(this), 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mountApp (__app) {
|
||||||
|
// Set global variables
|
||||||
|
app = __app.app
|
||||||
|
router = __app.router
|
||||||
|
|
||||||
|
// Create Vue instance
|
||||||
|
const _app = new Vue(app)
|
||||||
|
|
||||||
|
// Load layout
|
||||||
|
const layout = NUXT.layout || 'default'
|
||||||
|
await _app.loadLayout(layout)
|
||||||
|
_app.setLayout(layout)
|
||||||
|
|
||||||
|
// Mounts Vue app to DOM element
|
||||||
|
const mount = () => {
|
||||||
|
_app.$mount('#__nuxt')
|
||||||
|
|
||||||
|
// Add afterEach router hooks
|
||||||
|
router.afterEach(normalizeComponents)
|
||||||
|
|
||||||
|
router.afterEach(setLayoutForNextPage.bind(_app))
|
||||||
|
|
||||||
|
router.afterEach(fixPrepatch.bind(_app))
|
||||||
|
|
||||||
|
// Listen for first Vue update
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
// Call window.{{globals.readyCallback}} callbacks
|
||||||
|
nuxtReady(_app)
|
||||||
|
|
||||||
|
// Enable hot reloading
|
||||||
|
hotReloadAPI(_app)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve route components
|
||||||
|
const Components = await Promise.all(resolveComponents(router))
|
||||||
|
|
||||||
|
// Enable transitions
|
||||||
|
_app.setTransitions = _app.$options.nuxt.setTransitions.bind(_app)
|
||||||
|
if (Components.length) {
|
||||||
|
_app.setTransitions(mapTransitions(Components, router.currentRoute))
|
||||||
|
_lastPaths = router.currentRoute.matched.map(route => compile(route.path)(router.currentRoute.params))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize error handler
|
||||||
|
_app.$loading = {} // To avoid error while _app.$nuxt does not exist
|
||||||
|
if (NUXT.error) {
|
||||||
|
_app.error(NUXT.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add beforeEach router hooks
|
||||||
|
router.beforeEach(loadAsyncComponents.bind(_app))
|
||||||
|
router.beforeEach(render.bind(_app))
|
||||||
|
|
||||||
|
// Fix in static: remove trailing slash to force hydration
|
||||||
|
// Full static, if server-rendered: hydrate, to allow custom redirect to generated page
|
||||||
|
|
||||||
|
// Fix in static: remove trailing slash to force hydration
|
||||||
|
if (NUXT.serverRendered && isSamePath(NUXT.routePath, _app.context.route.path)) {
|
||||||
|
return mount()
|
||||||
|
}
|
||||||
|
|
||||||
|
// First render on client-side
|
||||||
|
const clientFirstMount = () => {
|
||||||
|
normalizeComponents(router.currentRoute, router.currentRoute)
|
||||||
|
setLayoutForNextPage.call(_app, router.currentRoute)
|
||||||
|
checkForErrors(_app)
|
||||||
|
// Don't call fixPrepatch.call(_app, router.currentRoute, router.currentRoute) since it's first render
|
||||||
|
mount()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix: force next tick to avoid having same timestamp when an error happen on spa fallback
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 0))
|
||||||
|
render.call(_app, router.currentRoute, router.currentRoute, (path) => {
|
||||||
|
// If not redirected
|
||||||
|
if (!path) {
|
||||||
|
clientFirstMount()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a one-time afterEach hook to
|
||||||
|
// mount the app wait for redirect and route gets resolved
|
||||||
|
const unregisterHook = router.afterEach((to, from) => {
|
||||||
|
unregisterHook()
|
||||||
|
clientFirstMount()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Push the path and let route to be resolved
|
||||||
|
router.push(path, undefined, (err) => {
|
||||||
|
if (err) {
|
||||||
|
errorHandler(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
9
build/components/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export { default as Footer } from '../..\\src\\components\\Footer.vue'
|
||||||
|
export { default as GoToTop } from '../..\\src\\components\\GoToTop.vue'
|
||||||
|
export { default as Header } from '../..\\src\\components\\Header.vue'
|
||||||
|
export { default as LangSwitcher } from '../..\\src\\components\\LangSwitcher.vue'
|
||||||
|
|
||||||
|
export const LazyFooter = import('../..\\src\\components\\Footer.vue' /* webpackChunkName: "components_Footer" */).then(c => c.default || c)
|
||||||
|
export const LazyGoToTop = import('../..\\src\\components\\GoToTop.vue' /* webpackChunkName: "components_GoToTop" */).then(c => c.default || c)
|
||||||
|
export const LazyHeader = import('../..\\src\\components\\Header.vue' /* webpackChunkName: "components_Header" */).then(c => c.default || c)
|
||||||
|
export const LazyLangSwitcher = import('../..\\src\\components\\LangSwitcher.vue' /* webpackChunkName: "components_LangSwitcher" */).then(c => c.default || c)
|
||||||
143
build/components/nuxt-build-indicator.vue
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<transition appear>
|
||||||
|
<div v-if="building" class="nuxt__build_indicator" :style="indicatorStyle">
|
||||||
|
<svg viewBox="0 0 96 72" version="1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M6 66h23l1-3 21-37L40 6 6 66zM79 66h11L62 17l-5 9 22 37v3zM54 31L35 66h38z" />
|
||||||
|
<path d="M29 69v-1-2H6L40 6l11 20 3-6L44 3s-2-3-4-3-3 1-5 3L1 63c0 1-2 3 0 6 0 1 2 2 5 2h28c-3 0-4-1-5-2z" fill="#00C58E" />
|
||||||
|
<path d="M95 63L67 14c0-1-2-3-5-3-1 0-3 0-4 3l-4 6 3 6 5-9 28 49H79a5 5 0 0 1 0 3c-2 2-5 2-5 2h16c1 0 4 0 5-2 1-1 2-3 0-6z" fill="#00C58E" />
|
||||||
|
<path d="M79 69v-1-2-3L57 26l-3-6-3 6-21 37-1 3a5 5 0 0 0 0 3c1 1 2 2 5 2h40s3 0 5-2zM54 31l19 35H35l19-35z" fill="#FFF" fill-rule="nonzero" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
{{ animatedProgress }}%
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'NuxtBuildIndicator',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
building: false,
|
||||||
|
progress: 0,
|
||||||
|
animatedProgress: 0,
|
||||||
|
reconnectAttempts: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
options: () => ({"position":"bottom-right","backgroundColor":"#2E495E","color":"#00C48D"}),
|
||||||
|
indicatorStyle () {
|
||||||
|
const [d1, d2] = this.options.position.split('-')
|
||||||
|
return {
|
||||||
|
[d1]: '20px',
|
||||||
|
[d2]: '20px',
|
||||||
|
'background-color': this.options.backgroundColor,
|
||||||
|
color: this.options.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
progress (val, oldVal) {
|
||||||
|
// Average progress may decrease but ignore it!
|
||||||
|
if (val < oldVal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Cancel old animation
|
||||||
|
clearInterval(this._progressAnimation)
|
||||||
|
// Jump to edge immediately
|
||||||
|
if (val < 10 || val > 90) {
|
||||||
|
this.animatedProgress = val
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Animate to value
|
||||||
|
this._progressAnimation = setInterval(() => {
|
||||||
|
const diff = this.progress - this.animatedProgress
|
||||||
|
if (diff > 0) {
|
||||||
|
this.animatedProgress++
|
||||||
|
} else {
|
||||||
|
clearInterval(this._progressAnimation)
|
||||||
|
}
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if (EventSource === undefined) {
|
||||||
|
return // Unsupported
|
||||||
|
}
|
||||||
|
this.sseConnect()
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this.sseClose()
|
||||||
|
clearInterval(this._progressAnimation)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
sseConnect () {
|
||||||
|
if (this._connecting) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._connecting = true
|
||||||
|
this.sse = new EventSource('/_loading/sse')
|
||||||
|
this.sse.addEventListener('message', event => this.onSseMessage(event))
|
||||||
|
},
|
||||||
|
onSseMessage (message) {
|
||||||
|
const data = JSON.parse(message.data)
|
||||||
|
if (!data.states) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.progress = Math.round(data.states.reduce((p, s) => p + s.progress, 0) / data.states.length)
|
||||||
|
|
||||||
|
if (!data.allDone) {
|
||||||
|
this.building = true
|
||||||
|
} else {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.building = false
|
||||||
|
this.animatedProgress = 0
|
||||||
|
this.progress = 0
|
||||||
|
clearInterval(this._progressAnimation)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
sseClose () {
|
||||||
|
if (this.sse) {
|
||||||
|
this.sse.close()
|
||||||
|
delete this.sse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.nuxt__build_indicator {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: fixed;
|
||||||
|
font-family: monospace;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 1px 1px 2px 0px rgba(0,0,0,0.2);
|
||||||
|
width: 88px;
|
||||||
|
z-index: 2147483647;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.2rem;
|
||||||
|
}
|
||||||
|
.v-enter-active, .v-leave-active {
|
||||||
|
transition-delay: 0.2s;
|
||||||
|
transition-property: all;
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
}
|
||||||
|
.v-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: baseline;
|
||||||
|
width: 1.1em;
|
||||||
|
height: 0.825em;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
122
build/components/nuxt-child.js
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NuxtChild',
|
||||||
|
functional: true,
|
||||||
|
props: {
|
||||||
|
nuxtChildKey: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
keepAlive: Boolean,
|
||||||
|
keepAliveProps: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render (_, { parent, data, props }) {
|
||||||
|
const h = parent.$createElement
|
||||||
|
|
||||||
|
data.nuxtChild = true
|
||||||
|
const _parent = parent
|
||||||
|
const transitions = parent.$nuxt.nuxt.transitions
|
||||||
|
const defaultTransition = parent.$nuxt.nuxt.defaultTransition
|
||||||
|
|
||||||
|
let depth = 0
|
||||||
|
while (parent) {
|
||||||
|
if (parent.$vnode && parent.$vnode.data.nuxtChild) {
|
||||||
|
depth++
|
||||||
|
}
|
||||||
|
parent = parent.$parent
|
||||||
|
}
|
||||||
|
data.nuxtChildDepth = depth
|
||||||
|
const transition = transitions[depth] || defaultTransition
|
||||||
|
const transitionProps = {}
|
||||||
|
transitionsKeys.forEach((key) => {
|
||||||
|
if (typeof transition[key] !== 'undefined') {
|
||||||
|
transitionProps[key] = transition[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const listeners = {}
|
||||||
|
listenersKeys.forEach((key) => {
|
||||||
|
if (typeof transition[key] === 'function') {
|
||||||
|
listeners[key] = transition[key].bind(_parent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (process.client) {
|
||||||
|
// Add triggerScroll event on beforeEnter (fix #1376)
|
||||||
|
const beforeEnter = listeners.beforeEnter
|
||||||
|
listeners.beforeEnter = (el) => {
|
||||||
|
// Ensure to trigger scroll event after calling scrollBehavior
|
||||||
|
window.$nuxt.$nextTick(() => {
|
||||||
|
window.$nuxt.$emit('triggerScroll')
|
||||||
|
})
|
||||||
|
if (beforeEnter) {
|
||||||
|
return beforeEnter.call(_parent, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure that leave is called asynchronous (fix #5703)
|
||||||
|
if (transition.css === false) {
|
||||||
|
const leave = listeners.leave
|
||||||
|
|
||||||
|
// only add leave listener when user didnt provide one
|
||||||
|
// or when it misses the done argument
|
||||||
|
if (!leave || leave.length < 2) {
|
||||||
|
listeners.leave = (el, done) => {
|
||||||
|
if (leave) {
|
||||||
|
leave.call(_parent, el)
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent.$nextTick(done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let routerView = h('routerView', data)
|
||||||
|
|
||||||
|
if (props.keepAlive) {
|
||||||
|
routerView = h('keep-alive', { props: props.keepAliveProps }, [routerView])
|
||||||
|
}
|
||||||
|
|
||||||
|
return h('transition', {
|
||||||
|
props: transitionProps,
|
||||||
|
on: listeners
|
||||||
|
}, [routerView])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const transitionsKeys = [
|
||||||
|
'name',
|
||||||
|
'mode',
|
||||||
|
'appear',
|
||||||
|
'css',
|
||||||
|
'type',
|
||||||
|
'duration',
|
||||||
|
'enterClass',
|
||||||
|
'leaveClass',
|
||||||
|
'appearClass',
|
||||||
|
'enterActiveClass',
|
||||||
|
'enterActiveClass',
|
||||||
|
'leaveActiveClass',
|
||||||
|
'appearActiveClass',
|
||||||
|
'enterToClass',
|
||||||
|
'leaveToClass',
|
||||||
|
'appearToClass'
|
||||||
|
]
|
||||||
|
|
||||||
|
const listenersKeys = [
|
||||||
|
'beforeEnter',
|
||||||
|
'enter',
|
||||||
|
'afterEnter',
|
||||||
|
'enterCancelled',
|
||||||
|
'beforeLeave',
|
||||||
|
'leave',
|
||||||
|
'afterLeave',
|
||||||
|
'leaveCancelled',
|
||||||
|
'beforeAppear',
|
||||||
|
'appear',
|
||||||
|
'afterAppear',
|
||||||
|
'appearCancelled'
|
||||||
|
]
|
||||||
98
build/components/nuxt-error.vue
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<div class="__nuxt-error-page">
|
||||||
|
<div class="error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48">
|
||||||
|
<path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="title">{{ message }}</div>
|
||||||
|
<p v-if="statusCode === 404" class="description">
|
||||||
|
<a v-if="typeof $route === 'undefined'" class="error-link" href="/"></a>
|
||||||
|
<NuxtLink v-else class="error-link" to="/">Back to the home page</NuxtLink>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="description" v-else>An error occurred while rendering the page. Check developer tools console for details.</p>
|
||||||
|
|
||||||
|
<div class="logo">
|
||||||
|
<a href="https://nuxtjs.org" target="_blank" rel="noopener">Nuxt.js</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'NuxtError',
|
||||||
|
props: {
|
||||||
|
error: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
statusCode () {
|
||||||
|
return (this.error && this.error.statusCode) || 500
|
||||||
|
},
|
||||||
|
message () {
|
||||||
|
return this.error.message || 'Error'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
head () {
|
||||||
|
return {
|
||||||
|
title: this.message,
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
name: 'viewport',
|
||||||
|
content: 'width=device-width,initial-scale=1.0,minimum-scale=1.0'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.__nuxt-error-page {
|
||||||
|
padding: 1rem;
|
||||||
|
background: #F7F8FB;
|
||||||
|
color: #47494E;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: 100 !important;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.__nuxt-error-page .error {
|
||||||
|
max-width: 450px;
|
||||||
|
}
|
||||||
|
.__nuxt-error-page .title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-top: 15px;
|
||||||
|
color: #47494E;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.__nuxt-error-page .description {
|
||||||
|
color: #7F828B;
|
||||||
|
line-height: 21px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.__nuxt-error-page a {
|
||||||
|
color: #7F828B !important;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.__nuxt-error-page .logo {
|
||||||
|
position: fixed;
|
||||||
|
left: 12px;
|
||||||
|
bottom: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
98
build/components/nuxt-link.client.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
const requestIdleCallback = window.requestIdleCallback ||
|
||||||
|
function (cb) {
|
||||||
|
const start = Date.now()
|
||||||
|
return setTimeout(function () {
|
||||||
|
cb({
|
||||||
|
didTimeout: false,
|
||||||
|
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
|
||||||
|
})
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelIdleCallback = window.cancelIdleCallback || function (id) {
|
||||||
|
clearTimeout(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const observer = window.IntersectionObserver && new window.IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(({ intersectionRatio, target: link }) => {
|
||||||
|
if (intersectionRatio <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
link.__prefetch()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NuxtLink',
|
||||||
|
extends: Vue.component('RouterLink'),
|
||||||
|
props: {
|
||||||
|
prefetch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
noPrefetch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if (this.prefetch && !this.noPrefetch) {
|
||||||
|
this.handleId = requestIdleCallback(this.observe, { timeout: 2e3 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
cancelIdleCallback(this.handleId)
|
||||||
|
|
||||||
|
if (this.__observed) {
|
||||||
|
observer.unobserve(this.$el)
|
||||||
|
delete this.$el.__prefetch
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
observe () {
|
||||||
|
// If no IntersectionObserver, avoid prefetching
|
||||||
|
if (!observer) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Add to observer
|
||||||
|
if (this.shouldPrefetch()) {
|
||||||
|
this.$el.__prefetch = this.prefetchLink.bind(this)
|
||||||
|
observer.observe(this.$el)
|
||||||
|
this.__observed = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shouldPrefetch () {
|
||||||
|
return this.getPrefetchComponents().length > 0
|
||||||
|
},
|
||||||
|
canPrefetch () {
|
||||||
|
const conn = navigator.connection
|
||||||
|
const hasBadConnection = this.$nuxt.isOffline || (conn && ((conn.effectiveType || '').includes('2g') || conn.saveData))
|
||||||
|
|
||||||
|
return !hasBadConnection
|
||||||
|
},
|
||||||
|
getPrefetchComponents () {
|
||||||
|
const ref = this.$router.resolve(this.to, this.$route, this.append)
|
||||||
|
const Components = ref.resolved.matched.map(r => r.components.default)
|
||||||
|
|
||||||
|
return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched)
|
||||||
|
},
|
||||||
|
prefetchLink () {
|
||||||
|
if (!this.canPrefetch()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Stop observing this link (in case of internet connection changes)
|
||||||
|
observer.unobserve(this.$el)
|
||||||
|
const Components = this.getPrefetchComponents()
|
||||||
|
|
||||||
|
for (const Component of Components) {
|
||||||
|
const componentOrPromise = Component()
|
||||||
|
if (componentOrPromise instanceof Promise) {
|
||||||
|
componentOrPromise.catch(() => {})
|
||||||
|
}
|
||||||
|
Component.__prefetched = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
build/components/nuxt-link.server.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NuxtLink',
|
||||||
|
extends: Vue.component('RouterLink'),
|
||||||
|
props: {
|
||||||
|
prefetch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
noPrefetch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
177
build/components/nuxt-loading.vue
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'NuxtLoading',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
percent: 0,
|
||||||
|
show: false,
|
||||||
|
canSucceed: true,
|
||||||
|
reversed: false,
|
||||||
|
skipTimerCount: 0,
|
||||||
|
rtl: false,
|
||||||
|
throttle: 200,
|
||||||
|
duration: 5000,
|
||||||
|
continuous: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
left () {
|
||||||
|
if (!this.continuous && !this.rtl) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return this.rtl
|
||||||
|
? (this.reversed ? '0px' : 'auto')
|
||||||
|
: (!this.reversed ? '0px' : 'auto')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this.clear()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clear () {
|
||||||
|
clearInterval(this._timer)
|
||||||
|
clearTimeout(this._throttle)
|
||||||
|
this._timer = null
|
||||||
|
},
|
||||||
|
start () {
|
||||||
|
this.clear()
|
||||||
|
this.percent = 0
|
||||||
|
this.reversed = false
|
||||||
|
this.skipTimerCount = 0
|
||||||
|
this.canSucceed = true
|
||||||
|
|
||||||
|
if (this.throttle) {
|
||||||
|
this._throttle = setTimeout(() => this.startTimer(), this.throttle)
|
||||||
|
} else {
|
||||||
|
this.startTimer()
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
set (num) {
|
||||||
|
this.show = true
|
||||||
|
this.canSucceed = true
|
||||||
|
this.percent = Math.min(100, Math.max(0, Math.floor(num)))
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
get () {
|
||||||
|
return this.percent
|
||||||
|
},
|
||||||
|
increase (num) {
|
||||||
|
this.percent = Math.min(100, Math.floor(this.percent + num))
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
decrease (num) {
|
||||||
|
this.percent = Math.max(0, Math.floor(this.percent - num))
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
pause () {
|
||||||
|
clearInterval(this._timer)
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
resume () {
|
||||||
|
this.startTimer()
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
finish () {
|
||||||
|
this.percent = this.reversed ? 0 : 100
|
||||||
|
this.hide()
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
hide () {
|
||||||
|
this.clear()
|
||||||
|
setTimeout(() => {
|
||||||
|
this.show = false
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.percent = 0
|
||||||
|
this.reversed = false
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
fail (error) {
|
||||||
|
this.canSucceed = false
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
startTimer () {
|
||||||
|
if (!this.show) {
|
||||||
|
this.show = true
|
||||||
|
}
|
||||||
|
if (typeof this._cut === 'undefined') {
|
||||||
|
this._cut = 10000 / Math.floor(this.duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
this._timer = setInterval(() => {
|
||||||
|
/**
|
||||||
|
* When reversing direction skip one timers
|
||||||
|
* so 0, 100 are displayed for two iterations
|
||||||
|
* also disable css width transitioning
|
||||||
|
* which otherwise interferes and shows
|
||||||
|
* a jojo effect
|
||||||
|
*/
|
||||||
|
if (this.skipTimerCount > 0) {
|
||||||
|
this.skipTimerCount--
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.reversed) {
|
||||||
|
this.decrease(this._cut)
|
||||||
|
} else {
|
||||||
|
this.increase(this._cut)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.continuous) {
|
||||||
|
if (this.percent >= 100) {
|
||||||
|
this.skipTimerCount = 1
|
||||||
|
|
||||||
|
this.reversed = !this.reversed
|
||||||
|
} else if (this.percent <= 0) {
|
||||||
|
this.skipTimerCount = 1
|
||||||
|
|
||||||
|
this.reversed = !this.reversed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render (h) {
|
||||||
|
let el = h(false)
|
||||||
|
if (this.show) {
|
||||||
|
el = h('div', {
|
||||||
|
staticClass: 'nuxt-progress',
|
||||||
|
class: {
|
||||||
|
'nuxt-progress-notransition': this.skipTimerCount > 0,
|
||||||
|
'nuxt-progress-failed': !this.canSucceed
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
width: this.percent + '%',
|
||||||
|
left: this.left
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.nuxt-progress {
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
height: 2px;
|
||||||
|
width: 0%;
|
||||||
|
opacity: 1;
|
||||||
|
transition: width 0.1s, opacity 0.4s;
|
||||||
|
background-color: black;
|
||||||
|
z-index: 999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nuxt-progress.nuxt-progress-notransition {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nuxt-progress-failed {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
101
build/components/nuxt.js
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import { compile } from '../utils'
|
||||||
|
|
||||||
|
import NuxtError from '../..\\src\\templates\\layouts\\error.vue'
|
||||||
|
|
||||||
|
import NuxtChild from './nuxt-child'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Nuxt',
|
||||||
|
components: {
|
||||||
|
NuxtChild,
|
||||||
|
NuxtError
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
nuxtChildKey: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
keepAlive: Boolean,
|
||||||
|
keepAliveProps: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: 'default'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorCaptured (error) {
|
||||||
|
// if we receive and error while showing the NuxtError component
|
||||||
|
// capture the error and force an immediate update so we re-render
|
||||||
|
// without the NuxtError component
|
||||||
|
if (this.displayingNuxtError) {
|
||||||
|
this.errorFromNuxtError = error
|
||||||
|
this.$forceUpdate()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
routerViewKey () {
|
||||||
|
// If nuxtChildKey prop is given or current route has children
|
||||||
|
if (typeof this.nuxtChildKey !== 'undefined' || this.$route.matched.length > 1) {
|
||||||
|
return this.nuxtChildKey || compile(this.$route.matched[0].path)(this.$route.params)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [matchedRoute] = this.$route.matched
|
||||||
|
|
||||||
|
if (!matchedRoute) {
|
||||||
|
return this.$route.path
|
||||||
|
}
|
||||||
|
|
||||||
|
const Component = matchedRoute.components.default
|
||||||
|
|
||||||
|
if (Component && Component.options) {
|
||||||
|
const { options } = Component
|
||||||
|
|
||||||
|
if (options.key) {
|
||||||
|
return (typeof options.key === 'function' ? options.key(this.$route) : options.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const strict = /\/$/.test(matchedRoute.path)
|
||||||
|
return strict ? this.$route.path : this.$route.path.replace(/\/$/, '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeCreate () {
|
||||||
|
Vue.util.defineReactive(this, 'nuxt', this.$root.$options.nuxt)
|
||||||
|
},
|
||||||
|
render (h) {
|
||||||
|
// if there is no error
|
||||||
|
if (!this.nuxt.err) {
|
||||||
|
// Directly return nuxt child
|
||||||
|
return h('NuxtChild', {
|
||||||
|
key: this.routerViewKey,
|
||||||
|
props: this.$props
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// if an error occurred within NuxtError show a simple
|
||||||
|
// error message instead to prevent looping
|
||||||
|
if (this.errorFromNuxtError) {
|
||||||
|
this.$nextTick(() => (this.errorFromNuxtError = false))
|
||||||
|
|
||||||
|
return h('div', {}, [
|
||||||
|
h('h2', 'An error occurred while showing the error page'),
|
||||||
|
h('p', 'Unfortunately an error occurred and while showing the error page another error occurred'),
|
||||||
|
h('p', `Error details: ${this.errorFromNuxtError.toString()}`),
|
||||||
|
h('nuxt-link', { props: { to: '/' } }, 'Go back to home')
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
// track if we are showing the NuxtError component
|
||||||
|
this.displayingNuxtError = true
|
||||||
|
this.$nextTick(() => (this.displayingNuxtError = false))
|
||||||
|
|
||||||
|
return h(NuxtError, {
|
||||||
|
props: {
|
||||||
|
error: this.nuxt.err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
8
build/components/plugin.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
const globalComponents = {
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const name in globalComponents) {
|
||||||
|
Vue.component(name, globalComponents[name])
|
||||||
|
}
|
||||||
1
build/empty.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// This file is intentionally left empty for noop aliases
|
||||||
218
build/index.js
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
import Meta from 'vue-meta'
|
||||||
|
import ClientOnly from 'vue-client-only'
|
||||||
|
import NoSsr from 'vue-no-ssr'
|
||||||
|
import { createRouter } from './router.js'
|
||||||
|
import NuxtChild from './components/nuxt-child.js'
|
||||||
|
import NuxtError from '..\\src\\templates\\layouts\\error.vue'
|
||||||
|
import Nuxt from './components/nuxt.js'
|
||||||
|
import App from './App.js'
|
||||||
|
import { setContext, getLocation, getRouteData, normalizeError } from './utils'
|
||||||
|
|
||||||
|
/* Plugins */
|
||||||
|
|
||||||
|
import nuxt_plugin_plugin_030ac950 from 'nuxt_plugin_plugin_030ac950' // Source: .\\components\\plugin.js (mode: 'all')
|
||||||
|
import nuxt_plugin_axios_63fe537b from 'nuxt_plugin_axios_63fe537b' // Source: .\\axios.js (mode: 'all')
|
||||||
|
|
||||||
|
// Component: <ClientOnly>
|
||||||
|
Vue.component(ClientOnly.name, ClientOnly)
|
||||||
|
|
||||||
|
// TODO: Remove in Nuxt 3: <NoSsr>
|
||||||
|
Vue.component(NoSsr.name, {
|
||||||
|
...NoSsr,
|
||||||
|
render (h, ctx) {
|
||||||
|
if (process.client && !NoSsr._warned) {
|
||||||
|
NoSsr._warned = true
|
||||||
|
|
||||||
|
console.warn('<no-ssr> has been deprecated and will be removed in Nuxt 3, please use <client-only> instead')
|
||||||
|
}
|
||||||
|
return NoSsr.render(h, ctx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Component: <NuxtChild>
|
||||||
|
Vue.component(NuxtChild.name, NuxtChild)
|
||||||
|
Vue.component('NChild', NuxtChild)
|
||||||
|
|
||||||
|
// Component NuxtLink is imported in server.js or client.js
|
||||||
|
|
||||||
|
// Component: <Nuxt>
|
||||||
|
Vue.component(Nuxt.name, Nuxt)
|
||||||
|
|
||||||
|
Object.defineProperty(Vue.prototype, '$nuxt', {
|
||||||
|
get() {
|
||||||
|
return this.$root.$options.$nuxt
|
||||||
|
},
|
||||||
|
configurable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
Vue.use(Meta, {"keyName":"head","attribute":"data-n-head","ssrAttribute":"data-n-head-ssr","tagIDKeyName":"hid"})
|
||||||
|
|
||||||
|
const defaultTransition = {"name":"page","mode":"out-in","appear":false,"appearClass":"appear","appearActiveClass":"appear-active","appearToClass":"appear-to"}
|
||||||
|
|
||||||
|
async function createApp(ssrContext, config = {}) {
|
||||||
|
const router = await createRouter(ssrContext)
|
||||||
|
|
||||||
|
// Create Root instance
|
||||||
|
|
||||||
|
// here we inject the router and store to all child components,
|
||||||
|
// making them available everywhere as `this.$router` and `this.$store`.
|
||||||
|
const app = {
|
||||||
|
head: {"title":"artsite","meta":[{"charset":"utf-8"},{"name":"viewport","content":"width=device-width, initial-scale=1"},{"hid":"description","name":"description","content":""}],"link":[{"rel":"icon","type":"image\u002Fx-icon","href":"\u002Ffavicon.ico"}],"style":[],"script":[]},
|
||||||
|
|
||||||
|
router,
|
||||||
|
nuxt: {
|
||||||
|
defaultTransition,
|
||||||
|
transitions: [defaultTransition],
|
||||||
|
setTransitions (transitions) {
|
||||||
|
if (!Array.isArray(transitions)) {
|
||||||
|
transitions = [transitions]
|
||||||
|
}
|
||||||
|
transitions = transitions.map((transition) => {
|
||||||
|
if (!transition) {
|
||||||
|
transition = defaultTransition
|
||||||
|
} else if (typeof transition === 'string') {
|
||||||
|
transition = Object.assign({}, defaultTransition, { name: transition })
|
||||||
|
} else {
|
||||||
|
transition = Object.assign({}, defaultTransition, transition)
|
||||||
|
}
|
||||||
|
return transition
|
||||||
|
})
|
||||||
|
this.$options.nuxt.transitions = transitions
|
||||||
|
return transitions
|
||||||
|
},
|
||||||
|
|
||||||
|
err: null,
|
||||||
|
dateErr: null,
|
||||||
|
error (err) {
|
||||||
|
err = err || null
|
||||||
|
app.context._errored = Boolean(err)
|
||||||
|
err = err ? normalizeError(err) : null
|
||||||
|
let nuxt = app.nuxt // to work with @vue/composition-api, see https://github.com/nuxt/nuxt.js/issues/6517#issuecomment-573280207
|
||||||
|
if (this) {
|
||||||
|
nuxt = this.nuxt || this.$options.nuxt
|
||||||
|
}
|
||||||
|
nuxt.dateErr = Date.now()
|
||||||
|
nuxt.err = err
|
||||||
|
// Used in src/server.js
|
||||||
|
if (ssrContext) {
|
||||||
|
ssrContext.nuxt.error = err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...App
|
||||||
|
}
|
||||||
|
|
||||||
|
const next = ssrContext ? ssrContext.next : location => app.router.push(location)
|
||||||
|
// Resolve route
|
||||||
|
let route
|
||||||
|
if (ssrContext) {
|
||||||
|
route = router.resolve(ssrContext.url).route
|
||||||
|
} else {
|
||||||
|
const path = getLocation(router.options.base, router.options.mode)
|
||||||
|
route = router.resolve(path).route
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set context to app.context
|
||||||
|
await setContext(app, {
|
||||||
|
route,
|
||||||
|
next,
|
||||||
|
error: app.nuxt.error.bind(app),
|
||||||
|
payload: ssrContext ? ssrContext.payload : undefined,
|
||||||
|
req: ssrContext ? ssrContext.req : undefined,
|
||||||
|
res: ssrContext ? ssrContext.res : undefined,
|
||||||
|
beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined,
|
||||||
|
ssrContext
|
||||||
|
})
|
||||||
|
|
||||||
|
function inject(key, value) {
|
||||||
|
if (!key) {
|
||||||
|
throw new Error('inject(key, value) has no key provided')
|
||||||
|
}
|
||||||
|
if (value === undefined) {
|
||||||
|
throw new Error(`inject('${key}', value) has no value provided`)
|
||||||
|
}
|
||||||
|
|
||||||
|
key = '$' + key
|
||||||
|
// Add into app
|
||||||
|
app[key] = value
|
||||||
|
// Add into context
|
||||||
|
if (!app.context[key]) {
|
||||||
|
app.context[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if plugin not already installed
|
||||||
|
const installKey = '__nuxt_' + key + '_installed__'
|
||||||
|
if (Vue[installKey]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Vue[installKey] = true
|
||||||
|
// Call Vue.use() to install the plugin into vm
|
||||||
|
Vue.use(() => {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(Vue.prototype, key)) {
|
||||||
|
Object.defineProperty(Vue.prototype, key, {
|
||||||
|
get () {
|
||||||
|
return this.$root.$options[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject runtime config as $config
|
||||||
|
inject('config', config)
|
||||||
|
|
||||||
|
// Add enablePreview(previewData = {}) in context for plugins
|
||||||
|
if (process.static && process.client) {
|
||||||
|
app.context.enablePreview = function (previewData = {}) {
|
||||||
|
app.previewData = Object.assign({}, previewData)
|
||||||
|
inject('preview', previewData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Plugin execution
|
||||||
|
|
||||||
|
if (typeof nuxt_plugin_plugin_030ac950 === 'function') {
|
||||||
|
await nuxt_plugin_plugin_030ac950(app.context, inject)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof nuxt_plugin_axios_63fe537b === 'function') {
|
||||||
|
await nuxt_plugin_axios_63fe537b(app.context, inject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock enablePreview in context
|
||||||
|
if (process.static && process.client) {
|
||||||
|
app.context.enablePreview = function () {
|
||||||
|
console.warn('You cannot call enablePreview() outside a plugin.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If server-side, wait for async component to be resolved first
|
||||||
|
if (process.server && ssrContext && ssrContext.url) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
router.push(ssrContext.url, resolve, (err) => {
|
||||||
|
// https://github.com/vuejs/vue-router/blob/v3.4.3/src/util/errors.js
|
||||||
|
if (!err._isRouter) return reject(err)
|
||||||
|
if (err.type !== 2 /* NavigationFailureType.redirected */) return resolve()
|
||||||
|
|
||||||
|
// navigated to a different route in router guard
|
||||||
|
const unregister = router.afterEach(async (to, from) => {
|
||||||
|
ssrContext.url = to.fullPath
|
||||||
|
app.context.route = await getRouteData(to)
|
||||||
|
app.context.params = to.params || {}
|
||||||
|
app.context.query = to.query || {}
|
||||||
|
unregister()
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
app,
|
||||||
|
router
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { createApp, NuxtError }
|
||||||
80
build/jsonp.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
const chunks = {} // chunkId => exports
|
||||||
|
const chunksInstalling = {} // chunkId => Promise
|
||||||
|
const failedChunks = {}
|
||||||
|
|
||||||
|
function importChunk(chunkId, src) {
|
||||||
|
// Already installed
|
||||||
|
if (chunks[chunkId]) {
|
||||||
|
return Promise.resolve(chunks[chunkId])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed loading
|
||||||
|
if (failedChunks[chunkId]) {
|
||||||
|
return Promise.reject(failedChunks[chunkId])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Installing
|
||||||
|
if (chunksInstalling[chunkId]) {
|
||||||
|
return chunksInstalling[chunkId]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a promise in chunk cache
|
||||||
|
let resolve, reject
|
||||||
|
const promise = chunksInstalling[chunkId] = new Promise((_resolve, _reject) => {
|
||||||
|
resolve = _resolve
|
||||||
|
reject = _reject
|
||||||
|
})
|
||||||
|
|
||||||
|
// Clear chunk data from cache
|
||||||
|
delete chunks[chunkId]
|
||||||
|
|
||||||
|
// Start chunk loading
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.charset = 'utf-8'
|
||||||
|
script.timeout = 120
|
||||||
|
script.src = src
|
||||||
|
let timeout
|
||||||
|
|
||||||
|
// Create error before stack unwound to get useful stacktrace later
|
||||||
|
const error = new Error()
|
||||||
|
|
||||||
|
// Complete handlers
|
||||||
|
const onScriptComplete = script.onerror = script.onload = (event) => {
|
||||||
|
// Cleanups
|
||||||
|
clearTimeout(timeout)
|
||||||
|
delete chunksInstalling[chunkId]
|
||||||
|
|
||||||
|
// Avoid mem leaks in IE
|
||||||
|
script.onerror = script.onload = null
|
||||||
|
|
||||||
|
// Verify chunk is loaded
|
||||||
|
if (chunks[chunkId]) {
|
||||||
|
return resolve(chunks[chunkId])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something bad happened
|
||||||
|
const errorType = event && (event.type === 'load' ? 'missing' : event.type)
|
||||||
|
const realSrc = event && event.target && event.target.src
|
||||||
|
error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')'
|
||||||
|
error.name = 'ChunkLoadError'
|
||||||
|
error.type = errorType
|
||||||
|
error.request = realSrc
|
||||||
|
failedChunks[chunkId] = error
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
onScriptComplete({ type: 'timeout', target: script })
|
||||||
|
}, 120000)
|
||||||
|
|
||||||
|
// Append script
|
||||||
|
document.head.appendChild(script)
|
||||||
|
|
||||||
|
// Return promise
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
|
||||||
|
window.__NUXT_JSONP__ = function (chunkId, exports) { chunks[chunkId] = exports }
|
||||||
|
window.__NUXT_JSONP_CACHE__ = chunks
|
||||||
|
window.__NUXT_IMPORT__ = importChunk
|
||||||
110
build/loading.html
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<style>
|
||||||
|
#nuxt-loading {
|
||||||
|
background: white;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
animation: nuxtLoadingIn 10s ease;
|
||||||
|
-webkit-animation: nuxtLoadingIn 10s ease;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes nuxtLoadingIn {
|
||||||
|
0% {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes nuxtLoadingIn {
|
||||||
|
0% {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#nuxt-loading>div,
|
||||||
|
#nuxt-loading>div:after {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 5rem;
|
||||||
|
height: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nuxt-loading>div {
|
||||||
|
font-size: 10px;
|
||||||
|
position: relative;
|
||||||
|
text-indent: -9999em;
|
||||||
|
border: .5rem solid #F5F5F5;
|
||||||
|
border-left: .5rem solid black;
|
||||||
|
-webkit-transform: translateZ(0);
|
||||||
|
-ms-transform: translateZ(0);
|
||||||
|
transform: translateZ(0);
|
||||||
|
-webkit-animation: nuxtLoading 1.1s infinite linear;
|
||||||
|
animation: nuxtLoading 1.1s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nuxt-loading.error>div {
|
||||||
|
border-left: .5rem solid #ff4500;
|
||||||
|
animation-duration: 5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes nuxtLoading {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes nuxtLoading {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener('error', function () {
|
||||||
|
var e = document.getElementById('nuxt-loading');
|
||||||
|
if (e) {
|
||||||
|
e.className += ' error';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="nuxt-loading" aria-live="polite" role="status"><div>Loading...</div></div>
|
||||||
|
|
||||||
|
<!-- https://projects.lukehaas.me/css-loaders -->
|
||||||
3
build/middleware.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
const middleware = {}
|
||||||
|
|
||||||
|
export default middleware
|
||||||
90
build/mixins/fetch.client.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import { hasFetch, normalizeError, addLifecycleHook } from '../utils'
|
||||||
|
|
||||||
|
const isSsrHydration = (vm) => vm.$vnode && vm.$vnode.elm && vm.$vnode.elm.dataset && vm.$vnode.elm.dataset.fetchKey
|
||||||
|
const nuxtState = window.__NUXT__
|
||||||
|
|
||||||
|
export default {
|
||||||
|
beforeCreate () {
|
||||||
|
if (!hasFetch(this)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this._fetchDelay = typeof this.$options.fetchDelay === 'number' ? this.$options.fetchDelay : 200
|
||||||
|
|
||||||
|
Vue.util.defineReactive(this, '$fetchState', {
|
||||||
|
pending: false,
|
||||||
|
error: null,
|
||||||
|
timestamp: Date.now()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$fetch = $fetch.bind(this)
|
||||||
|
addLifecycleHook(this, 'created', created)
|
||||||
|
addLifecycleHook(this, 'beforeMount', beforeMount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeMount() {
|
||||||
|
if (!this._hydrated) {
|
||||||
|
return this.$fetch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function created() {
|
||||||
|
if (!isSsrHydration(this)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hydrate component
|
||||||
|
this._hydrated = true
|
||||||
|
this._fetchKey = +this.$vnode.elm.dataset.fetchKey
|
||||||
|
const data = nuxtState.fetch[this._fetchKey]
|
||||||
|
|
||||||
|
// If fetch error
|
||||||
|
if (data && data._error) {
|
||||||
|
this.$fetchState.error = data._error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge data
|
||||||
|
for (const key in data) {
|
||||||
|
Vue.set(this.$data, key, data[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function $fetch() {
|
||||||
|
if (!this._fetchPromise) {
|
||||||
|
this._fetchPromise = $_fetch.call(this)
|
||||||
|
.then(() => { delete this._fetchPromise })
|
||||||
|
}
|
||||||
|
return this._fetchPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
async function $_fetch() {
|
||||||
|
this.$nuxt.nbFetching++
|
||||||
|
this.$fetchState.pending = true
|
||||||
|
this.$fetchState.error = null
|
||||||
|
this._hydrated = false
|
||||||
|
let error = null
|
||||||
|
const startTime = Date.now()
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.$options.fetch.call(this)
|
||||||
|
} catch (err) {
|
||||||
|
if (process.dev) {
|
||||||
|
console.error('Error in fetch():', err)
|
||||||
|
}
|
||||||
|
error = normalizeError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const delayLeft = this._fetchDelay - (Date.now() - startTime)
|
||||||
|
if (delayLeft > 0) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, delayLeft))
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$fetchState.error = error
|
||||||
|
this.$fetchState.pending = false
|
||||||
|
this.$fetchState.timestamp = Date.now()
|
||||||
|
|
||||||
|
this.$nextTick(() => this.$nuxt.nbFetching--)
|
||||||
|
}
|
||||||
53
build/mixins/fetch.server.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import { hasFetch, normalizeError, addLifecycleHook } from '../utils'
|
||||||
|
|
||||||
|
async function serverPrefetch() {
|
||||||
|
if (!this._fetchOnServer) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call and await on $fetch
|
||||||
|
try {
|
||||||
|
await this.$options.fetch.call(this)
|
||||||
|
} catch (err) {
|
||||||
|
if (process.dev) {
|
||||||
|
console.error('Error in fetch():', err)
|
||||||
|
}
|
||||||
|
this.$fetchState.error = normalizeError(err)
|
||||||
|
}
|
||||||
|
this.$fetchState.pending = false
|
||||||
|
|
||||||
|
// Define an ssrKey for hydration
|
||||||
|
this._fetchKey = this.$ssrContext.nuxt.fetch.length
|
||||||
|
|
||||||
|
// Add data-fetch-key on parent element of Component
|
||||||
|
const attrs = this.$vnode.data.attrs = this.$vnode.data.attrs || {}
|
||||||
|
attrs['data-fetch-key'] = this._fetchKey
|
||||||
|
|
||||||
|
// Add to ssrContext for window.__NUXT__.fetch
|
||||||
|
this.$ssrContext.nuxt.fetch.push(this.$fetchState.error ? { _error: this.$fetchState.error } : this._data)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
if (!hasFetch(this)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.$options.fetchOnServer === 'function') {
|
||||||
|
this._fetchOnServer = this.$options.fetchOnServer.call(this) !== false
|
||||||
|
} else {
|
||||||
|
this._fetchOnServer = this.$options.fetchOnServer !== false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added for remove vue undefined warning while ssr
|
||||||
|
this.$fetch = () => {} // issue #8043
|
||||||
|
Vue.util.defineReactive(this, '$fetchState', {
|
||||||
|
pending: true,
|
||||||
|
error: null,
|
||||||
|
timestamp: Date.now()
|
||||||
|
})
|
||||||
|
|
||||||
|
addLifecycleHook(this, 'serverPrefetch', serverPrefetch)
|
||||||
|
}
|
||||||
|
}
|
||||||
40
build/router.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Router from 'vue-router'
|
||||||
|
import { interopDefault } from './utils'
|
||||||
|
import scrollBehavior from './router.scrollBehavior.js'
|
||||||
|
|
||||||
|
const _3829e6ee = () => interopDefault(import('..\\src\\templates\\pages\\about.vue' /* webpackChunkName: "templates/pages/about" */))
|
||||||
|
const _57e1c1b3 = () => interopDefault(import('..\\src\\templates\\pages\\index.vue' /* webpackChunkName: "templates/pages/index" */))
|
||||||
|
|
||||||
|
// TODO: remove in Nuxt 3
|
||||||
|
const emptyFn = () => {}
|
||||||
|
const originalPush = Router.prototype.push
|
||||||
|
Router.prototype.push = function push (location, onComplete = emptyFn, onAbort) {
|
||||||
|
return originalPush.call(this, location, onComplete, onAbort)
|
||||||
|
}
|
||||||
|
|
||||||
|
Vue.use(Router)
|
||||||
|
|
||||||
|
export const routerOptions = {
|
||||||
|
mode: 'history',
|
||||||
|
base: decodeURI('/'),
|
||||||
|
linkActiveClass: 'nuxt-link-active',
|
||||||
|
linkExactActiveClass: 'nuxt-link-exact-active',
|
||||||
|
scrollBehavior,
|
||||||
|
|
||||||
|
routes: [{
|
||||||
|
path: "/about",
|
||||||
|
component: _3829e6ee,
|
||||||
|
name: "about"
|
||||||
|
}, {
|
||||||
|
path: "/",
|
||||||
|
component: _57e1c1b3,
|
||||||
|
name: "index"
|
||||||
|
}],
|
||||||
|
|
||||||
|
fallback: false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRouter () {
|
||||||
|
return new Router(routerOptions)
|
||||||
|
}
|
||||||
76
build/router.scrollBehavior.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { getMatchedComponents, setScrollRestoration } from './utils'
|
||||||
|
|
||||||
|
if (process.client) {
|
||||||
|
if ('scrollRestoration' in window.history) {
|
||||||
|
setScrollRestoration('manual')
|
||||||
|
|
||||||
|
// reset scrollRestoration to auto when leaving page, allowing page reload
|
||||||
|
// and back-navigation from other pages to use the browser to restore the
|
||||||
|
// scrolling position.
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
setScrollRestoration('auto')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Setting scrollRestoration to manual again when returning to this page.
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
setScrollRestoration('manual')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (to, from, savedPosition) {
|
||||||
|
// If the returned position is falsy or an empty object, will retain current scroll position
|
||||||
|
let position = false
|
||||||
|
|
||||||
|
const Pages = getMatchedComponents(to)
|
||||||
|
|
||||||
|
// Scroll to the top of the page if...
|
||||||
|
if (
|
||||||
|
// One of the children set `scrollToTop`
|
||||||
|
Pages.some(Page => Page.options.scrollToTop) ||
|
||||||
|
// scrollToTop set in only page without children
|
||||||
|
(Pages.length < 2 && Pages.every(Page => Page.options.scrollToTop !== false))
|
||||||
|
) {
|
||||||
|
position = { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// savedPosition is only available for popstate navigations (back button)
|
||||||
|
if (savedPosition) {
|
||||||
|
position = savedPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
const nuxt = window.$nuxt
|
||||||
|
|
||||||
|
if (
|
||||||
|
// Route hash changes
|
||||||
|
(to.path === from.path && to.hash !== from.hash) ||
|
||||||
|
// Initial load (vuejs/vue-router#3199)
|
||||||
|
to === from
|
||||||
|
) {
|
||||||
|
nuxt.$nextTick(() => nuxt.$emit('triggerScroll'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// wait for the out transition to complete (if necessary)
|
||||||
|
nuxt.$once('triggerScroll', () => {
|
||||||
|
// coords will be used if no selector is provided,
|
||||||
|
// or if the selector didn't match any element.
|
||||||
|
if (to.hash) {
|
||||||
|
let hash = to.hash
|
||||||
|
// CSS.escape() is not supported with IE and Edge.
|
||||||
|
if (typeof window.CSS !== 'undefined' && typeof window.CSS.escape !== 'undefined') {
|
||||||
|
hash = '#' + window.CSS.escape(hash.substr(1))
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (document.querySelector(hash)) {
|
||||||
|
// scroll to anchor by returning the selector
|
||||||
|
position = { selector: hash }
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(position)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
16
build/routes.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "about",
|
||||||
|
"path": "/about",
|
||||||
|
"component": "C:\\\\Users\\\\arthu\\\\Documents\\\\Workspace\\\\artsite\\\\src\\\\templates\\\\pages\\\\about.vue",
|
||||||
|
"chunkName": "templates/pages/about",
|
||||||
|
"_name": "_3829e6ee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index",
|
||||||
|
"path": "/",
|
||||||
|
"component": "C:\\\\Users\\\\arthu\\\\Documents\\\\Workspace\\\\artsite\\\\src\\\\templates\\\\pages\\\\index.vue",
|
||||||
|
"chunkName": "templates/pages/index",
|
||||||
|
"_name": "_57e1c1b3"
|
||||||
|
}
|
||||||
|
]
|
||||||
272
build/server.js
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
import { stringify } from 'querystring'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
import middleware from './middleware.js'
|
||||||
|
import {
|
||||||
|
applyAsyncData,
|
||||||
|
middlewareSeries,
|
||||||
|
sanitizeComponent,
|
||||||
|
getMatchedComponents,
|
||||||
|
promisify
|
||||||
|
} from './utils.js'
|
||||||
|
import fetchMixin from './mixins/fetch.server'
|
||||||
|
import { createApp, NuxtError } from './index.js'
|
||||||
|
import NuxtLink from './components/nuxt-link.server.js' // should be included after ./index.js
|
||||||
|
|
||||||
|
// Update serverPrefetch strategy
|
||||||
|
Vue.config.optionMergeStrategies.serverPrefetch = Vue.config.optionMergeStrategies.created
|
||||||
|
|
||||||
|
// Fetch mixin
|
||||||
|
if (!Vue.__nuxt__fetch__mixin__) {
|
||||||
|
Vue.mixin(fetchMixin)
|
||||||
|
Vue.__nuxt__fetch__mixin__ = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component: <NuxtLink>
|
||||||
|
Vue.component(NuxtLink.name, NuxtLink)
|
||||||
|
Vue.component('NLink', NuxtLink)
|
||||||
|
|
||||||
|
if (!global.fetch) { global.fetch = fetch }
|
||||||
|
|
||||||
|
const noopApp = () => new Vue({ render: h => h('div') })
|
||||||
|
|
||||||
|
function urlJoin () {
|
||||||
|
return Array.prototype.slice.call(arguments).join('/').replace(/\/+/g, '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
const createNext = ssrContext => (opts) => {
|
||||||
|
// If static target, render on client-side
|
||||||
|
ssrContext.redirected = opts
|
||||||
|
if (ssrContext.target === 'static' || !ssrContext.res) {
|
||||||
|
ssrContext.nuxt.serverRendered = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
opts.query = stringify(opts.query)
|
||||||
|
opts.path = opts.path + (opts.query ? '?' + opts.query : '')
|
||||||
|
const routerBase = '/'
|
||||||
|
if (!opts.path.startsWith('http') && (routerBase !== '/' && !opts.path.startsWith(routerBase))) {
|
||||||
|
opts.path = urlJoin(routerBase, opts.path)
|
||||||
|
}
|
||||||
|
// Avoid loop redirect
|
||||||
|
if (opts.path === ssrContext.url) {
|
||||||
|
ssrContext.redirected = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ssrContext.res.writeHead(opts.status, {
|
||||||
|
Location: opts.path
|
||||||
|
})
|
||||||
|
ssrContext.res.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This exported function will be called by `bundleRenderer`.
|
||||||
|
// This is where we perform data-prefetching to determine the
|
||||||
|
// state of our application before actually rendering it.
|
||||||
|
// Since data fetching is async, this function is expected to
|
||||||
|
// return a Promise that resolves to the app instance.
|
||||||
|
export default async (ssrContext) => {
|
||||||
|
// Create ssrContext.next for simulate next() of beforeEach() when wanted to redirect
|
||||||
|
ssrContext.redirected = false
|
||||||
|
ssrContext.next = createNext(ssrContext)
|
||||||
|
// Used for beforeNuxtRender({ Components, nuxtState })
|
||||||
|
ssrContext.beforeRenderFns = []
|
||||||
|
// Nuxt object (window.{{globals.context}}, defaults to window.__NUXT__)
|
||||||
|
ssrContext.nuxt = { layout: 'default', data: [], fetch: [], error: null, serverRendered: true, routePath: '' }
|
||||||
|
// Remove query from url is static target
|
||||||
|
if (process.static && ssrContext.url) {
|
||||||
|
ssrContext.url = ssrContext.url.split('?')[0]
|
||||||
|
}
|
||||||
|
// Public runtime config
|
||||||
|
ssrContext.nuxt.config = ssrContext.runtimeConfig.public
|
||||||
|
// Create the app definition and the instance (created for each request)
|
||||||
|
const { app, router } = await createApp(ssrContext, { ...ssrContext.runtimeConfig.public, ...ssrContext.runtimeConfig.private })
|
||||||
|
const _app = new Vue(app)
|
||||||
|
// Add ssr route path to nuxt context so we can account for page navigation between ssr and csr
|
||||||
|
ssrContext.nuxt.routePath = app.context.route.path
|
||||||
|
|
||||||
|
// Add meta infos (used in renderer.js)
|
||||||
|
ssrContext.meta = _app.$meta()
|
||||||
|
|
||||||
|
// Keep asyncData for each matched component in ssrContext (used in app/utils.js via this.$ssrContext)
|
||||||
|
ssrContext.asyncData = {}
|
||||||
|
|
||||||
|
const beforeRender = async () => {
|
||||||
|
// Call beforeNuxtRender() methods
|
||||||
|
await Promise.all(ssrContext.beforeRenderFns.map(fn => promisify(fn, { Components, nuxtState: ssrContext.nuxt })))
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderErrorPage = async () => {
|
||||||
|
// Don't server-render the page in static target
|
||||||
|
if (ssrContext.target === 'static') {
|
||||||
|
ssrContext.nuxt.serverRendered = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load layout for error page
|
||||||
|
const layout = (NuxtError.options || NuxtError).layout
|
||||||
|
const errLayout = typeof layout === 'function' ? layout.call(NuxtError, app.context) : layout
|
||||||
|
ssrContext.nuxt.layout = errLayout || 'default'
|
||||||
|
await _app.loadLayout(errLayout)
|
||||||
|
_app.setLayout(errLayout)
|
||||||
|
|
||||||
|
await beforeRender()
|
||||||
|
return _app
|
||||||
|
}
|
||||||
|
const render404Page = () => {
|
||||||
|
app.context.error({ statusCode: 404, path: ssrContext.url, message: 'This page could not be found' })
|
||||||
|
return renderErrorPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
const s = Date.now()
|
||||||
|
|
||||||
|
// Components are already resolved by setContext -> getRouteData (app/utils.js)
|
||||||
|
const Components = getMatchedComponents(router.match(ssrContext.url))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Call global middleware (nuxt.config.js)
|
||||||
|
*/
|
||||||
|
let midd = []
|
||||||
|
midd = midd.map((name) => {
|
||||||
|
if (typeof name === 'function') {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
if (typeof middleware[name] !== 'function') {
|
||||||
|
app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||||
|
}
|
||||||
|
return middleware[name]
|
||||||
|
})
|
||||||
|
await middlewareSeries(midd, app.context)
|
||||||
|
// ...If there is a redirect or an error, stop the process
|
||||||
|
if (ssrContext.redirected) {
|
||||||
|
return noopApp()
|
||||||
|
}
|
||||||
|
if (ssrContext.nuxt.error) {
|
||||||
|
return renderErrorPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Set layout
|
||||||
|
*/
|
||||||
|
let layout = Components.length ? Components[0].options.layout : NuxtError.layout
|
||||||
|
if (typeof layout === 'function') {
|
||||||
|
layout = layout(app.context)
|
||||||
|
}
|
||||||
|
await _app.loadLayout(layout)
|
||||||
|
if (ssrContext.nuxt.error) {
|
||||||
|
return renderErrorPage()
|
||||||
|
}
|
||||||
|
layout = _app.setLayout(layout)
|
||||||
|
ssrContext.nuxt.layout = _app.layoutName
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Call middleware (layout + pages)
|
||||||
|
*/
|
||||||
|
midd = []
|
||||||
|
|
||||||
|
layout = sanitizeComponent(layout)
|
||||||
|
if (layout.options.middleware) {
|
||||||
|
midd = midd.concat(layout.options.middleware)
|
||||||
|
}
|
||||||
|
|
||||||
|
Components.forEach((Component) => {
|
||||||
|
if (Component.options.middleware) {
|
||||||
|
midd = midd.concat(Component.options.middleware)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
midd = midd.map((name) => {
|
||||||
|
if (typeof name === 'function') {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
if (typeof middleware[name] !== 'function') {
|
||||||
|
app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||||
|
}
|
||||||
|
return middleware[name]
|
||||||
|
})
|
||||||
|
await middlewareSeries(midd, app.context)
|
||||||
|
// ...If there is a redirect or an error, stop the process
|
||||||
|
if (ssrContext.redirected) {
|
||||||
|
return noopApp()
|
||||||
|
}
|
||||||
|
if (ssrContext.nuxt.error) {
|
||||||
|
return renderErrorPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Call .validate()
|
||||||
|
*/
|
||||||
|
let isValid = true
|
||||||
|
try {
|
||||||
|
for (const Component of Components) {
|
||||||
|
if (typeof Component.options.validate !== 'function') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid = await Component.options.validate(app.context)
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (validationError) {
|
||||||
|
// ...If .validate() threw an error
|
||||||
|
app.context.error({
|
||||||
|
statusCode: validationError.statusCode || '500',
|
||||||
|
message: validationError.message
|
||||||
|
})
|
||||||
|
return renderErrorPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...If .validate() returned false
|
||||||
|
if (!isValid) {
|
||||||
|
// Render a 404 error page
|
||||||
|
return render404Page()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no Components found, returns 404
|
||||||
|
if (!Components.length) {
|
||||||
|
return render404Page()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call asyncData & fetch hooks on components matched by the route.
|
||||||
|
const asyncDatas = await Promise.all(Components.map((Component) => {
|
||||||
|
const promises = []
|
||||||
|
|
||||||
|
// Call asyncData(context)
|
||||||
|
if (Component.options.asyncData && typeof Component.options.asyncData === 'function') {
|
||||||
|
const promise = promisify(Component.options.asyncData, app.context)
|
||||||
|
promise.then((asyncDataResult) => {
|
||||||
|
ssrContext.asyncData[Component.cid] = asyncDataResult
|
||||||
|
applyAsyncData(Component)
|
||||||
|
return asyncDataResult
|
||||||
|
})
|
||||||
|
promises.push(promise)
|
||||||
|
} else {
|
||||||
|
promises.push(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call fetch(context)
|
||||||
|
if (Component.options.fetch && Component.options.fetch.length) {
|
||||||
|
promises.push(Component.options.fetch(app.context))
|
||||||
|
} else {
|
||||||
|
promises.push(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (process.env.DEBUG && asyncDatas.length) console.debug('Data fetching ' + ssrContext.url + ': ' + (Date.now() - s) + 'ms')
|
||||||
|
|
||||||
|
// datas are the first row of each
|
||||||
|
ssrContext.nuxt.data = asyncDatas.map(r => r[0] || {})
|
||||||
|
|
||||||
|
// ...If there is a redirect or an error, stop the process
|
||||||
|
if (ssrContext.redirected) {
|
||||||
|
return noopApp()
|
||||||
|
}
|
||||||
|
if (ssrContext.nuxt.error) {
|
||||||
|
return renderErrorPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call beforeNuxtRender methods & add store state
|
||||||
|
await beforeRender()
|
||||||
|
|
||||||
|
return _app
|
||||||
|
}
|
||||||
643
build/utils.js
Normal file
@@ -0,0 +1,643 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
// window.{{globals.loadedCallback}} hook
|
||||||
|
// Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
|
||||||
|
if (process.client) {
|
||||||
|
window.onNuxtReadyCbs = []
|
||||||
|
window.onNuxtReady = (cb) => {
|
||||||
|
window.onNuxtReadyCbs.push(cb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function empty () {}
|
||||||
|
|
||||||
|
export function globalHandleError (error) {
|
||||||
|
if (Vue.config.errorHandler) {
|
||||||
|
Vue.config.errorHandler(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function interopDefault (promise) {
|
||||||
|
return promise.then(m => m.default || m)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasFetch(vm) {
|
||||||
|
return vm.$options && typeof vm.$options.fetch === 'function' && !vm.$options.fetch.length
|
||||||
|
}
|
||||||
|
export function getChildrenComponentInstancesUsingFetch(vm, instances = []) {
|
||||||
|
const children = vm.$children || []
|
||||||
|
for (const child of children) {
|
||||||
|
if (child.$fetch) {
|
||||||
|
instances.push(child)
|
||||||
|
continue; // Don't get the children since it will reload the template
|
||||||
|
}
|
||||||
|
if (child.$children) {
|
||||||
|
getChildrenComponentInstancesUsingFetch(child, instances)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instances
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyAsyncData (Component, asyncData) {
|
||||||
|
if (
|
||||||
|
// For SSR, we once all this function without second param to just apply asyncData
|
||||||
|
// Prevent doing this for each SSR request
|
||||||
|
!asyncData && Component.options.__hasNuxtData
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComponentData = Component.options._originDataFn || Component.options.data || function () { return {} }
|
||||||
|
Component.options._originDataFn = ComponentData
|
||||||
|
|
||||||
|
Component.options.data = function () {
|
||||||
|
const data = ComponentData.call(this, this)
|
||||||
|
if (this.$ssrContext) {
|
||||||
|
asyncData = this.$ssrContext.asyncData[Component.cid]
|
||||||
|
}
|
||||||
|
return { ...data, ...asyncData }
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.options.__hasNuxtData = true
|
||||||
|
|
||||||
|
if (Component._Ctor && Component._Ctor.options) {
|
||||||
|
Component._Ctor.options.data = Component.options.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sanitizeComponent (Component) {
|
||||||
|
// If Component already sanitized
|
||||||
|
if (Component.options && Component._Ctor === Component) {
|
||||||
|
return Component
|
||||||
|
}
|
||||||
|
if (!Component.options) {
|
||||||
|
Component = Vue.extend(Component) // fix issue #6
|
||||||
|
Component._Ctor = Component
|
||||||
|
} else {
|
||||||
|
Component._Ctor = Component
|
||||||
|
Component.extendOptions = Component.options
|
||||||
|
}
|
||||||
|
// If no component name defined, set file path as name, (also fixes #5703)
|
||||||
|
if (!Component.options.name && Component.options.__file) {
|
||||||
|
Component.options.name = Component.options.__file
|
||||||
|
}
|
||||||
|
return Component
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMatchedComponents (route, matches = false, prop = 'components') {
|
||||||
|
return Array.prototype.concat.apply([], route.matched.map((m, index) => {
|
||||||
|
return Object.keys(m[prop]).map((key) => {
|
||||||
|
matches && matches.push(index)
|
||||||
|
return m[prop][key]
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMatchedComponentsInstances (route, matches = false) {
|
||||||
|
return getMatchedComponents(route, matches, 'instances')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function flatMapComponents (route, fn) {
|
||||||
|
return Array.prototype.concat.apply([], route.matched.map((m, index) => {
|
||||||
|
return Object.keys(m.components).reduce((promises, key) => {
|
||||||
|
if (m.components[key]) {
|
||||||
|
promises.push(fn(m.components[key], m.instances[key], m, key, index))
|
||||||
|
} else {
|
||||||
|
delete m.components[key]
|
||||||
|
}
|
||||||
|
return promises
|
||||||
|
}, [])
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveRouteComponents (route, fn) {
|
||||||
|
return Promise.all(
|
||||||
|
flatMapComponents(route, async (Component, instance, match, key) => {
|
||||||
|
// If component is a function, resolve it
|
||||||
|
if (typeof Component === 'function' && !Component.options) {
|
||||||
|
Component = await Component()
|
||||||
|
}
|
||||||
|
match.components[key] = Component = sanitizeComponent(Component)
|
||||||
|
return typeof fn === 'function' ? fn(Component, instance, match, key) : Component
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRouteData (route) {
|
||||||
|
if (!route) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Make sure the components are resolved (code-splitting)
|
||||||
|
await resolveRouteComponents(route)
|
||||||
|
// Send back a copy of route with meta based on Component definition
|
||||||
|
return {
|
||||||
|
...route,
|
||||||
|
meta: getMatchedComponents(route).map((Component, index) => {
|
||||||
|
return { ...Component.options.meta, ...(route.matched[index] || {}).meta }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setContext (app, context) {
|
||||||
|
// If context not defined, create it
|
||||||
|
if (!app.context) {
|
||||||
|
app.context = {
|
||||||
|
isStatic: process.static,
|
||||||
|
isDev: true,
|
||||||
|
isHMR: false,
|
||||||
|
app,
|
||||||
|
|
||||||
|
payload: context.payload,
|
||||||
|
error: context.error,
|
||||||
|
base: '/',
|
||||||
|
env: {}
|
||||||
|
}
|
||||||
|
// Only set once
|
||||||
|
if (!process.static && context.req) {
|
||||||
|
app.context.req = context.req
|
||||||
|
}
|
||||||
|
if (!process.static && context.res) {
|
||||||
|
app.context.res = context.res
|
||||||
|
}
|
||||||
|
if (context.ssrContext) {
|
||||||
|
app.context.ssrContext = context.ssrContext
|
||||||
|
}
|
||||||
|
app.context.redirect = (status, path, query) => {
|
||||||
|
if (!status) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.context._redirected = true
|
||||||
|
// if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
|
||||||
|
let pathType = typeof path
|
||||||
|
if (typeof status !== 'number' && (pathType === 'undefined' || pathType === 'object')) {
|
||||||
|
query = path || {}
|
||||||
|
path = status
|
||||||
|
pathType = typeof path
|
||||||
|
status = 302
|
||||||
|
}
|
||||||
|
if (pathType === 'object') {
|
||||||
|
path = app.router.resolve(path).route.fullPath
|
||||||
|
}
|
||||||
|
// "/absolute/route", "./relative/route" or "../relative/route"
|
||||||
|
if (/(^[.]{1,2}\/)|(^\/(?!\/))/.test(path)) {
|
||||||
|
app.context.next({
|
||||||
|
path,
|
||||||
|
query,
|
||||||
|
status
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
path = formatUrl(path, query)
|
||||||
|
if (process.server) {
|
||||||
|
app.context.next({
|
||||||
|
path,
|
||||||
|
status
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (process.client) {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/Location/replace
|
||||||
|
window.location.replace(path)
|
||||||
|
|
||||||
|
// Throw a redirect error
|
||||||
|
throw new Error('ERR_REDIRECT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (process.server) {
|
||||||
|
app.context.beforeNuxtRender = fn => context.beforeRenderFns.push(fn)
|
||||||
|
}
|
||||||
|
if (process.client) {
|
||||||
|
app.context.nuxtState = window.__NUXT__
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamic keys
|
||||||
|
const [currentRouteData, fromRouteData] = await Promise.all([
|
||||||
|
getRouteData(context.route),
|
||||||
|
getRouteData(context.from)
|
||||||
|
])
|
||||||
|
|
||||||
|
if (context.route) {
|
||||||
|
app.context.route = currentRouteData
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.from) {
|
||||||
|
app.context.from = fromRouteData
|
||||||
|
}
|
||||||
|
|
||||||
|
app.context.next = context.next
|
||||||
|
app.context._redirected = false
|
||||||
|
app.context._errored = false
|
||||||
|
app.context.isHMR = Boolean(context.isHMR)
|
||||||
|
app.context.params = app.context.route.params || {}
|
||||||
|
app.context.query = app.context.route.query || {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function middlewareSeries (promises, appContext) {
|
||||||
|
if (!promises.length || appContext._redirected || appContext._errored) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
return promisify(promises[0], appContext)
|
||||||
|
.then(() => {
|
||||||
|
return middlewareSeries(promises.slice(1), appContext)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function promisify (fn, context) {
|
||||||
|
let promise
|
||||||
|
if (fn.length === 2) {
|
||||||
|
console.warn('Callback-based asyncData, fetch or middleware calls are deprecated. ' +
|
||||||
|
'Please switch to promises or async/await syntax')
|
||||||
|
|
||||||
|
// fn(context, callback)
|
||||||
|
promise = new Promise((resolve) => {
|
||||||
|
fn(context, function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
context.error(err)
|
||||||
|
}
|
||||||
|
data = data || {}
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
promise = fn(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promise && promise instanceof Promise && typeof promise.then === 'function') {
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
return Promise.resolve(promise)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imported from vue-router
|
||||||
|
export function getLocation (base, mode) {
|
||||||
|
let path = decodeURI(window.location.pathname)
|
||||||
|
if (mode === 'hash') {
|
||||||
|
return window.location.hash.replace(/^#\//, '')
|
||||||
|
}
|
||||||
|
// To get matched with sanitized router.base add trailing slash
|
||||||
|
if (base && (path.endsWith('/') ? path : path + '/').startsWith(base)) {
|
||||||
|
path = path.slice(base.length)
|
||||||
|
}
|
||||||
|
return (path || '/') + window.location.search + window.location.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imported from path-to-regexp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile a string to a template function for the path.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {Object=} options
|
||||||
|
* @return {!function(Object=, Object=)}
|
||||||
|
*/
|
||||||
|
export function compile (str, options) {
|
||||||
|
return tokensToFunction(parse(str, options), options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getQueryDiff (toQuery, fromQuery) {
|
||||||
|
const diff = {}
|
||||||
|
const queries = { ...toQuery, ...fromQuery }
|
||||||
|
for (const k in queries) {
|
||||||
|
if (String(toQuery[k]) !== String(fromQuery[k])) {
|
||||||
|
diff[k] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return diff
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeError (err) {
|
||||||
|
let message
|
||||||
|
if (!(err.message || typeof err === 'string')) {
|
||||||
|
try {
|
||||||
|
message = JSON.stringify(err, null, 2)
|
||||||
|
} catch (e) {
|
||||||
|
message = `[${err.constructor.name}]`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message = err.message || err
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...err,
|
||||||
|
message,
|
||||||
|
statusCode: (err.statusCode || err.status || (err.response && err.response.status) || 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main path matching regexp utility.
|
||||||
|
*
|
||||||
|
* @type {RegExp}
|
||||||
|
*/
|
||||||
|
const PATH_REGEXP = new RegExp([
|
||||||
|
// Match escaped characters that would otherwise appear in future matches.
|
||||||
|
// This allows the user to escape special characters that won't transform.
|
||||||
|
'(\\\\.)',
|
||||||
|
// Match Express-style parameters and un-named parameters with a prefix
|
||||||
|
// and optional suffixes. Matches appear as:
|
||||||
|
//
|
||||||
|
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
|
||||||
|
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
|
||||||
|
// "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
|
||||||
|
'([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
|
||||||
|
].join('|'), 'g')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a string for the raw tokens.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {Object=} options
|
||||||
|
* @return {!Array}
|
||||||
|
*/
|
||||||
|
function parse (str, options) {
|
||||||
|
const tokens = []
|
||||||
|
let key = 0
|
||||||
|
let index = 0
|
||||||
|
let path = ''
|
||||||
|
const defaultDelimiter = (options && options.delimiter) || '/'
|
||||||
|
let res
|
||||||
|
|
||||||
|
while ((res = PATH_REGEXP.exec(str)) != null) {
|
||||||
|
const m = res[0]
|
||||||
|
const escaped = res[1]
|
||||||
|
const offset = res.index
|
||||||
|
path += str.slice(index, offset)
|
||||||
|
index = offset + m.length
|
||||||
|
|
||||||
|
// Ignore already escaped sequences.
|
||||||
|
if (escaped) {
|
||||||
|
path += escaped[1]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const next = str[index]
|
||||||
|
const prefix = res[2]
|
||||||
|
const name = res[3]
|
||||||
|
const capture = res[4]
|
||||||
|
const group = res[5]
|
||||||
|
const modifier = res[6]
|
||||||
|
const asterisk = res[7]
|
||||||
|
|
||||||
|
// Push the current path onto the tokens.
|
||||||
|
if (path) {
|
||||||
|
tokens.push(path)
|
||||||
|
path = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const partial = prefix != null && next != null && next !== prefix
|
||||||
|
const repeat = modifier === '+' || modifier === '*'
|
||||||
|
const optional = modifier === '?' || modifier === '*'
|
||||||
|
const delimiter = res[2] || defaultDelimiter
|
||||||
|
const pattern = capture || group
|
||||||
|
|
||||||
|
tokens.push({
|
||||||
|
name: name || key++,
|
||||||
|
prefix: prefix || '',
|
||||||
|
delimiter,
|
||||||
|
optional,
|
||||||
|
repeat,
|
||||||
|
partial,
|
||||||
|
asterisk: Boolean(asterisk),
|
||||||
|
pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any characters still remaining.
|
||||||
|
if (index < str.length) {
|
||||||
|
path += str.substr(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the path exists, push it onto the end.
|
||||||
|
if (path) {
|
||||||
|
tokens.push(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prettier encoding of URI path segments.
|
||||||
|
*
|
||||||
|
* @param {string}
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function encodeURIComponentPretty (str, slashAllowed) {
|
||||||
|
const re = slashAllowed ? /[?#]/g : /[/?#]/g
|
||||||
|
return encodeURI(str).replace(re, (c) => {
|
||||||
|
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
|
||||||
|
*
|
||||||
|
* @param {string}
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function encodeAsterisk (str) {
|
||||||
|
return encodeURIComponentPretty(str, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape a regular expression string.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function escapeString (str) {
|
||||||
|
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape the capturing group by escaping special characters and meaning.
|
||||||
|
*
|
||||||
|
* @param {string} group
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function escapeGroup (group) {
|
||||||
|
return group.replace(/([=!:$/()])/g, '\\$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose a method for transforming tokens into the path function.
|
||||||
|
*/
|
||||||
|
function tokensToFunction (tokens, options) {
|
||||||
|
// Compile all the tokens into regexps.
|
||||||
|
const matches = new Array(tokens.length)
|
||||||
|
|
||||||
|
// Compile all the patterns before compilation.
|
||||||
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
|
if (typeof tokens[i] === 'object') {
|
||||||
|
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (obj, opts) {
|
||||||
|
let path = ''
|
||||||
|
const data = obj || {}
|
||||||
|
const options = opts || {}
|
||||||
|
const encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
|
||||||
|
|
||||||
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
|
const token = tokens[i]
|
||||||
|
|
||||||
|
if (typeof token === 'string') {
|
||||||
|
path += token
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = data[token.name || 'pathMatch']
|
||||||
|
let segment
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
if (token.optional) {
|
||||||
|
// Prepend partial segment prefixes.
|
||||||
|
if (token.partial) {
|
||||||
|
path += token.prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to be defined')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
if (!token.repeat) {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length === 0) {
|
||||||
|
if (token.optional) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to not be empty')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < value.length; j++) {
|
||||||
|
segment = encode(value[j])
|
||||||
|
|
||||||
|
if (!matches[i].test(segment)) {
|
||||||
|
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
|
||||||
|
}
|
||||||
|
|
||||||
|
path += (j === 0 ? token.prefix : token.delimiter) + segment
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
segment = token.asterisk ? encodeAsterisk(value) : encode(value)
|
||||||
|
|
||||||
|
if (!matches[i].test(segment)) {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
|
||||||
|
}
|
||||||
|
|
||||||
|
path += token.prefix + segment
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the flags for a regexp from the options.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function flags (options) {
|
||||||
|
return options && options.sensitive ? '' : 'i'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format given url, append query to url query string
|
||||||
|
*
|
||||||
|
* @param {string} url
|
||||||
|
* @param {string} query
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function formatUrl (url, query) {
|
||||||
|
let protocol
|
||||||
|
const index = url.indexOf('://')
|
||||||
|
if (index !== -1) {
|
||||||
|
protocol = url.substring(0, index)
|
||||||
|
url = url.substring(index + 3)
|
||||||
|
} else if (url.startsWith('//')) {
|
||||||
|
url = url.substring(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
let parts = url.split('/')
|
||||||
|
let result = (protocol ? protocol + '://' : '//') + parts.shift()
|
||||||
|
|
||||||
|
let path = parts.join('/')
|
||||||
|
if (path === '' && parts.length === 1) {
|
||||||
|
result += '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
let hash
|
||||||
|
parts = path.split('#')
|
||||||
|
if (parts.length === 2) {
|
||||||
|
[path, hash] = parts
|
||||||
|
}
|
||||||
|
|
||||||
|
result += path ? '/' + path : ''
|
||||||
|
|
||||||
|
if (query && JSON.stringify(query) !== '{}') {
|
||||||
|
result += (url.split('?').length === 2 ? '&' : '?') + formatQuery(query)
|
||||||
|
}
|
||||||
|
result += hash ? '#' + hash : ''
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform data object to query string
|
||||||
|
*
|
||||||
|
* @param {object} query
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function formatQuery (query) {
|
||||||
|
return Object.keys(query).sort().map((key) => {
|
||||||
|
const val = query[key]
|
||||||
|
if (val == null) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
return val.slice().map(val2 => [key, '=', val2].join('')).join('&')
|
||||||
|
}
|
||||||
|
return key + '=' + val
|
||||||
|
}).filter(Boolean).join('&')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addLifecycleHook(vm, hook, fn) {
|
||||||
|
if (!vm.$options[hook]) {
|
||||||
|
vm.$options[hook] = []
|
||||||
|
}
|
||||||
|
if (!vm.$options[hook].includes(fn)) {
|
||||||
|
vm.$options[hook].push(fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function urlJoin () {
|
||||||
|
return [].slice
|
||||||
|
.call(arguments)
|
||||||
|
.join('/')
|
||||||
|
.replace(/\/+/g, '/')
|
||||||
|
.replace(':/', '://')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stripTrailingSlash (path) {
|
||||||
|
return path.replace(/\/+$/, '') || '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSamePath (p1, p2) {
|
||||||
|
return stripTrailingSlash(p1) === stripTrailingSlash(p2)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setScrollRestoration (newVal) {
|
||||||
|
try {
|
||||||
|
window.history.scrollRestoration = newVal;
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
26
build/vetur/tags.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"Footer": {
|
||||||
|
"description": "Auto imported from components/Footer.vue"
|
||||||
|
},
|
||||||
|
"LazyFooter": {
|
||||||
|
"description": "Auto imported from components/Footer.vue"
|
||||||
|
},
|
||||||
|
"GoToTop": {
|
||||||
|
"description": "Auto imported from components/GoToTop.vue"
|
||||||
|
},
|
||||||
|
"LazyGoToTop": {
|
||||||
|
"description": "Auto imported from components/GoToTop.vue"
|
||||||
|
},
|
||||||
|
"Header": {
|
||||||
|
"description": "Auto imported from components/Header.vue"
|
||||||
|
},
|
||||||
|
"LazyHeader": {
|
||||||
|
"description": "Auto imported from components/Header.vue"
|
||||||
|
},
|
||||||
|
"LangSwitcher": {
|
||||||
|
"description": "Auto imported from components/LangSwitcher.vue"
|
||||||
|
},
|
||||||
|
"LazyLangSwitcher": {
|
||||||
|
"description": "Auto imported from components/LangSwitcher.vue"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
build/views/app.template.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html {{ HTML_ATTRS }}>
|
||||||
|
<head {{ HEAD_ATTRS }}>
|
||||||
|
{{ HEAD }}
|
||||||
|
</head>
|
||||||
|
<body {{ BODY_ATTRS }}>
|
||||||
|
{{ APP }}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
build/views/error.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Server error</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name=viewport>
|
||||||
|
<style>
|
||||||
|
.__nuxt-error-page{padding: 1rem;background:#f7f8fb;color:#47494e;text-align:center;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;font-family:sans-serif;font-weight:100!important;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;position:absolute;top:0;left:0;right:0;bottom:0}.__nuxt-error-page .error{max-width:450px}.__nuxt-error-page .title{font-size:24px;font-size:1.5rem;margin-top:15px;color:#47494e;margin-bottom:8px}.__nuxt-error-page .description{color:#7f828b;line-height:21px;margin-bottom:10px}.__nuxt-error-page a{color:#7f828b!important;text-decoration:none}.__nuxt-error-page .logo{position:fixed;left:12px;bottom:12px}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="__nuxt-error-page">
|
||||||
|
<div class="error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48"><path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z"/></svg>
|
||||||
|
<div class="title">Server error</div>
|
||||||
|
<div class="description">{{ message }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="logo">
|
||||||
|
<a href="https://nuxtjs.org" target="_blank" rel="noopener">Nuxt.js</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
4
config/Axios.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
baseUrl: 'http://localhost:3333',
|
||||||
|
credentials: true
|
||||||
|
}
|
||||||
11
config/Head.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default {
|
||||||
|
title: 'artsite',
|
||||||
|
meta: [
|
||||||
|
{ charset: 'utf-8' },
|
||||||
|
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||||
|
{ hid: 'description', name: 'description', content: '' }
|
||||||
|
],
|
||||||
|
link: [
|
||||||
|
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
|
||||||
|
]
|
||||||
|
}
|
||||||
4
config/index.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import Axios from './Axios'
|
||||||
|
import Head from './Head'
|
||||||
|
|
||||||
|
export { Axios, Head }
|
||||||
47
nuxt.config.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { Axios, Head } from './config'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
head: Head,
|
||||||
|
|
||||||
|
server: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 3333
|
||||||
|
},
|
||||||
|
|
||||||
|
css: [
|
||||||
|
],
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
],
|
||||||
|
|
||||||
|
components: true,
|
||||||
|
|
||||||
|
buildModules: [
|
||||||
|
'@nuxt/typescript-build',
|
||||||
|
'@nuxtjs/tailwindcss',
|
||||||
|
],
|
||||||
|
|
||||||
|
modules: [
|
||||||
|
['@nuxtjs/axios', Axios],
|
||||||
|
],
|
||||||
|
|
||||||
|
buildDir: 'build',
|
||||||
|
|
||||||
|
srcDir: 'src',
|
||||||
|
|
||||||
|
dir: {
|
||||||
|
assets: 'assets',
|
||||||
|
layouts: 'templates/layouts',
|
||||||
|
middleware: 'middleware',
|
||||||
|
pages: 'templates/pages',
|
||||||
|
static: 'public',
|
||||||
|
store: 'store',
|
||||||
|
},
|
||||||
|
|
||||||
|
build: {},
|
||||||
|
|
||||||
|
pageTransition: {
|
||||||
|
name: 'page',
|
||||||
|
mode: 'out-in',
|
||||||
|
},
|
||||||
|
}
|
||||||
24
package.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "artsite",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "nuxt-ts",
|
||||||
|
"build": "nuxt-ts build",
|
||||||
|
"start": "nuxt-ts start",
|
||||||
|
"generate": "nuxt-ts generate"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nuxt/typescript-runtime": "^2.0.0",
|
||||||
|
"@nuxtjs/axios": "^5.12.2",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"nuxt": "^2.14.6",
|
||||||
|
"sass": "^1.27.0",
|
||||||
|
"sass-loader": "^10.0.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@nuxt/types": "^2.14.6",
|
||||||
|
"@nuxt/typescript-build": "^2.0.3",
|
||||||
|
"@nuxtjs/tailwindcss": "^3.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/assets/css/tailwind.css
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Raleway&display=swap');
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
1
src/assets/img/404.svg
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src/assets/img/computer.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
1
src/assets/img/icons/arrow-down.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 5v11.17l-4.88-4.88c-.39-.39-1.03-.39-1.42 0-.39.39-.39 1.02 0 1.41l6.59 6.59c.39.39 1.02.39 1.41 0l6.59-6.59c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L13 16.17V5c0-.55-.45-1-1-1s-1 .45-1 1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 355 B |
15
src/assets/img/icons/case.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 337.76 337.76" style="enable-background:new 0 0 337.76 337.76;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M320.88,67.76H223.6c0,0,0-0.56,0-0.88V35.92c0-9.323-7.557-16.88-16.88-16.88h-75.76c-9.323,0-16.88,7.557-16.88,16.88
|
||||||
|
v31.04c0,0,0,0.56,0,0.88h-97.2C7.557,67.84,0,75.397,0,84.72v217.12c0,9.323,7.557,16.88,16.88,16.88h304
|
||||||
|
c9.323,0,16.88-7.557,16.88-16.88V84.64C337.76,75.317,330.203,67.76,320.88,67.76z M130.08,66.8l0.16-31.04
|
||||||
|
c0-0.486,0.394-0.88,0.88-0.88h75.92c0.486,0,0.88,0.394,0.88,0.88V66.8c0,0.486-0.394,0.88-0.88,0.88h-76.08
|
||||||
|
C130.474,67.68,130.08,67.286,130.08,66.8C130.08,66.8,130.08,66.8,130.08,66.8z M16.88,83.76h304
|
||||||
|
c-7.52,14.24-46.64,81.6-119.44,97.76v-9.28c0.002-9.199-7.363-16.706-16.56-16.88h-32c-9.323,0-16.88,7.557-16.88,16.88v9.44
|
||||||
|
c-72.72-16-112-83.6-119.44-97.76L16.88,83.76z M185.52,172.24v46.56c0,0.486-0.394,0.88-0.88,0.88h-31.76
|
||||||
|
c-0.486,0-0.88-0.394-0.88-0.88v-46.56c0-0.486,0.394-0.88,0.88-0.88h32C185.271,171.47,185.535,171.834,185.52,172.24z
|
||||||
|
M321.52,301.92c0,0.486-0.394,0.88-0.88,0.88H16.88c-0.486,0-0.88-0.394-0.88-0.88V113.68c19.68,28.56,58.88,72,120,84.32v20.72
|
||||||
|
c0,9.323,7.557,16.88,16.88,16.88h32c9.323,0,16.88-7.557,16.88-16.88V198c61.12-12.16,100.32-56,120-84.32L321.52,301.92z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
64
src/assets/img/icons/clipboard.svg
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 438.891 438.891" style="enable-background:new 0 0 438.891 438.891;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M347.968,57.503h-39.706V39.74c0-5.747-6.269-8.359-12.016-8.359h-30.824c-7.314-20.898-25.6-31.347-46.498-31.347
|
||||||
|
c-20.668-0.777-39.467,11.896-46.498,31.347h-30.302c-5.747,0-11.494,2.612-11.494,8.359v17.763H90.923
|
||||||
|
c-23.53,0.251-42.78,18.813-43.886,42.318v299.363c0,22.988,20.898,39.706,43.886,39.706h257.045
|
||||||
|
c22.988,0,43.886-16.718,43.886-39.706V99.822C390.748,76.316,371.498,57.754,347.968,57.503z M151.527,52.279h28.735
|
||||||
|
c5.016-0.612,9.045-4.428,9.927-9.404c3.094-13.474,14.915-23.146,28.735-23.51c13.692,0.415,25.335,10.117,28.212,23.51
|
||||||
|
c0.937,5.148,5.232,9.013,10.449,9.404h29.78v41.796H151.527V52.279z M370.956,399.185c0,11.494-11.494,18.808-22.988,18.808
|
||||||
|
H90.923c-11.494,0-22.988-7.314-22.988-18.808V99.822c1.066-11.964,10.978-21.201,22.988-21.42h39.706v26.645
|
||||||
|
c0.552,5.854,5.622,10.233,11.494,9.927h154.122c5.98,0.327,11.209-3.992,12.016-9.927V78.401h39.706
|
||||||
|
c12.009,0.22,21.922,9.456,22.988,21.42V399.185z"/>
|
||||||
|
<path d="M179.217,233.569c-3.919-4.131-10.425-4.364-14.629-0.522l-33.437,31.869l-14.106-14.629
|
||||||
|
c-3.919-4.131-10.425-4.363-14.629-0.522c-4.047,4.24-4.047,10.911,0,15.151l21.42,21.943c1.854,2.076,4.532,3.224,7.314,3.135
|
||||||
|
c2.756-0.039,5.385-1.166,7.314-3.135l40.751-38.661c4.04-3.706,4.31-9.986,0.603-14.025
|
||||||
|
C179.628,233.962,179.427,233.761,179.217,233.569z"/>
|
||||||
|
<path d="M329.16,256.034H208.997c-5.771,0-10.449,4.678-10.449,10.449s4.678,10.449,10.449,10.449H329.16
|
||||||
|
c5.771,0,10.449-4.678,10.449-10.449S334.931,256.034,329.16,256.034z"/>
|
||||||
|
<path d="M179.217,149.977c-3.919-4.131-10.425-4.364-14.629-0.522l-33.437,31.869l-14.106-14.629
|
||||||
|
c-3.919-4.131-10.425-4.364-14.629-0.522c-4.047,4.24-4.047,10.911,0,15.151l21.42,21.943c1.854,2.076,4.532,3.224,7.314,3.135
|
||||||
|
c2.756-0.039,5.385-1.166,7.314-3.135l40.751-38.661c4.04-3.706,4.31-9.986,0.603-14.025
|
||||||
|
C179.628,150.37,179.427,150.169,179.217,149.977z"/>
|
||||||
|
<path d="M329.16,172.442H208.997c-5.771,0-10.449,4.678-10.449,10.449s4.678,10.449,10.449,10.449H329.16
|
||||||
|
c5.771,0,10.449-4.678,10.449-10.449S334.931,172.442,329.16,172.442z"/>
|
||||||
|
<path d="M179.217,317.16c-3.919-4.131-10.425-4.363-14.629-0.522l-33.437,31.869l-14.106-14.629
|
||||||
|
c-3.919-4.131-10.425-4.363-14.629-0.522c-4.047,4.24-4.047,10.911,0,15.151l21.42,21.943c1.854,2.076,4.532,3.224,7.314,3.135
|
||||||
|
c2.756-0.039,5.385-1.166,7.314-3.135l40.751-38.661c4.04-3.706,4.31-9.986,0.603-14.025
|
||||||
|
C179.628,317.554,179.427,317.353,179.217,317.16z"/>
|
||||||
|
<path d="M329.16,339.626H208.997c-5.771,0-10.449,4.678-10.449,10.449s4.678,10.449,10.449,10.449H329.16
|
||||||
|
c5.771,0,10.449-4.678,10.449-10.449S334.931,339.626,329.16,339.626z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
1
src/assets/img/icons/pin.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m330.274 0-10.607 10.607c-24.914 24.914-28.585 63.132-11.047 91.987l-107.305 72.504-1.856-1.856c-40.939-40.939-107.553-40.94-148.492 0l-10.607 10.606 133.289 133.289-173.649 173.65 21.213 21.213 173.649-173.65 133.29 133.29 10.607-10.607c40.94-40.94 40.939-107.553 0-148.492l-1.856-1.856 72.504-107.305c28.855 17.539 67.073 13.868 91.987-11.047l10.606-10.606zm-3.187 428.148-243.235-243.235c29.104-19.248 68.783-16.069 94.394 9.541l139.3 139.3c25.61 25.611 28.789 65.29 9.541 94.394zm-11.791-139.07-92.374-92.374 105.496-71.281 58.159 58.159zm101.245-117.958-75.66-75.66c-13.828-13.828-16.758-34.491-8.789-51.216l135.665 135.665c-16.725 7.969-37.388 5.039-51.216-8.789z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 829 B |
1
src/assets/img/icons/profile.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="-42 0 512 512.001" xmlns="http://www.w3.org/2000/svg"><path d="m210.351562 246.632812c33.882813 0 63.21875-12.152343 87.195313-36.128906 23.96875-23.972656 36.125-53.304687 36.125-87.191406 0-33.875-12.152344-63.210938-36.128906-87.191406-23.976563-23.96875-53.3125-36.121094-87.191407-36.121094-33.886718 0-63.21875 12.152344-87.191406 36.125s-36.128906 53.308594-36.128906 87.1875c0 33.886719 12.15625 63.222656 36.128906 87.195312 23.980469 23.96875 53.316406 36.125 87.191406 36.125zm-65.972656-189.292968c18.394532-18.394532 39.972656-27.335938 65.972656-27.335938 25.996094 0 47.578126 8.941406 65.976563 27.335938 18.394531 18.398437 27.339844 39.980468 27.339844 65.972656 0 26-8.945313 47.578125-27.339844 65.976562-18.398437 18.398438-39.980469 27.339844-65.976563 27.339844-25.992187 0-47.570312-8.945312-65.972656-27.339844-18.398437-18.394531-27.34375-39.976562-27.34375-65.976562 0-25.992188 8.945313-47.574219 27.34375-65.972656zm0 0"/><path d="m426.128906 393.703125c-.691406-9.976563-2.089844-20.859375-4.148437-32.351563-2.078125-11.578124-4.753907-22.523437-7.957031-32.527343-3.3125-10.339844-7.808594-20.550781-13.375-30.335938-5.769532-10.15625-12.550782-19-20.160157-26.277343-7.957031-7.613282-17.699219-13.734376-28.964843-18.199219-11.226563-4.441407-23.667969-6.691407-36.976563-6.691407-5.226563 0-10.28125 2.144532-20.042969 8.5-6.007812 3.917969-13.035156 8.449219-20.878906 13.460938-6.707031 4.273438-15.792969 8.277344-27.015625 11.902344-10.949219 3.542968-22.066406 5.339844-33.042969 5.339844-10.96875 0-22.085937-1.796876-33.042968-5.339844-11.210938-3.621094-20.300782-7.625-26.996094-11.898438-7.769532-4.964844-14.800782-9.496094-20.898438-13.46875-9.753906-6.355468-14.808594-8.5-20.035156-8.5-13.3125 0-25.75 2.253906-36.972656 6.699219-11.257813 4.457031-21.003906 10.578125-28.96875 18.199219-7.609375 7.28125-14.390625 16.121094-20.15625 26.273437-5.558594 9.785157-10.058594 19.992188-13.371094 30.339844-3.199219 10.003906-5.875 20.945313-7.953125 32.523437-2.0625 11.476563-3.457031 22.363282-4.148437 32.363282-.679688 9.777344-1.023438 19.953125-1.023438 30.234375 0 26.726562 8.496094 48.363281 25.25 64.320312 16.546875 15.746094 38.4375 23.730469 65.066406 23.730469h246.53125c26.621094 0 48.511719-7.984375 65.0625-23.730469 16.757813-15.945312 25.253906-37.589843 25.253906-64.324219-.003906-10.316406-.351562-20.492187-1.035156-30.242187zm-44.90625 72.828125c-10.933594 10.40625-25.449218 15.464844-44.378906 15.464844h-246.527344c-18.933594 0-33.449218-5.058594-44.378906-15.460938-10.722656-10.207031-15.933594-24.140625-15.933594-42.585937 0-9.59375.316406-19.066407.949219-28.160157.617187-8.921874 1.878906-18.722656 3.75-29.136718 1.847656-10.285156 4.199219-19.9375 6.996094-28.675782 2.683593-8.378906 6.34375-16.675781 10.882812-24.667968 4.332031-7.617188 9.316407-14.152344 14.816407-19.417969 5.144531-4.925781 11.628906-8.957031 19.269531-11.980469 7.066406-2.796875 15.007812-4.328125 23.628906-4.558594 1.050781.558594 2.921875 1.625 5.953125 3.601563 6.167969 4.019531 13.277344 8.605469 21.136719 13.625 8.859375 5.648437 20.273437 10.75 33.910156 15.152344 13.941406 4.507812 28.160156 6.796875 42.273437 6.796875 14.113282 0 28.335938-2.289063 42.269532-6.792969 13.648437-4.410156 25.058594-9.507813 33.929687-15.164063 8.042969-5.140624 14.953125-9.59375 21.121094-13.617187 3.03125-1.972656 4.902344-3.042969 5.953125-3.601563 8.625.230469 16.566406 1.761719 23.636719 4.558594 7.636719 3.023438 14.121093 7.058594 19.265625 11.980469 5.5 5.261719 10.484375 11.796875 14.816406 19.421875 4.542969 7.988281 8.207031 16.289062 10.886719 24.660156 2.800781 8.75 5.15625 18.398438 7 28.675782 1.867187 10.433593 3.132812 20.238281 3.75 29.144531v.007812c.636719 9.058594.957031 18.527344.960937 28.148438-.003906 18.449219-5.214844 32.378906-15.9375 42.582031zm0 0"/></svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
1
src/assets/img/icons/quill.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg height="512" viewBox="0 0 128 128" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m121.937 4.826a1.756 1.756 0 0 0 -2.014.924c-.16.328-4.119 8.112-21.461 17.27a1.748 1.748 0 0 0 -.987 1.143 65.867 65.867 0 0 1 -4.388 11.782 24.213 24.213 0 0 1 -2.013-6.92 1.75 1.75 0 0 0 -2.418-1.361c-4.584 1.953-9.573 3.813-14.829 5.527a107.828 107.828 0 0 0 -20.069 8.747 1.748 1.748 0 0 0 -.785.953q-1.186 3.48-2.562 6.574.057-1.032.152-2.194a1.75 1.75 0 0 0 -2.741-1.583c-17.779 12.312-27.467 29.689-30.476 54.622a87.375 87.375 0 0 0 -11.928 15.695 4.87 4.87 0 0 0 1.482 6.513 4.725 4.725 0 0 0 2.554.753h80a1.75 1.75 0 0 0 0-3.5h-75.189a80.458 80.458 0 0 1 10.605-13.582c17.251-.846 57.253-4.33 72.974-18.544a43.377 43.377 0 0 0 3.251-3.273 1.75 1.75 0 0 0 -.942-2.882c-.375-.078-.746-.16-1.115-.243 1.244-.176 2.642-.343 4.183-.481a1.757 1.757 0 0 0 1.284-.75c12.779-18.544 16.457-32.95 18.737-73.4a1.75 1.75 0 0 0 -1.305-1.79zm-113.496 112.942c10.9-18.7 31.07-32.911 52.423-47.954 4.468-3.147 9.536-6.714 14.393-10.281a1.251 1.251 0 0 1 .743-.246 1.282 1.282 0 0 1 .2.016 1.228 1.228 0 0 1 .812.5 1.255 1.255 0 0 1 -.266 1.745c-4.879 3.573-9.96 7.152-14.446 10.31-21.163 14.91-41.153 28.993-51.774 47.293a1.24 1.24 0 0 1 -1.75.417 1.356 1.356 0 0 1 -.335-1.8zm93.642-40.411a62.972 62.972 0 0 0 -10.967 1.9 1.751 1.751 0 0 0 -.083 3.324c1.684.6 3.479 1.146 5.363 1.628-.3.287-.595.565-.9.837-14.012 12.669-50.513 16.385-66.938 17.429 10.112-9.683 22.709-18.56 35.762-27.755 4.5-3.167 9.59-6.756 14.491-10.351a4.764 4.764 0 0 0 1.029-6.621 4.744 4.744 0 0 0 -6.653-1.036c-4.834 3.546-9.884 7.1-14.339 10.242-13.584 9.57-26.694 18.808-37.368 29.137 3.255-20.02 11.408-34.614 25.368-45.36a49.382 49.382 0 0 0 .079 6.122 1.75 1.75 0 0 0 3.244.722 71.093 71.093 0 0 0 5.9-12.924 105.079 105.079 0 0 1 18.846-8.132c4.59-1.5 8.984-3.106 13.093-4.79 1.27 5.832 3.726 8.775 3.843 8.911a1.75 1.75 0 0 0 2.855-.271 65.8 65.8 0 0 0 5.941-14.547c9.846-5.266 15.556-10.162 18.753-13.61-2.24 34.822-5.968 48.463-17.319 65.145z"/><path d="m112.268 40.04a1.748 1.748 0 0 0 -2.034 1.412c-.477 2.653-1 5.073-1.586 7.4a1.751 1.751 0 0 0 1.267 2.126 1.73 1.73 0 0 0 .431.053 1.75 1.75 0 0 0 1.695-1.32c.609-2.4 1.146-4.9 1.639-7.637a1.751 1.751 0 0 0 -1.412-2.034z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/assets/img/me-full.png
Normal file
|
After Width: | Height: | Size: 241 KiB |
BIN
src/assets/img/me-home.jpg
Normal file
|
After Width: | Height: | Size: 142 KiB |
73
src/components/Footer.vue
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<footer class="footer w-full border-t border-gray-200 border-solid">
|
||||||
|
<div class="footer-top flex flex-col items-center justify-center">
|
||||||
|
<div>
|
||||||
|
<ul class="flex text-lg flex-row">
|
||||||
|
<nuxt-link to="/">
|
||||||
|
<li class="hover:bg-red-400 py-1 px-3 mx-4 cursor-pointer duration-500">
|
||||||
|
Accueil
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/about">
|
||||||
|
<li class="hover:bg-orange-400 py-1 px-3 mx-4 cursor-pointer duration-500">
|
||||||
|
A Propos
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/blog">
|
||||||
|
<li class="hover:bg-green-400 py-1 px-3 mx-4 cursor-pointer duration-500">
|
||||||
|
Blog
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/work">
|
||||||
|
<li class="hover:bg-blue-400 py-1 px-3 mx-4 cursor-pointer duration-500">
|
||||||
|
Travail
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/contact">
|
||||||
|
<li class="hover:bg-purple-400 py-1 px-3 mx-4 cursor-pointer duration-500">
|
||||||
|
Contact
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col justify-center my-4">
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-lg">
|
||||||
|
Contactez moi par mail : <span class="text-red-400 hover:text-red-700 duration-300 cursor-pointer">contact@arthurdanjou.fr</span>
|
||||||
|
</p>
|
||||||
|
<div class="text-gray-600 text-xs text-right">
|
||||||
|
(Clique c'est gratuit ❤)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-mg text-center">
|
||||||
|
Retrouvez moi sur : <span>Twitter</span>, <span>Github</span> et <span>Twitch</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center border-t border-solid border-gray-400 py-4 bg-gray-200">
|
||||||
|
<p>
|
||||||
|
Développé et conçu avec ❤ en utilisant <span>NuxtJs</span> & <span>AdonisJs</span> par <span>Arthur DANJOU</span>
|
||||||
|
</p>
|
||||||
|
<p>© Copyright {{date}} - Tous droits réservés</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Footer",
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
date: new Date().getFullYear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.footer {
|
||||||
|
.footer-top {
|
||||||
|
padding: 1rem 15%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
13
src/components/GoToTop.vue
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "GoToTop"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
54
src/components/Header.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<header class="header border-b border-gray-200 border-solid tracking-wider">
|
||||||
|
<div class="header-container flex justify-between items-center h-full">
|
||||||
|
<div class="left text-2xl font-bold cursor-pointer hover:underline duration-500">
|
||||||
|
Arthur Danjou
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<ul class="flex text-xl">
|
||||||
|
<nuxt-link to="/">
|
||||||
|
<li class="hover:bg-red-400 py-1 px-3 mx-2 cursor-pointer duration-500">
|
||||||
|
Accueil
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/about">
|
||||||
|
<li class="hover:bg-orange-400 py-1 px-3 mx-2 cursor-pointer duration-500">
|
||||||
|
A Propos
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/blog">
|
||||||
|
<li class="hover:bg-green-400 py-1 px-3 mx-2 cursor-pointer duration-500">
|
||||||
|
Blog
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/work">
|
||||||
|
<li class="hover:bg-blue-400 py-1 px-3 mx-2 cursor-pointer duration-500">
|
||||||
|
Travail
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="/contact">
|
||||||
|
<li class="hover:bg-purple-400 py-1 px-3 mx-2 cursor-pointer duration-500">
|
||||||
|
Contact
|
||||||
|
</li>
|
||||||
|
</nuxt-link>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Header"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.header {
|
||||||
|
height: 80px;
|
||||||
|
|
||||||
|
.header-container {
|
||||||
|
padding: 0 15%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
src/components/LangSwitcher.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lang-switcher fixed">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "LangSwitcher"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.lang-switcher {
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
BIN
src/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
19
src/templates/layouts/default.vue
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Header />
|
||||||
|
<Nuxt/>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Header from "~/components/Header";
|
||||||
|
import Footer from "~/components/Footer";
|
||||||
|
export default {
|
||||||
|
components: {Footer, Header}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
38
src/templates/layouts/error.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<main class="error">
|
||||||
|
<div v-if="error.statusCode === 404">
|
||||||
|
<div class="mt-16 flex flex-col items-center justify-center">
|
||||||
|
<img src="@/assets/img/404.svg" alt="404 Icon" height="768" width="768" />
|
||||||
|
<nuxt-link to="/" class="home-btn">
|
||||||
|
<div class="py-3 px-6 mb-16 font-bold border-2 border-solid border-red-500 hover:bg-red-500 duration-300 rounded">
|
||||||
|
Revenir à l'accueil
|
||||||
|
<img class="inline arrow-img" src="@/assets/img/icons/arrow-down.svg" alt="Go Down" height="32" width="32" />
|
||||||
|
</div>
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "error",
|
||||||
|
props: ['error']
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.error {
|
||||||
|
.home-btn:hover .arrow-img {
|
||||||
|
transform: translate(3px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-img {
|
||||||
|
transform: translate(3px, -3px);
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
20
src/templates/pages/about.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<main>
|
||||||
|
<div class="flex flex-col items-center mt-32">
|
||||||
|
<h1 class="font-bold text-3xl mr-2 inline">
|
||||||
|
A Propos
|
||||||
|
<img class="inline blog-img" src="@/assets/img/icons/profile.svg" height="40" width="40" alt="Blog Logo" />
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: "about"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
119
src/templates/pages/index.vue
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<template>
|
||||||
|
<main class="index">
|
||||||
|
<section class="banner w-full flex justify-between flex-row-reverse items-center mb-16">
|
||||||
|
<div class="flex justify-center items-center w-1/2">
|
||||||
|
<img src="@/assets/img/computer.png" alt="It's me !" class="me-img" />
|
||||||
|
</div>
|
||||||
|
<div class="title flex justify-center flex-col w-1/2 pr-3">
|
||||||
|
<div class="mb-10">
|
||||||
|
<h1 class="text-5xl text-left font-bold w-3/4">
|
||||||
|
Bonjour, je suis
|
||||||
|
<span class="text-red-700 font-black">Arthur Danjou</span> 👋
|
||||||
|
</h1>
|
||||||
|
<p class="text-3xl my-5 font-semibold">
|
||||||
|
Développeur & étudiant
|
||||||
|
</p>
|
||||||
|
<p class="text-2xl text-justify mb-8 leading-7 text-gray-700">
|
||||||
|
Je suis un jeune développeur autodidacte de 17 ans. J'habite à Paris 🇫🇷. J'adore créer des applications et des logiciels plus ou moins utiles.
|
||||||
|
J'utilise des technologies modernes pour obtenir le meilleur résultat possible ✨
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row justify-around items-center">
|
||||||
|
<nuxt-link to="about">
|
||||||
|
<p class="about-btn rounded-full bg-red-400 hover:bg-red-700 duration-300 px-10 py-1 cursor-pointer">
|
||||||
|
En savoir plus
|
||||||
|
<img class="inline arrow-img" src="@/assets/img/icons/arrow-down.svg" alt="Go Down" height="32" width="32" />
|
||||||
|
</p>
|
||||||
|
</nuxt-link>
|
||||||
|
<nuxt-link to="contact">
|
||||||
|
<p class="rounded-full hover:bg-gray-400 duration-300 px-12 py-1 bg-gray-300 cursor-pointer">
|
||||||
|
Me contacter
|
||||||
|
</p>
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="my-16 border-t border-solid border-black pt-16">
|
||||||
|
<h1 class="font-bold text-3xl mr-2 inline">
|
||||||
|
Mes Articles
|
||||||
|
<img class="inline blog-img" src="@/assets/img/icons/quill.svg" height="40" width="40" alt="Blog Logo" />
|
||||||
|
</h1>
|
||||||
|
<p class="mt-2 mb-8">
|
||||||
|
Parfois, je rédige des articles concernant le développement, ma vie, le design ou bien encore l'apprentissage !
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
TODO Insert blogs request
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="my-16 border-t border-solid border-black pt-16">
|
||||||
|
<h1 class="font-bold text-3xl mr-2 inline">
|
||||||
|
Mon Travail
|
||||||
|
<img class="inline work-img" src="@/assets/img/icons/case.svg" width="32" height="32" alt="Work Logo" />
|
||||||
|
</h1>
|
||||||
|
<p class="mt-2 mb-8">
|
||||||
|
Ayez une vision de mon travail, de mes projets personnels et professionnels ou de mes expérimentations !
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
TODO Insert Works request
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="my-16 border-t border-solid border-black pt-16">
|
||||||
|
<h1 class="font-bold text-3xl mr-2 inline">
|
||||||
|
Mes Services
|
||||||
|
<img class="inline services-img" src="@/assets/img/icons/clipboard.svg" height="32" width="32" alt="Services Logo" />
|
||||||
|
</h1>
|
||||||
|
<p class="mt-2 mb-8">
|
||||||
|
Vous avez une idée révolutionnaire ?
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
TODO Services
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
export default Vue.extend({})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.index {
|
||||||
|
margin-top: 6rem;
|
||||||
|
padding: 0 15%;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
line-height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.me-img {
|
||||||
|
height: 30rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-btn:hover .arrow-img {
|
||||||
|
transform: translate(3px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-img {
|
||||||
|
transform: translate(3px, -3px);
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-img {
|
||||||
|
transform: translate(5px, -10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-img {
|
||||||
|
transform: translate(5px, -6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pin-img {
|
||||||
|
transform: translate(5px, -8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-img {
|
||||||
|
transform: translate(5px, -7px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
825
tailwind.config.js
Normal file
@@ -0,0 +1,825 @@
|
|||||||
|
module.exports = {
|
||||||
|
future: {
|
||||||
|
removeDeprecatedGapUtilities: true,
|
||||||
|
purgeLayersByDefault: true,
|
||||||
|
},
|
||||||
|
purge: [],
|
||||||
|
target: 'relaxed',
|
||||||
|
prefix: '',
|
||||||
|
important: false,
|
||||||
|
separator: ':',
|
||||||
|
theme: {
|
||||||
|
screens: {
|
||||||
|
sm: '640px',
|
||||||
|
md: '768px',
|
||||||
|
lg: '1024px',
|
||||||
|
xl: '1280px',
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
transparent: 'transparent',
|
||||||
|
current: 'currentColor',
|
||||||
|
|
||||||
|
black: '#000',
|
||||||
|
white: '#fff',
|
||||||
|
|
||||||
|
gray: {
|
||||||
|
100: '#f7fafc',
|
||||||
|
200: '#edf2f7',
|
||||||
|
300: '#e2e8f0',
|
||||||
|
400: '#cbd5e0',
|
||||||
|
500: '#a0aec0',
|
||||||
|
600: '#718096',
|
||||||
|
700: '#4a5568',
|
||||||
|
800: '#2d3748',
|
||||||
|
900: '#1a202c',
|
||||||
|
},
|
||||||
|
red: {
|
||||||
|
100: '#fff5f5',
|
||||||
|
200: '#fed7d7',
|
||||||
|
300: '#feb2b2',
|
||||||
|
400: '#fc8181',
|
||||||
|
500: '#f56565',
|
||||||
|
600: '#e53e3e',
|
||||||
|
700: '#c53030',
|
||||||
|
800: '#9b2c2c',
|
||||||
|
900: '#742a2a',
|
||||||
|
},
|
||||||
|
orange: {
|
||||||
|
100: '#fffaf0',
|
||||||
|
200: '#feebc8',
|
||||||
|
300: '#fbd38d',
|
||||||
|
400: '#f6ad55',
|
||||||
|
500: '#ed8936',
|
||||||
|
600: '#dd6b20',
|
||||||
|
700: '#c05621',
|
||||||
|
800: '#9c4221',
|
||||||
|
900: '#7b341e',
|
||||||
|
},
|
||||||
|
yellow: {
|
||||||
|
100: '#fffff0',
|
||||||
|
200: '#fefcbf',
|
||||||
|
300: '#faf089',
|
||||||
|
400: '#f6e05e',
|
||||||
|
500: '#ecc94b',
|
||||||
|
600: '#d69e2e',
|
||||||
|
700: '#b7791f',
|
||||||
|
800: '#975a16',
|
||||||
|
900: '#744210',
|
||||||
|
},
|
||||||
|
green: {
|
||||||
|
100: '#f0fff4',
|
||||||
|
200: '#c6f6d5',
|
||||||
|
300: '#9ae6b4',
|
||||||
|
400: '#68d391',
|
||||||
|
500: '#48bb78',
|
||||||
|
600: '#38a169',
|
||||||
|
700: '#2f855a',
|
||||||
|
800: '#276749',
|
||||||
|
900: '#22543d',
|
||||||
|
},
|
||||||
|
teal: {
|
||||||
|
100: '#e6fffa',
|
||||||
|
200: '#b2f5ea',
|
||||||
|
300: '#81e6d9',
|
||||||
|
400: '#4fd1c5',
|
||||||
|
500: '#38b2ac',
|
||||||
|
600: '#319795',
|
||||||
|
700: '#2c7a7b',
|
||||||
|
800: '#285e61',
|
||||||
|
900: '#234e52',
|
||||||
|
},
|
||||||
|
blue: {
|
||||||
|
100: '#ebf8ff',
|
||||||
|
200: '#bee3f8',
|
||||||
|
300: '#90cdf4',
|
||||||
|
400: '#63b3ed',
|
||||||
|
500: '#4299e1',
|
||||||
|
600: '#3182ce',
|
||||||
|
700: '#2b6cb0',
|
||||||
|
800: '#2c5282',
|
||||||
|
900: '#2a4365',
|
||||||
|
},
|
||||||
|
indigo: {
|
||||||
|
100: '#ebf4ff',
|
||||||
|
200: '#c3dafe',
|
||||||
|
300: '#a3bffa',
|
||||||
|
400: '#7f9cf5',
|
||||||
|
500: '#667eea',
|
||||||
|
600: '#5a67d8',
|
||||||
|
700: '#4c51bf',
|
||||||
|
800: '#434190',
|
||||||
|
900: '#3c366b',
|
||||||
|
},
|
||||||
|
purple: {
|
||||||
|
100: '#faf5ff',
|
||||||
|
200: '#e9d8fd',
|
||||||
|
300: '#d6bcfa',
|
||||||
|
400: '#b794f4',
|
||||||
|
500: '#9f7aea',
|
||||||
|
600: '#805ad5',
|
||||||
|
700: '#6b46c1',
|
||||||
|
800: '#553c9a',
|
||||||
|
900: '#44337a',
|
||||||
|
},
|
||||||
|
pink: {
|
||||||
|
100: '#fff5f7',
|
||||||
|
200: '#fed7e2',
|
||||||
|
300: '#fbb6ce',
|
||||||
|
400: '#f687b3',
|
||||||
|
500: '#ed64a6',
|
||||||
|
600: '#d53f8c',
|
||||||
|
700: '#b83280',
|
||||||
|
800: '#97266d',
|
||||||
|
900: '#702459',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
px: '1px',
|
||||||
|
'0': '0',
|
||||||
|
'1': '0.25rem',
|
||||||
|
'2': '0.5rem',
|
||||||
|
'3': '0.75rem',
|
||||||
|
'4': '1rem',
|
||||||
|
'5': '1.25rem',
|
||||||
|
'6': '1.5rem',
|
||||||
|
'8': '2rem',
|
||||||
|
'10': '2.5rem',
|
||||||
|
'12': '3rem',
|
||||||
|
'16': '4rem',
|
||||||
|
'20': '5rem',
|
||||||
|
'24': '6rem',
|
||||||
|
'32': '8rem',
|
||||||
|
'40': '10rem',
|
||||||
|
'48': '12rem',
|
||||||
|
'56': '14rem',
|
||||||
|
'64': '16rem',
|
||||||
|
'1/2': '50%',
|
||||||
|
'1/3': '33.333333%',
|
||||||
|
'2/3': '66.666667%',
|
||||||
|
'1/4': '25%',
|
||||||
|
'2/4': '50%',
|
||||||
|
'3/4': '75%',
|
||||||
|
'1/5': '20%',
|
||||||
|
'2/5': '40%',
|
||||||
|
'3/5': '60%',
|
||||||
|
'4/5': '80%',
|
||||||
|
'1/6': '16.666667%',
|
||||||
|
'2/6': '33.333333%',
|
||||||
|
'3/6': '50%',
|
||||||
|
'4/6': '66.666667%',
|
||||||
|
'5/6': '83.333333%',
|
||||||
|
'1/12': '8.333333%',
|
||||||
|
'2/12': '16.666667%',
|
||||||
|
'3/12': '25%',
|
||||||
|
'4/12': '33.333333%',
|
||||||
|
'5/12': '41.666667%',
|
||||||
|
'6/12': '50%',
|
||||||
|
'7/12': '58.333333%',
|
||||||
|
'8/12': '66.666667%',
|
||||||
|
'9/12': '75%',
|
||||||
|
'10/12': '83.333333%',
|
||||||
|
'11/12': '91.666667%',
|
||||||
|
},
|
||||||
|
backgroundColor: theme => theme('colors'),
|
||||||
|
backgroundImage: {
|
||||||
|
none: 'none',
|
||||||
|
'gradient-to-t': 'linear-gradient(to top, var(--gradient-color-stops))',
|
||||||
|
'gradient-to-tr': 'linear-gradient(to top right, var(--gradient-color-stops))',
|
||||||
|
'gradient-to-r': 'linear-gradient(to right, var(--gradient-color-stops))',
|
||||||
|
'gradient-to-br': 'linear-gradient(to bottom right, var(--gradient-color-stops))',
|
||||||
|
'gradient-to-b': 'linear-gradient(to bottom, var(--gradient-color-stops))',
|
||||||
|
'gradient-to-bl': 'linear-gradient(to bottom left, var(--gradient-color-stops))',
|
||||||
|
'gradient-to-l': 'linear-gradient(to left, var(--gradient-color-stops))',
|
||||||
|
'gradient-to-tl': 'linear-gradient(to top left, var(--gradient-color-stops))',
|
||||||
|
},
|
||||||
|
gradientColorStops: theme => theme('colors'),
|
||||||
|
backgroundOpacity: theme => theme('opacity'),
|
||||||
|
backgroundPosition: {
|
||||||
|
bottom: 'bottom',
|
||||||
|
center: 'center',
|
||||||
|
left: 'left',
|
||||||
|
'left-bottom': 'left bottom',
|
||||||
|
'left-top': 'left top',
|
||||||
|
right: 'right',
|
||||||
|
'right-bottom': 'right bottom',
|
||||||
|
'right-top': 'right top',
|
||||||
|
top: 'top',
|
||||||
|
},
|
||||||
|
backgroundSize: {
|
||||||
|
auto: 'auto',
|
||||||
|
cover: 'cover',
|
||||||
|
contain: 'contain',
|
||||||
|
},
|
||||||
|
borderColor: theme => ({
|
||||||
|
...theme('colors'),
|
||||||
|
default: theme('colors.gray.300', 'currentColor'),
|
||||||
|
}),
|
||||||
|
borderOpacity: theme => theme('opacity'),
|
||||||
|
borderRadius: {
|
||||||
|
none: '0',
|
||||||
|
sm: '0.125rem',
|
||||||
|
default: '0.25rem',
|
||||||
|
md: '0.375rem',
|
||||||
|
lg: '0.5rem',
|
||||||
|
xl: '0.75rem',
|
||||||
|
'2xl': '1rem',
|
||||||
|
'3xl': '1.5rem',
|
||||||
|
full: '9999px',
|
||||||
|
},
|
||||||
|
borderWidth: {
|
||||||
|
default: '1px',
|
||||||
|
'0': '0',
|
||||||
|
'2': '2px',
|
||||||
|
'4': '4px',
|
||||||
|
'8': '8px',
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
xs: '0 0 0 1px rgba(0, 0, 0, 0.05)',
|
||||||
|
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
||||||
|
default: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
|
||||||
|
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
|
||||||
|
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
||||||
|
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
||||||
|
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
||||||
|
inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
|
||||||
|
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
|
||||||
|
none: 'none',
|
||||||
|
},
|
||||||
|
container: {},
|
||||||
|
cursor: {
|
||||||
|
auto: 'auto',
|
||||||
|
default: 'default',
|
||||||
|
pointer: 'pointer',
|
||||||
|
wait: 'wait',
|
||||||
|
text: 'text',
|
||||||
|
move: 'move',
|
||||||
|
'not-allowed': 'not-allowed',
|
||||||
|
},
|
||||||
|
divideColor: theme => theme('borderColor'),
|
||||||
|
divideOpacity: theme => theme('borderOpacity'),
|
||||||
|
divideWidth: theme => theme('borderWidth'),
|
||||||
|
fill: {
|
||||||
|
current: 'currentColor',
|
||||||
|
},
|
||||||
|
flex: {
|
||||||
|
'1': '1 1 0%',
|
||||||
|
auto: '1 1 auto',
|
||||||
|
initial: '0 1 auto',
|
||||||
|
none: 'none',
|
||||||
|
},
|
||||||
|
flexGrow: {
|
||||||
|
'0': '0',
|
||||||
|
default: '1',
|
||||||
|
},
|
||||||
|
flexShrink: {
|
||||||
|
'0': '0',
|
||||||
|
default: '1',
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: [
|
||||||
|
'raleway',
|
||||||
|
'system-ui',
|
||||||
|
'-apple-system',
|
||||||
|
'BlinkMacSystemFont',
|
||||||
|
'"Segoe UI"',
|
||||||
|
'Roboto',
|
||||||
|
'"Helvetica Neue"',
|
||||||
|
'Arial',
|
||||||
|
'"Noto Sans"',
|
||||||
|
'sans-serif',
|
||||||
|
'"Apple Color Emoji"',
|
||||||
|
'"Segoe UI Emoji"',
|
||||||
|
'"Segoe UI Symbol"',
|
||||||
|
'"Noto Color Emoji"',
|
||||||
|
],
|
||||||
|
serif: ['Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'],
|
||||||
|
mono: ['Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace'],
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
xs: '0.75rem',
|
||||||
|
sm: '0.875rem',
|
||||||
|
base: '1rem',
|
||||||
|
lg: '1.125rem',
|
||||||
|
xl: '1.25rem',
|
||||||
|
'2xl': '1.5rem',
|
||||||
|
'3xl': '1.875rem',
|
||||||
|
'4xl': '2.25rem',
|
||||||
|
'5xl': '3rem',
|
||||||
|
'6xl': '4rem',
|
||||||
|
},
|
||||||
|
fontWeight: {
|
||||||
|
hairline: '100',
|
||||||
|
thin: '200',
|
||||||
|
light: '300',
|
||||||
|
normal: '400',
|
||||||
|
medium: '500',
|
||||||
|
semibold: '600',
|
||||||
|
bold: '700',
|
||||||
|
extrabold: '800',
|
||||||
|
black: '900',
|
||||||
|
},
|
||||||
|
height: theme => ({
|
||||||
|
auto: 'auto',
|
||||||
|
...theme('spacing'),
|
||||||
|
full: '100%',
|
||||||
|
screen: '100vh',
|
||||||
|
}),
|
||||||
|
inset: {
|
||||||
|
'0': '0',
|
||||||
|
auto: 'auto',
|
||||||
|
},
|
||||||
|
letterSpacing: {
|
||||||
|
tighter: '-0.05em',
|
||||||
|
tight: '-0.025em',
|
||||||
|
normal: '0',
|
||||||
|
wide: '0.025em',
|
||||||
|
wider: '0.05em',
|
||||||
|
widest: '0.1em',
|
||||||
|
},
|
||||||
|
lineHeight: {
|
||||||
|
none: '1',
|
||||||
|
tight: '1.25',
|
||||||
|
snug: '1.375',
|
||||||
|
normal: '1.5',
|
||||||
|
relaxed: '1.625',
|
||||||
|
loose: '2',
|
||||||
|
'3': '.75rem',
|
||||||
|
'4': '1rem',
|
||||||
|
'5': '1.25rem',
|
||||||
|
'6': '1.5rem',
|
||||||
|
'7': '1.75rem',
|
||||||
|
'8': '2rem',
|
||||||
|
'9': '2.25rem',
|
||||||
|
'10': '2.5rem',
|
||||||
|
},
|
||||||
|
listStyleType: {
|
||||||
|
none: 'none',
|
||||||
|
disc: 'disc',
|
||||||
|
decimal: 'decimal',
|
||||||
|
},
|
||||||
|
margin: (theme, { negative }) => ({
|
||||||
|
auto: 'auto',
|
||||||
|
...theme('spacing'),
|
||||||
|
...negative(theme('spacing')),
|
||||||
|
}),
|
||||||
|
maxHeight: {
|
||||||
|
full: '100%',
|
||||||
|
screen: '100vh',
|
||||||
|
},
|
||||||
|
maxWidth: (theme, { breakpoints }) => ({
|
||||||
|
none: 'none',
|
||||||
|
xs: '20rem',
|
||||||
|
sm: '24rem',
|
||||||
|
md: '28rem',
|
||||||
|
lg: '32rem',
|
||||||
|
xl: '36rem',
|
||||||
|
'2xl': '42rem',
|
||||||
|
'3xl': '48rem',
|
||||||
|
'4xl': '56rem',
|
||||||
|
'5xl': '64rem',
|
||||||
|
'6xl': '72rem',
|
||||||
|
full: '100%',
|
||||||
|
...breakpoints(theme('screens')),
|
||||||
|
}),
|
||||||
|
minHeight: {
|
||||||
|
'0': '0',
|
||||||
|
full: '100%',
|
||||||
|
screen: '100vh',
|
||||||
|
},
|
||||||
|
minWidth: {
|
||||||
|
'0': '0',
|
||||||
|
full: '100%',
|
||||||
|
},
|
||||||
|
objectPosition: {
|
||||||
|
bottom: 'bottom',
|
||||||
|
center: 'center',
|
||||||
|
left: 'left',
|
||||||
|
'left-bottom': 'left bottom',
|
||||||
|
'left-top': 'left top',
|
||||||
|
right: 'right',
|
||||||
|
'right-bottom': 'right bottom',
|
||||||
|
'right-top': 'right top',
|
||||||
|
top: 'top',
|
||||||
|
},
|
||||||
|
opacity: {
|
||||||
|
'0': '0',
|
||||||
|
'25': '0.25',
|
||||||
|
'50': '0.5',
|
||||||
|
'75': '0.75',
|
||||||
|
'100': '1',
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
first: '-9999',
|
||||||
|
last: '9999',
|
||||||
|
none: '0',
|
||||||
|
'1': '1',
|
||||||
|
'2': '2',
|
||||||
|
'3': '3',
|
||||||
|
'4': '4',
|
||||||
|
'5': '5',
|
||||||
|
'6': '6',
|
||||||
|
'7': '7',
|
||||||
|
'8': '8',
|
||||||
|
'9': '9',
|
||||||
|
'10': '10',
|
||||||
|
'11': '11',
|
||||||
|
'12': '12',
|
||||||
|
},
|
||||||
|
outline: {
|
||||||
|
none: ['2px solid transparent', '2px'],
|
||||||
|
white: ['2px dotted white', '2px'],
|
||||||
|
black: ['2px dotted black', '2px'],
|
||||||
|
},
|
||||||
|
padding: theme => theme('spacing'),
|
||||||
|
placeholderColor: theme => theme('colors'),
|
||||||
|
placeholderOpacity: theme => theme('opacity'),
|
||||||
|
space: (theme, { negative }) => ({
|
||||||
|
...theme('spacing'),
|
||||||
|
...negative(theme('spacing')),
|
||||||
|
}),
|
||||||
|
stroke: {
|
||||||
|
current: 'currentColor',
|
||||||
|
},
|
||||||
|
strokeWidth: {
|
||||||
|
'0': '0',
|
||||||
|
'1': '1',
|
||||||
|
'2': '2',
|
||||||
|
},
|
||||||
|
textColor: theme => theme('colors'),
|
||||||
|
textOpacity: theme => theme('opacity'),
|
||||||
|
width: theme => ({
|
||||||
|
auto: 'auto',
|
||||||
|
...theme('spacing'),
|
||||||
|
full: '100%',
|
||||||
|
screen: '100vw',
|
||||||
|
}),
|
||||||
|
zIndex: {
|
||||||
|
auto: 'auto',
|
||||||
|
'0': '0',
|
||||||
|
'10': '10',
|
||||||
|
'20': '20',
|
||||||
|
'30': '30',
|
||||||
|
'40': '40',
|
||||||
|
'50': '50',
|
||||||
|
},
|
||||||
|
gap: theme => theme('spacing'),
|
||||||
|
gridTemplateColumns: {
|
||||||
|
none: 'none',
|
||||||
|
'1': 'repeat(1, minmax(0, 1fr))',
|
||||||
|
'2': 'repeat(2, minmax(0, 1fr))',
|
||||||
|
'3': 'repeat(3, minmax(0, 1fr))',
|
||||||
|
'4': 'repeat(4, minmax(0, 1fr))',
|
||||||
|
'5': 'repeat(5, minmax(0, 1fr))',
|
||||||
|
'6': 'repeat(6, minmax(0, 1fr))',
|
||||||
|
'7': 'repeat(7, minmax(0, 1fr))',
|
||||||
|
'8': 'repeat(8, minmax(0, 1fr))',
|
||||||
|
'9': 'repeat(9, minmax(0, 1fr))',
|
||||||
|
'10': 'repeat(10, minmax(0, 1fr))',
|
||||||
|
'11': 'repeat(11, minmax(0, 1fr))',
|
||||||
|
'12': 'repeat(12, minmax(0, 1fr))',
|
||||||
|
},
|
||||||
|
gridAutoColumns: {
|
||||||
|
auto: 'auto',
|
||||||
|
min: 'min-content',
|
||||||
|
max: 'max-content',
|
||||||
|
fr: 'minmax(0, 1fr)',
|
||||||
|
},
|
||||||
|
gridColumn: {
|
||||||
|
auto: 'auto',
|
||||||
|
'span-1': 'span 1 / span 1',
|
||||||
|
'span-2': 'span 2 / span 2',
|
||||||
|
'span-3': 'span 3 / span 3',
|
||||||
|
'span-4': 'span 4 / span 4',
|
||||||
|
'span-5': 'span 5 / span 5',
|
||||||
|
'span-6': 'span 6 / span 6',
|
||||||
|
'span-7': 'span 7 / span 7',
|
||||||
|
'span-8': 'span 8 / span 8',
|
||||||
|
'span-9': 'span 9 / span 9',
|
||||||
|
'span-10': 'span 10 / span 10',
|
||||||
|
'span-11': 'span 11 / span 11',
|
||||||
|
'span-12': 'span 12 / span 12',
|
||||||
|
'span-full': '1 / -1',
|
||||||
|
},
|
||||||
|
gridColumnStart: {
|
||||||
|
auto: 'auto',
|
||||||
|
'1': '1',
|
||||||
|
'2': '2',
|
||||||
|
'3': '3',
|
||||||
|
'4': '4',
|
||||||
|
'5': '5',
|
||||||
|
'6': '6',
|
||||||
|
'7': '7',
|
||||||
|
'8': '8',
|
||||||
|
'9': '9',
|
||||||
|
'10': '10',
|
||||||
|
'11': '11',
|
||||||
|
'12': '12',
|
||||||
|
'13': '13',
|
||||||
|
},
|
||||||
|
gridColumnEnd: {
|
||||||
|
auto: 'auto',
|
||||||
|
'1': '1',
|
||||||
|
'2': '2',
|
||||||
|
'3': '3',
|
||||||
|
'4': '4',
|
||||||
|
'5': '5',
|
||||||
|
'6': '6',
|
||||||
|
'7': '7',
|
||||||
|
'8': '8',
|
||||||
|
'9': '9',
|
||||||
|
'10': '10',
|
||||||
|
'11': '11',
|
||||||
|
'12': '12',
|
||||||
|
'13': '13',
|
||||||
|
},
|
||||||
|
gridTemplateRows: {
|
||||||
|
none: 'none',
|
||||||
|
'1': 'repeat(1, minmax(0, 1fr))',
|
||||||
|
'2': 'repeat(2, minmax(0, 1fr))',
|
||||||
|
'3': 'repeat(3, minmax(0, 1fr))',
|
||||||
|
'4': 'repeat(4, minmax(0, 1fr))',
|
||||||
|
'5': 'repeat(5, minmax(0, 1fr))',
|
||||||
|
'6': 'repeat(6, minmax(0, 1fr))',
|
||||||
|
},
|
||||||
|
gridAutoRows: {
|
||||||
|
auto: 'auto',
|
||||||
|
min: 'min-content',
|
||||||
|
max: 'max-content',
|
||||||
|
fr: 'minmax(0, 1fr)',
|
||||||
|
},
|
||||||
|
gridRow: {
|
||||||
|
auto: 'auto',
|
||||||
|
'span-1': 'span 1 / span 1',
|
||||||
|
'span-2': 'span 2 / span 2',
|
||||||
|
'span-3': 'span 3 / span 3',
|
||||||
|
'span-4': 'span 4 / span 4',
|
||||||
|
'span-5': 'span 5 / span 5',
|
||||||
|
'span-6': 'span 6 / span 6',
|
||||||
|
'span-full': '1 / -1',
|
||||||
|
},
|
||||||
|
gridRowStart: {
|
||||||
|
auto: 'auto',
|
||||||
|
'1': '1',
|
||||||
|
'2': '2',
|
||||||
|
'3': '3',
|
||||||
|
'4': '4',
|
||||||
|
'5': '5',
|
||||||
|
'6': '6',
|
||||||
|
'7': '7',
|
||||||
|
},
|
||||||
|
gridRowEnd: {
|
||||||
|
auto: 'auto',
|
||||||
|
'1': '1',
|
||||||
|
'2': '2',
|
||||||
|
'3': '3',
|
||||||
|
'4': '4',
|
||||||
|
'5': '5',
|
||||||
|
'6': '6',
|
||||||
|
'7': '7',
|
||||||
|
},
|
||||||
|
transformOrigin: {
|
||||||
|
center: 'center',
|
||||||
|
top: 'top',
|
||||||
|
'top-right': 'top right',
|
||||||
|
right: 'right',
|
||||||
|
'bottom-right': 'bottom right',
|
||||||
|
bottom: 'bottom',
|
||||||
|
'bottom-left': 'bottom left',
|
||||||
|
left: 'left',
|
||||||
|
'top-left': 'top left',
|
||||||
|
},
|
||||||
|
scale: {
|
||||||
|
'0': '0',
|
||||||
|
'50': '.5',
|
||||||
|
'75': '.75',
|
||||||
|
'90': '.9',
|
||||||
|
'95': '.95',
|
||||||
|
'100': '1',
|
||||||
|
'105': '1.05',
|
||||||
|
'110': '1.1',
|
||||||
|
'125': '1.25',
|
||||||
|
'150': '1.5',
|
||||||
|
},
|
||||||
|
rotate: {
|
||||||
|
'-180': '-180deg',
|
||||||
|
'-90': '-90deg',
|
||||||
|
'-45': '-45deg',
|
||||||
|
'-12': '-12deg',
|
||||||
|
'-6': '-6deg',
|
||||||
|
'-3': '-3deg',
|
||||||
|
'-2': '-2deg',
|
||||||
|
'-1': '-1deg',
|
||||||
|
'0': '0',
|
||||||
|
'1': '1deg',
|
||||||
|
'2': '2deg',
|
||||||
|
'3': '3deg',
|
||||||
|
'6': '6deg',
|
||||||
|
'12': '12deg',
|
||||||
|
'45': '45deg',
|
||||||
|
'90': '90deg',
|
||||||
|
'180': '180deg',
|
||||||
|
},
|
||||||
|
translate: (theme, { negative }) => ({
|
||||||
|
...theme('spacing'),
|
||||||
|
...negative(theme('spacing')),
|
||||||
|
'-full': '-100%',
|
||||||
|
'-1/2': '-50%',
|
||||||
|
'1/2': '50%',
|
||||||
|
full: '100%',
|
||||||
|
}),
|
||||||
|
skew: {
|
||||||
|
'-12': '-12deg',
|
||||||
|
'-6': '-6deg',
|
||||||
|
'-3': '-3deg',
|
||||||
|
'-2': '-2deg',
|
||||||
|
'-1': '-1deg',
|
||||||
|
'0': '0',
|
||||||
|
'1': '1deg',
|
||||||
|
'2': '2deg',
|
||||||
|
'3': '3deg',
|
||||||
|
'6': '6deg',
|
||||||
|
'12': '12deg',
|
||||||
|
},
|
||||||
|
transitionProperty: {
|
||||||
|
none: 'none',
|
||||||
|
all: 'all',
|
||||||
|
default: 'background-color, border-color, color, fill, stroke, opacity, box-shadow, transform',
|
||||||
|
colors: 'background-color, border-color, color, fill, stroke',
|
||||||
|
opacity: 'opacity',
|
||||||
|
shadow: 'box-shadow',
|
||||||
|
transform: 'transform',
|
||||||
|
},
|
||||||
|
transitionTimingFunction: {
|
||||||
|
linear: 'linear',
|
||||||
|
in: 'cubic-bezier(0.4, 0, 1, 1)',
|
||||||
|
out: 'cubic-bezier(0, 0, 0.2, 1)',
|
||||||
|
'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||||
|
},
|
||||||
|
transitionDuration: {
|
||||||
|
'75': '75ms',
|
||||||
|
'100': '100ms',
|
||||||
|
'150': '150ms',
|
||||||
|
'200': '200ms',
|
||||||
|
'300': '300ms',
|
||||||
|
'500': '500ms',
|
||||||
|
'700': '700ms',
|
||||||
|
'1000': '1000ms',
|
||||||
|
},
|
||||||
|
transitionDelay: {
|
||||||
|
'75': '75ms',
|
||||||
|
'100': '100ms',
|
||||||
|
'150': '150ms',
|
||||||
|
'200': '200ms',
|
||||||
|
'300': '300ms',
|
||||||
|
'500': '500ms',
|
||||||
|
'700': '700ms',
|
||||||
|
'1000': '1000ms',
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
none: 'none',
|
||||||
|
spin: 'spin 1s linear infinite',
|
||||||
|
ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite',
|
||||||
|
pulse: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||||
|
bounce: 'bounce 1s infinite',
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
spin: {
|
||||||
|
to: { transform: 'rotate(360deg)' },
|
||||||
|
},
|
||||||
|
ping: {
|
||||||
|
'75%, 100%': { transform: 'scale(2)', opacity: '0' },
|
||||||
|
},
|
||||||
|
pulse: {
|
||||||
|
'50%': { opacity: '.5' },
|
||||||
|
},
|
||||||
|
bounce: {
|
||||||
|
'0%, 100%': {
|
||||||
|
transform: 'translateY(-25%)',
|
||||||
|
animationTimingFunction: 'cubic-bezier(0.8,0,1,1)',
|
||||||
|
},
|
||||||
|
'50%': {
|
||||||
|
transform: 'none',
|
||||||
|
animationTimingFunction: 'cubic-bezier(0,0,0.2,1)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
accessibility: ['responsive', 'focus'],
|
||||||
|
alignContent: ['responsive'],
|
||||||
|
alignItems: ['responsive'],
|
||||||
|
alignSelf: ['responsive'],
|
||||||
|
appearance: ['responsive'],
|
||||||
|
backgroundAttachment: ['responsive'],
|
||||||
|
backgroundClip: ['responsive'],
|
||||||
|
backgroundColor: ['responsive', 'hover', 'focus'],
|
||||||
|
backgroundImage: ['responsive'],
|
||||||
|
gradientColorStops: ['responsive', 'hover', 'focus'],
|
||||||
|
backgroundOpacity: ['responsive', 'hover', 'focus'],
|
||||||
|
backgroundPosition: ['responsive'],
|
||||||
|
backgroundRepeat: ['responsive'],
|
||||||
|
backgroundSize: ['responsive'],
|
||||||
|
borderCollapse: ['responsive'],
|
||||||
|
borderColor: ['responsive', 'hover', 'focus'],
|
||||||
|
borderOpacity: ['responsive', 'hover', 'focus'],
|
||||||
|
borderRadius: ['responsive'],
|
||||||
|
borderStyle: ['responsive'],
|
||||||
|
borderWidth: ['responsive'],
|
||||||
|
boxShadow: ['responsive', 'hover', 'focus'],
|
||||||
|
boxSizing: ['responsive'],
|
||||||
|
container: ['responsive'],
|
||||||
|
cursor: ['responsive'],
|
||||||
|
display: ['responsive'],
|
||||||
|
divideColor: ['responsive'],
|
||||||
|
divideOpacity: ['responsive'],
|
||||||
|
divideStyle: ['responsive'],
|
||||||
|
divideWidth: ['responsive'],
|
||||||
|
fill: ['responsive'],
|
||||||
|
flex: ['responsive'],
|
||||||
|
flexDirection: ['responsive'],
|
||||||
|
flexGrow: ['responsive'],
|
||||||
|
flexShrink: ['responsive'],
|
||||||
|
flexWrap: ['responsive'],
|
||||||
|
float: ['responsive'],
|
||||||
|
clear: ['responsive'],
|
||||||
|
fontFamily: ['responsive'],
|
||||||
|
fontSize: ['responsive'],
|
||||||
|
fontSmoothing: ['responsive'],
|
||||||
|
fontVariantNumeric: ['responsive'],
|
||||||
|
fontStyle: ['responsive'],
|
||||||
|
fontWeight: ['responsive', 'hover', 'focus'],
|
||||||
|
height: ['responsive'],
|
||||||
|
inset: ['responsive'],
|
||||||
|
justifyContent: ['responsive'],
|
||||||
|
justifyItems: ['responsive'],
|
||||||
|
justifySelf: ['responsive'],
|
||||||
|
letterSpacing: ['responsive'],
|
||||||
|
lineHeight: ['responsive'],
|
||||||
|
listStylePosition: ['responsive'],
|
||||||
|
listStyleType: ['responsive'],
|
||||||
|
margin: ['responsive'],
|
||||||
|
maxHeight: ['responsive'],
|
||||||
|
maxWidth: ['responsive'],
|
||||||
|
minHeight: ['responsive'],
|
||||||
|
minWidth: ['responsive'],
|
||||||
|
objectFit: ['responsive'],
|
||||||
|
objectPosition: ['responsive'],
|
||||||
|
opacity: ['responsive', 'hover', 'focus'],
|
||||||
|
order: ['responsive'],
|
||||||
|
outline: ['responsive', 'focus'],
|
||||||
|
overflow: ['responsive'],
|
||||||
|
overscrollBehavior: ['responsive'],
|
||||||
|
padding: ['responsive'],
|
||||||
|
placeContent: ['responsive'],
|
||||||
|
placeItems: ['responsive'],
|
||||||
|
placeSelf: ['responsive'],
|
||||||
|
placeholderColor: ['responsive', 'focus'],
|
||||||
|
placeholderOpacity: ['responsive', 'focus'],
|
||||||
|
pointerEvents: ['responsive'],
|
||||||
|
position: ['responsive'],
|
||||||
|
resize: ['responsive'],
|
||||||
|
space: ['responsive'],
|
||||||
|
stroke: ['responsive'],
|
||||||
|
strokeWidth: ['responsive'],
|
||||||
|
tableLayout: ['responsive'],
|
||||||
|
textAlign: ['responsive'],
|
||||||
|
textColor: ['responsive', 'hover', 'focus'],
|
||||||
|
textOpacity: ['responsive', 'hover', 'focus'],
|
||||||
|
textDecoration: ['responsive', 'hover', 'focus'],
|
||||||
|
textTransform: ['responsive'],
|
||||||
|
userSelect: ['responsive'],
|
||||||
|
verticalAlign: ['responsive'],
|
||||||
|
visibility: ['responsive'],
|
||||||
|
whitespace: ['responsive'],
|
||||||
|
width: ['responsive'],
|
||||||
|
wordBreak: ['responsive'],
|
||||||
|
zIndex: ['responsive'],
|
||||||
|
gap: ['responsive'],
|
||||||
|
gridAutoFlow: ['responsive'],
|
||||||
|
gridTemplateColumns: ['responsive'],
|
||||||
|
gridAutoColumns: ['responsive'],
|
||||||
|
gridColumn: ['responsive'],
|
||||||
|
gridColumnStart: ['responsive'],
|
||||||
|
gridColumnEnd: ['responsive'],
|
||||||
|
gridTemplateRows: ['responsive'],
|
||||||
|
gridAutoRows: ['responsive'],
|
||||||
|
gridRow: ['responsive'],
|
||||||
|
gridRowStart: ['responsive'],
|
||||||
|
gridRowEnd: ['responsive'],
|
||||||
|
transform: ['responsive'],
|
||||||
|
transformOrigin: ['responsive'],
|
||||||
|
scale: ['responsive', 'hover', 'focus'],
|
||||||
|
rotate: ['responsive', 'hover', 'focus'],
|
||||||
|
translate: ['responsive', 'hover', 'focus'],
|
||||||
|
skew: ['responsive', 'hover', 'focus'],
|
||||||
|
transitionProperty: ['responsive'],
|
||||||
|
transitionTimingFunction: ['responsive'],
|
||||||
|
transitionDuration: ['responsive'],
|
||||||
|
transitionDelay: ['responsive'],
|
||||||
|
animation: ['responsive'],
|
||||||
|
},
|
||||||
|
corePlugins: {
|
||||||
|
container: false
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
37
tsconfig.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2018",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"lib": [
|
||||||
|
"ESNext",
|
||||||
|
"ESNext.AsyncIterable",
|
||||||
|
"DOM"
|
||||||
|
],
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"~/*": [
|
||||||
|
"./*"
|
||||||
|
],
|
||||||
|
"@/*": [
|
||||||
|
"./*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"types": [
|
||||||
|
"@types/node",
|
||||||
|
"@nuxt/types",
|
||||||
|
"@nuxtjs/axios"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
".nuxt",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
4
vue-shim.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue
|
||||||
|
}
|
||||||