mirror of
https://github.com/em-squared/5e-drs.git
synced 2025-10-29 12:44:20 +00:00
search autocomplete
This commit is contained in:
parent
d47ad5e88d
commit
eccc40a123
15 changed files with 1094 additions and 9924 deletions
23
docs/.vuepress/store/index.js
Normal file
23
docs/.vuepress/store/index.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
drawer: true,
|
||||
},
|
||||
getters: {
|
||||
drawer: state => state.drawer,
|
||||
},
|
||||
actions: {
|
||||
updateDrawer: ({ commit }, payload) => {
|
||||
commit('setDrawer', payload)
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setDrawer: (state, payload) => {
|
||||
state.drawer = payload
|
||||
},
|
||||
},
|
||||
})
|
||||
48
docs/.vuepress/theme/components/Navbar.vue
Normal file
48
docs/.vuepress/theme/components/Navbar.vue
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<v-app-bar :clipped-left="$vuetify.breakpoint.lgAndUp" app color="blue darken-3" dark>
|
||||
<v-app-bar-nav-icon @click.stop="setDrawer" />
|
||||
<v-toolbar-title class="ml-0 mr-4 pl-4">
|
||||
<v-btn class="hidden-sm-and-down site-title" text link :to="{ path: '/' }">{{ $site.title }}</v-btn>
|
||||
</v-toolbar-title>
|
||||
<SRDSearchBox v-if="$site.themeConfig.search !== false && $page.frontmatter.search !== false" />
|
||||
<!-- <v-text-field flat solo-inverted hide-details prepend-inner-icon="mdi-magnify" label="Search" class="hidden-sm-and-down" /> -->
|
||||
<v-spacer />
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SRDSearchBox from '@theme/components/search/SRDSearchBox.vue'
|
||||
// import NavLinks from '@theme/components/NavLinks.vue'
|
||||
|
||||
export default {
|
||||
name: 'Navbar',
|
||||
|
||||
components: {
|
||||
// NavLinks,
|
||||
SRDSearchBox
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
drawer() {
|
||||
return this.$store.state.drawer
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setDrawer () {
|
||||
this.$store.commit('setDrawer', !this.$store.state.drawer)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.site-title.theme--dark.v-btn--active:before {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
81
docs/.vuepress/theme/components/SearchBox.vue
Normal file
81
docs/.vuepress/theme/components/SearchBox.vue
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<template>
|
||||
<v-autocomplete
|
||||
v-model="select"
|
||||
:loading="loading"
|
||||
:items="items"
|
||||
:search-input.sync="search"
|
||||
cache-items
|
||||
class="mx-4"
|
||||
flat
|
||||
clearable
|
||||
hide-no-data
|
||||
hide-details
|
||||
item-text="title"
|
||||
item-value="path"
|
||||
:label="$site.themeConfig.searchPlaceholder"
|
||||
append-icon="mdi-magnify"
|
||||
solo-inverted
|
||||
></v-autocomplete>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Flexsearch from "flexsearch";
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
index: null,
|
||||
loading: false,
|
||||
items: [],
|
||||
search: null,
|
||||
select: null,
|
||||
results: [{}]
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
search (val) {
|
||||
val && val.length > 1 && val !== this.select && this.querySelections(val)
|
||||
},
|
||||
|
||||
select (val) {
|
||||
if (val) {
|
||||
this.$router.push(val).catch(err => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.index = new Flexsearch({
|
||||
tokenize: "forward",
|
||||
doc: {
|
||||
id: "key",
|
||||
field: ["title", "headers"]
|
||||
}
|
||||
})
|
||||
const { pages } = this.$site
|
||||
console.log(pages)
|
||||
this.index.add(pages)
|
||||
},
|
||||
|
||||
methods: {
|
||||
querySelections (v) {
|
||||
this.loading = true
|
||||
|
||||
this.index.search(
|
||||
v,
|
||||
{
|
||||
limit: 10,
|
||||
threshold: 2,
|
||||
encode: 'extra'
|
||||
},
|
||||
(result) => {
|
||||
console.log(result)
|
||||
this.items = result
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
6
docs/.vuepress/theme/components/search/README.md
Normal file
6
docs/.vuepress/theme/components/search/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# @vuepress/plugin-search
|
||||
|
||||
> header-based search plugin for VuePress
|
||||
|
||||
See [documentation](https://v1.vuepress.vuejs.org/plugin/official/plugin-search.html).
|
||||
|
||||
159
docs/.vuepress/theme/components/search/SRDSearchBox.vue
Normal file
159
docs/.vuepress/theme/components/search/SRDSearchBox.vue
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<template>
|
||||
<v-autocomplete
|
||||
v-model="select"
|
||||
:loading="loading"
|
||||
:items="entries"
|
||||
:search-input.sync="search"
|
||||
cache-items
|
||||
class="mx-4"
|
||||
flat
|
||||
clearable
|
||||
hide-no-data
|
||||
hide-details
|
||||
item-text="title"
|
||||
item-value="path"
|
||||
:label="placeholder"
|
||||
append-icon="mdi-magnify"
|
||||
solo-inverted
|
||||
return-object
|
||||
>
|
||||
|
||||
<template v-slot:item="data">
|
||||
<template>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-html="data.item.title"></v-list-item-title>
|
||||
<v-list-item-subtitle v-if="data.item.subtitle" v-html="data.item.subtitle"></v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</v-autocomplete>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import matchQuery from './match-query'
|
||||
|
||||
/* global SEARCH_MAX_SUGGESTIONS, SEARCH_PATHS, SEARCH_HOTKEYS */
|
||||
export default {
|
||||
name: 'SRDSearchBox',
|
||||
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
focused: false,
|
||||
focusIndex: 0,
|
||||
placeholder: undefined,
|
||||
search: null,
|
||||
select: null,
|
||||
items: []
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
search (query) {
|
||||
if (query && query.length > 1) {
|
||||
this.suggestions(query)
|
||||
}
|
||||
},
|
||||
|
||||
select (selected) {
|
||||
this.go(selected)
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
entries () {
|
||||
return this.items.map(item => {
|
||||
return {
|
||||
title: item.title,
|
||||
subtitle: item.subtitle,
|
||||
path: item.path
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.placeholder = this.$site.themeConfig.searchPlaceholder || ''
|
||||
},
|
||||
|
||||
methods: {
|
||||
suggestions (query) {
|
||||
this.loading = true
|
||||
query = query.trim().toLowerCase()
|
||||
if (!query) {
|
||||
this.items = []
|
||||
return
|
||||
}
|
||||
|
||||
const { pages } = this.$site
|
||||
const max = this.$site.themeConfig.searchMaxSuggestions || 10
|
||||
const localePath = this.$localePath
|
||||
const res = []
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
if (res.length >= max) break
|
||||
const p = pages[i]
|
||||
// filter out results that do not match current locale
|
||||
if (this.getPageLocalePath(p) !== localePath) {
|
||||
continue
|
||||
}
|
||||
|
||||
// filter out results that do not match searchable paths
|
||||
if (!this.isSearchable(p)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (matchQuery(query, p)) {
|
||||
res.push(p)
|
||||
} else if (p.headers) {
|
||||
for (let j = 0; j < p.headers.length; j++) {
|
||||
if (res.length >= max) break
|
||||
const h = p.headers[j]
|
||||
if (h.title && matchQuery(query, p, h.title)) {
|
||||
res.push(Object.assign({}, p, {
|
||||
subtitle: p.title,
|
||||
title: h.title,
|
||||
path: p.path + '#' + h.slug,
|
||||
header: h
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.items = res
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
getPageLocalePath (page) {
|
||||
for (const localePath in this.$site.locales || {}) {
|
||||
if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
|
||||
return localePath
|
||||
}
|
||||
}
|
||||
return '/'
|
||||
},
|
||||
|
||||
isSearchable (page) {
|
||||
let searchPaths = null
|
||||
|
||||
// all paths searchables
|
||||
if (searchPaths === null) { return true }
|
||||
|
||||
searchPaths = Array.isArray(searchPaths) ? searchPaths : new Array(searchPaths)
|
||||
|
||||
return searchPaths.filter(path => {
|
||||
return page.path.match(path)
|
||||
}).length > 0
|
||||
},
|
||||
|
||||
go (selected) {
|
||||
if (selected) {
|
||||
this.$router.push(selected.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
14
docs/.vuepress/theme/components/search/index.js
Normal file
14
docs/.vuepress/theme/components/search/index.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
const { path } = require('@vuepress/shared-utils')
|
||||
|
||||
module.exports = (options) => ({
|
||||
alias: {
|
||||
'@SRDSearchBox':
|
||||
path.resolve(__dirname, 'SearchBox.vue')
|
||||
},
|
||||
|
||||
define: {
|
||||
SEARCH_MAX_SUGGESTIONS: options.searchMaxSuggestions || 5,
|
||||
SEARCH_PATHS: options.test || null,
|
||||
SEARCH_HOTKEYS: options.searchHotkeys || ['s', '/']
|
||||
}
|
||||
})
|
||||
42
docs/.vuepress/theme/components/search/match-query.js
Normal file
42
docs/.vuepress/theme/components/search/match-query.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
import get from 'lodash/get'
|
||||
|
||||
export default (query, page, additionalStr = null) => {
|
||||
let domain = get(page, 'title', '')
|
||||
|
||||
if (get(page, 'frontmatter.tags')) {
|
||||
domain += ` ${page.frontmatter.tags.join(' ')}`
|
||||
}
|
||||
|
||||
if (additionalStr) {
|
||||
domain += ` ${additionalStr}`
|
||||
}
|
||||
|
||||
return matchTest(query, domain)
|
||||
}
|
||||
|
||||
const matchTest = (query, domain) => {
|
||||
const escapeRegExp = str => str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
||||
|
||||
const words = query
|
||||
.split(/\s+/g)
|
||||
.map(str => str.trim())
|
||||
.filter(str => !!str)
|
||||
const hasTrailingSpace = query.endsWith(' ')
|
||||
const searchRegex = new RegExp(
|
||||
words
|
||||
.map((word, index) => {
|
||||
if (words.length === index + 1 && !hasTrailingSpace) {
|
||||
// The last word - ok with the word being "startswith"-like
|
||||
return `(?=.*\\b${escapeRegExp(word)})`
|
||||
} else {
|
||||
// Not the last word - expect the whole word exactly
|
||||
return `(?=.*\\b${escapeRegExp(word)}\\b)`
|
||||
}
|
||||
})
|
||||
.join('') + '.+',
|
||||
'gi'
|
||||
)
|
||||
return searchRegex.test(domain)
|
||||
}
|
||||
|
||||
25
docs/.vuepress/theme/enhanceApp.js
Normal file
25
docs/.vuepress/theme/enhanceApp.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import Vuex from 'vuex'
|
||||
import store from '../store'
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import Vuetify from 'vuetify'
|
||||
import 'vuetify/dist/vuetify.min.css'
|
||||
|
||||
import colors from 'vuetify/es5/util/colors'
|
||||
|
||||
export default ({
|
||||
Vue,
|
||||
options,
|
||||
router,
|
||||
siteData
|
||||
}) => {
|
||||
Vue.use(Vuex)
|
||||
Vue.mixin({ store: store })
|
||||
Vue.use(Vuetify)
|
||||
options.vuetify = new Vuetify({
|
||||
theme: {
|
||||
// primary: colors.red.darken1, // #E53935
|
||||
// secondary: colors.red.lighten4, // #FFCDD2
|
||||
// accent: colors.indigo.base // #3F51B5
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = {
|
||||
extend: '@vuepress/theme-default'
|
||||
// extend: '@vuepress/theme-default'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,137 +1,127 @@
|
|||
<template>
|
||||
<div
|
||||
class="theme-container"
|
||||
:class="pageClasses"
|
||||
@touchstart="onTouchStart"
|
||||
@touchend="onTouchEnd"
|
||||
>
|
||||
<Navbar
|
||||
v-if="shouldShowNavbar"
|
||||
@toggle-sidebar="toggleSidebar"
|
||||
/>
|
||||
<v-app>
|
||||
<v-navigation-drawer v-model="drawer" :clipped="$vuetify.breakpoint.lgAndUp" app>
|
||||
<v-list dense>
|
||||
<template v-for="item in items">
|
||||
<v-row v-if="item.heading" :key="item.heading" align="center">
|
||||
<v-col cols="6">
|
||||
<v-subheader v-if="item.heading">
|
||||
{{ item.heading }}
|
||||
</v-subheader>
|
||||
</v-col>
|
||||
<v-col cols="6" class="text-center">
|
||||
<a href="#!" class="body-2 black--text">EDIT</a>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-list-group v-else-if="item.children" :key="item.text" v-model="item.model" :prepend-icon="item.model ? item.icon : item['icon-alt']" append-icon="">
|
||||
<template v-slot:activator>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
{{ item.text }}
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
<v-list-item v-for="(child, i) in item.children" :key="i" link>
|
||||
<v-list-item-action v-if="child.icon">
|
||||
<v-icon>{{ child.icon }}</v-icon>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
{{ child.text }}
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-group>
|
||||
<v-list-item v-else :key="item.text" link>
|
||||
<v-list-item-action>
|
||||
<v-icon>{{ item.icon }}</v-icon>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
{{ item.text }}
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
|
||||
<div
|
||||
class="sidebar-mask"
|
||||
@click="toggleSidebar(false)"
|
||||
/>
|
||||
<Navbar />
|
||||
|
||||
<Sidebar
|
||||
:items="sidebarItems"
|
||||
@toggle-sidebar="toggleSidebar"
|
||||
>
|
||||
<template #top>
|
||||
<slot name="sidebar-top" />
|
||||
</template>
|
||||
<template #bottom>
|
||||
<slot name="sidebar-bottom" />
|
||||
</template>
|
||||
</Sidebar>
|
||||
|
||||
<DefaultGlobalLayout/>
|
||||
</div>
|
||||
<v-content>
|
||||
<v-container class="fill-height" fluid>
|
||||
<v-row align="center" justify="center">
|
||||
<DefaultGlobalLayout/>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-content>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GlobalLayout from '@app/components/GlobalLayout.vue'
|
||||
import Navbar from '@theme/components/Navbar.vue'
|
||||
import Sidebar from '@theme/components/Sidebar.vue'
|
||||
import { resolveSidebarItems } from '../util'
|
||||
|
||||
export default {
|
||||
name: 'GlobalLayout',
|
||||
|
||||
components: {
|
||||
DefaultGlobalLayout: GlobalLayout,
|
||||
Sidebar,
|
||||
Navbar
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
isSidebarOpen: false
|
||||
items: [
|
||||
{ icon: 'mdi-contacts', text: 'Contacts' },
|
||||
{ icon: 'mdi-history', text: 'Frequently contacted' },
|
||||
{ icon: 'mdi-content-copy', text: 'Duplicates' },
|
||||
{
|
||||
icon: 'mdi-chevron-up',
|
||||
'icon-alt': 'mdi-chevron-down',
|
||||
text: 'Labels',
|
||||
model: true,
|
||||
children: [
|
||||
{ icon: 'mdi-plus', text: 'Create label' },
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'mdi-chevron-up',
|
||||
'icon-alt': 'mdi-chevron-down',
|
||||
text: 'More',
|
||||
model: false,
|
||||
children: [
|
||||
{ text: 'Import' },
|
||||
{ text: 'Export' },
|
||||
{ text: 'Print' },
|
||||
{ text: 'Undo changes' },
|
||||
{ text: 'Other contacts' },
|
||||
],
|
||||
},
|
||||
{ icon: 'mdi-settings', text: 'Settings' },
|
||||
{ icon: 'mdi-message', text: 'Send feedback' },
|
||||
{ icon: 'mdi-help-circle', text: 'Help' },
|
||||
{ icon: 'mdi-cellphone-link', text: 'App downloads' },
|
||||
{ icon: 'mdi-keyboard', text: 'Go to the old version' },
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
shouldShowNavbar () {
|
||||
const { themeConfig } = this.$site
|
||||
const { frontmatter } = this.$page
|
||||
if (
|
||||
frontmatter.navbar === false
|
||||
|| themeConfig.navbar === false) {
|
||||
return false
|
||||
drawer: {
|
||||
get () {
|
||||
return this.$store.state.drawer
|
||||
},
|
||||
set (newValue) {
|
||||
this.$store.commit('setDrawer', newValue)
|
||||
}
|
||||
return (
|
||||
this.$title
|
||||
|| themeConfig.logo
|
||||
|| themeConfig.repo
|
||||
|| themeConfig.nav
|
||||
|| this.$themeLocaleConfig.nav
|
||||
)
|
||||
},
|
||||
|
||||
shouldShowSidebar () {
|
||||
const { frontmatter } = this.$page
|
||||
return (
|
||||
!frontmatter.home
|
||||
&& frontmatter.sidebar !== false
|
||||
&& this.sidebarItems.length
|
||||
)
|
||||
},
|
||||
|
||||
sidebarItems () {
|
||||
return resolveSidebarItems(
|
||||
this.$page,
|
||||
this.$page.regularPath,
|
||||
this.$site,
|
||||
this.$localePath
|
||||
)
|
||||
},
|
||||
|
||||
pageClasses () {
|
||||
const userPageClass = this.$page.frontmatter.pageClass
|
||||
return [
|
||||
{
|
||||
'no-navbar': !this.shouldShowNavbar,
|
||||
'sidebar-open': this.isSidebarOpen,
|
||||
'no-sidebar': !this.shouldShowSidebar
|
||||
},
|
||||
userPageClass
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$router.afterEach(() => {
|
||||
this.isSidebarOpen = false
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleSidebar (to) {
|
||||
this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
|
||||
this.$emit('toggle-sidebar', this.isSidebarOpen)
|
||||
},
|
||||
|
||||
// side swipe
|
||||
onTouchStart (e) {
|
||||
this.touchStart = {
|
||||
x: e.changedTouches[0].clientX,
|
||||
y: e.changedTouches[0].clientY
|
||||
}
|
||||
},
|
||||
|
||||
onTouchEnd (e) {
|
||||
const dx = e.changedTouches[0].clientX - this.touchStart.x
|
||||
const dy = e.changedTouches[0].clientY - this.touchStart.y
|
||||
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
|
||||
if (dx > 0 && this.touchStart.x <= 80) {
|
||||
this.toggleSidebar(true)
|
||||
} else {
|
||||
this.toggleSidebar(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@
|
|||
<div>
|
||||
<Home v-if="$page.frontmatter.home" />
|
||||
|
||||
<Page
|
||||
v-else
|
||||
:sidebar-items="sidebarItems"
|
||||
>
|
||||
<Page v-else>
|
||||
<template #top>
|
||||
<slot name="page-top" />
|
||||
</template>
|
||||
|
|
@ -17,29 +14,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Home from '@theme/components/Home.vue'
|
||||
import Page from '@theme/components/Page.vue'
|
||||
import { resolveSidebarItems } from '../util'
|
||||
|
||||
export default {
|
||||
name: 'Layout',
|
||||
|
||||
components: {
|
||||
Home,
|
||||
Page
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
sidebarItems () {
|
||||
return resolveSidebarItems(
|
||||
this.$page,
|
||||
this.$page.regularPath,
|
||||
this.$site,
|
||||
this.$localePath
|
||||
)
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Création du personnage
|
||||
description: Création du personnage
|
||||
description: Règles de création de personnage
|
||||
---
|
||||
# Création du personnage
|
||||
<a class="button is-primary" href="https://www.black-book-editions.fr/file.php?id=178" target="_blank"><span><i class="fa fa-theater-masks"></i> Feuille de personnage PDF</span></a>
|
||||
|
|
|
|||
9773
package-lock.json
generated
9773
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -9,8 +9,14 @@
|
|||
"docs:build": "vuepress build docs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "^5.0.45",
|
||||
"@vuepress/plugin-blog": "^1.9.2",
|
||||
"flexsearch": "nextapps-de/flexsearch",
|
||||
"node-sass": "^4.13.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"vuepress": "^1.4.0",
|
||||
"vuepress-plugin-clean-urls": "^1.1.1"
|
||||
"vuepress-plugin-clean-urls": "^1.1.1",
|
||||
"vuetify": "^2.2.19",
|
||||
"vuex": "^3.1.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue