Migrate to vite
This commit is contained in:
parent
b2e255d97b
commit
468007dba8
|
@ -20,7 +20,7 @@ $ node dist/server
|
|||
```
|
||||
|
||||
```
|
||||
$ cd client && npm run serve
|
||||
$ cd client && npm run dev
|
||||
```
|
||||
|
||||
Then open http://localhost:8080.
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
VUE_APP_API_URL=http://localhost:3234
|
||||
#VUE_APP_API_URL=https://search.joinpeertube.org
|
||||
VITE_APP_API_URL=http://localhost:3234
|
||||
#VITE_APP_API_URL=https://search.joinpeertube.org
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "vue-eslint-parser",
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser"
|
||||
},
|
||||
"plugins": [ "@typescript-eslint" ],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:vue/vue3-recommended"
|
||||
],
|
||||
"rules": {
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/require-default-prop": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
}
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
src/locale/**/*~
|
||||
dist/
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
|
||||
<link rel="icon" type="image/png" href="<%= BASE_URL %>img/favicon.png">
|
||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
@ -15,9 +15,7 @@
|
|||
</noscript>
|
||||
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
|
||||
<div id="footer"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -3,34 +3,32 @@
|
|||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve --mode development",
|
||||
"build": "vue-cli-service build --mode production",
|
||||
"lint": "vue-cli-service lint",
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"lint": "eslint --ext .js,.vue,.ts --ignore-path .gitignore --fix src",
|
||||
"i18n:update": "git fetch weblate && git merge weblate/master && rm -f src/locale/en_US/LC_MESSAGES/app.po && make clean && make makemessages && make translations"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@jshmrtn/vue3-gettext": "^1.5.0",
|
||||
"@sipec/vue3-tags-input": "^3.0.4",
|
||||
"@types/axios": "^0.14.0",
|
||||
"@types/markdown-it": "^10.0.1",
|
||||
"@vue/cli-plugin-typescript": "~5.0.0-beta.2",
|
||||
"@vue/cli-service": "~5.0.0-beta.2",
|
||||
"@vue/compiler-sfc": "^3.1.0",
|
||||
"axios": "^0.20.0",
|
||||
"markdown-it": "^11.0.0",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"@vitejs/plugin-vue": "^2.2.2",
|
||||
"@vue/eslint-config-typescript": "^10.0.0",
|
||||
"axios": "^0.26.0",
|
||||
"eslint": "^8.9.0",
|
||||
"eslint-plugin-vue": "^8.5.0",
|
||||
"markdown-it": "^12.3.2",
|
||||
"nprogress": "^0.2.0",
|
||||
"register-service-worker": "^1.0.0",
|
||||
"sass": "^1.35.1",
|
||||
"sass-loader": "^12.1.0",
|
||||
"typescript": "~4.3.4",
|
||||
"vue": "^3.1.0",
|
||||
"vue-matomo": "^4.0.1",
|
||||
"vue-router": "^4.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
"sass": "^1.49.8",
|
||||
"typescript": "~4.5.5",
|
||||
"vite": "^2.8.4",
|
||||
"vue": "^3.2.31",
|
||||
"vue-matomo": "^4.1.0",
|
||||
"vue-router": "^4.0.12",
|
||||
"vue-tsc": "^0.31.4",
|
||||
"vue3-gettext": "^2.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<template>
|
||||
<div>
|
||||
<router-view id="main-container" class="container"/>
|
||||
<router-view
|
||||
id="main-container"
|
||||
class="container"
|
||||
/>
|
||||
|
||||
<my-footer></my-footer>
|
||||
<my-footer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -18,7 +21,7 @@
|
|||
|
||||
data () {
|
||||
return {
|
||||
title: process.env.VUE_APP_TITLE
|
||||
title: import.meta.env.VITE_APP_TITLE
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
<template>
|
||||
<a v-bind:href="actor.url" rel="nofollow noreferrer noopener" target="_blank" class="actor" v-bind:title="linkTitle">
|
||||
<img v-if="actor.avatar && !avatarError" v-bind:src="actor.avatar.url" alt="" :class="{ account: isAccount }" @error="setAvatarError()">
|
||||
<a
|
||||
:href="actor.url"
|
||||
rel="nofollow noreferrer noopener"
|
||||
target="_blank"
|
||||
class="actor"
|
||||
:title="linkTitle"
|
||||
>
|
||||
<img
|
||||
v-if="actor.avatar && !avatarError"
|
||||
:src="actor.avatar.url"
|
||||
alt=""
|
||||
:class="{ account: isAccount }"
|
||||
@error="setAvatarError()"
|
||||
>
|
||||
|
||||
<strong>{{ actor.displayName }}</strong>
|
||||
|
||||
|
@ -10,6 +22,42 @@
|
|||
</a>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { AccountSummary, VideoChannelSummary } from '../../../PeerTube/shared/models'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
actor: Object as PropType<AccountSummary | VideoChannelSummary>,
|
||||
type: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
avatarError: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
linkTitle (): string {
|
||||
if (this.type === 'channel') return this.$gettext('Go on this channel page')
|
||||
|
||||
return this.$gettext('Go on this account page')
|
||||
},
|
||||
|
||||
isAccount (): boolean {
|
||||
return this.type === 'account'
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setAvatarError () {
|
||||
this.avatarError = true
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
|
@ -56,39 +104,3 @@
|
|||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { AccountSummary, VideoChannelSummary } from '../../../PeerTube/shared/models'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
actor: Object as PropType<AccountSummary | VideoChannelSummary>,
|
||||
type: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
avatarError: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setAvatarError () {
|
||||
this.avatarError = true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
linkTitle (): string {
|
||||
if (this.type === 'channel') return this.$gettext('Go on this channel page')
|
||||
|
||||
return this.$gettext('Go on this account page')
|
||||
},
|
||||
|
||||
isAccount (): boolean {
|
||||
return this.type === 'account'
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,15 +1,33 @@
|
|||
<template>
|
||||
<div class="channel root-result">
|
||||
|
||||
<a target="_blank" rel="nofollow noreferrer noopener" v-bind:href="channel.url" :title="discoverChannelMessage" class="avatar">
|
||||
<img v-if="channel.avatar" v-bind:src="channel.avatar.url" alt="">
|
||||
<img v-else src="/img/default-avatar.png" alt="">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="channel.url"
|
||||
:title="discoverChannelMessage"
|
||||
class="avatar"
|
||||
>
|
||||
<img
|
||||
v-if="channel.avatar"
|
||||
:src="channel.avatar.url"
|
||||
alt=""
|
||||
>
|
||||
<img
|
||||
v-else
|
||||
src="/img/default-avatar.png"
|
||||
alt=""
|
||||
>
|
||||
</a>
|
||||
|
||||
<div class="information">
|
||||
<div class="title-block">
|
||||
<h5 class="title">
|
||||
<a target="_blank" rel="nofollow noreferrer noopener" v-bind:href="channel.url" :title="discoverChannelMessage">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="channel.url"
|
||||
:title="discoverChannelMessage"
|
||||
>
|
||||
{{ channel.displayName }}
|
||||
</a>
|
||||
</h5>
|
||||
|
@ -23,40 +41,24 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="description">{{ channel.description }}</div>
|
||||
<div class="description">
|
||||
{{ channel.description }}
|
||||
</div>
|
||||
|
||||
<div class="button">
|
||||
<a class="button-link" rel="nofollow noreferrer noopener" target="_blank" v-bind:href="channel.url">
|
||||
<a
|
||||
class="button-link"
|
||||
rel="nofollow noreferrer noopener"
|
||||
target="_blank"
|
||||
:href="channel.url"
|
||||
>
|
||||
{{ discoverChannelMessage }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
.channel {
|
||||
.avatar {
|
||||
width: $thumbnail-width;
|
||||
min-width: $thumbnail-width;
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
object-fit: cover;
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
min-width: 110px;
|
||||
min-height: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { VideoChannel } from '../../../PeerTube/shared/models'
|
||||
|
@ -85,3 +87,25 @@
|
|||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
.channel {
|
||||
.avatar {
|
||||
width: $thumbnail-width;
|
||||
min-width: $thumbnail-width;
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
object-fit: cover;
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
min-width: 110px;
|
||||
min-height: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,42 +1,107 @@
|
|||
<template>
|
||||
<footer id="main-footer">
|
||||
|
||||
<div class="header">
|
||||
<img src="/img/bottom-peertube-logo-v3.svg" alt="">
|
||||
<img
|
||||
src="/img/bottom-peertube-logo-v3.svg"
|
||||
alt=""
|
||||
>
|
||||
|
||||
<div v-translate class="description">A free software to take back control of your videos</div>
|
||||
<div
|
||||
v-translate
|
||||
class="description"
|
||||
>
|
||||
A free software to take back control of your videos
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div>
|
||||
<div v-translate class="subtitle">Open your own videos website with PeerTube!</div>
|
||||
<div
|
||||
v-translate
|
||||
class="subtitle"
|
||||
>
|
||||
Open your own videos website with PeerTube!
|
||||
</div>
|
||||
|
||||
<a target="_blank" v-translate href="https://docs.joinpeertube.org/#/install-any-os">Install PeerTube</a>
|
||||
<a
|
||||
v-translate
|
||||
target="_blank"
|
||||
href="https://docs.joinpeertube.org/#/install-any-os"
|
||||
>Install PeerTube</a>
|
||||
|
||||
<a target="_blank" v-translate href="https://joinpeertube.org#what-is-peertube">Why should I have my own PeerTube website?</a>
|
||||
<a
|
||||
v-translate
|
||||
target="_blank"
|
||||
href="https://joinpeertube.org#what-is-peertube"
|
||||
>Why should I have my own PeerTube website?</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div v-translate class="subtitle">Create an account to take back control of your videos</div>
|
||||
<div
|
||||
v-translate
|
||||
class="subtitle"
|
||||
>
|
||||
Create an account to take back control of your videos
|
||||
</div>
|
||||
|
||||
<a target="_blank" v-translate href="https://joinpeertube.org/instances">Open an account on a PeerTube website</a>
|
||||
<a
|
||||
v-translate
|
||||
target="_blank"
|
||||
href="https://joinpeertube.org/instances"
|
||||
>Open an account on a PeerTube website</a>
|
||||
|
||||
<a target="_blank" v-translate href="https://docs.joinpeertube.org/#/use-library?id=playlist">Create playlists</a>
|
||||
<a
|
||||
v-translate
|
||||
target="_blank"
|
||||
href="https://docs.joinpeertube.org/#/use-library?id=playlist"
|
||||
>Create playlists</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="big-link">
|
||||
<a href="https://joinpeertube.org" target="_blank" v-translate> >> Check all guides on joinpeertube.org << </a>
|
||||
<a
|
||||
v-translate
|
||||
href="https://joinpeertube.org"
|
||||
target="_blank"
|
||||
> >> Check all guides on joinpeertube.org << </a>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<a v-translate href="https://framagit.org/framasoft/peertube/search-index/" target="_blank">Source code</a>
|
||||
<a
|
||||
v-translate
|
||||
href="https://framagit.org/framasoft/peertube/search-index/"
|
||||
target="_blank"
|
||||
>Source code</a>
|
||||
|
||||
<a v-if="legalNoticesUrl" v-translate :href="legalNoticesUrl" target="_blank">Legal notices</a>
|
||||
<a
|
||||
v-if="legalNoticesUrl"
|
||||
v-translate
|
||||
:href="legalNoticesUrl"
|
||||
target="_blank"
|
||||
>Legal notices</a>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { getConfig } from '../shared/config'
|
||||
|
||||
export default defineComponent({
|
||||
data () {
|
||||
return {
|
||||
legalNoticesUrl: ''
|
||||
}
|
||||
},
|
||||
|
||||
async mounted () {
|
||||
const config = await getConfig()
|
||||
|
||||
this.legalNoticesUrl = config.legalNoticesUrl
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
|
@ -152,22 +217,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
import { getConfig } from '../shared/config'
|
||||
|
||||
export default defineComponent({
|
||||
data () {
|
||||
return {
|
||||
legalNoticesUrl: ''
|
||||
}
|
||||
},
|
||||
|
||||
async mounted () {
|
||||
const config = await getConfig()
|
||||
|
||||
this.legalNoticesUrl = config.legalNoticesUrl
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,29 +1,87 @@
|
|||
<template>
|
||||
<div>
|
||||
<header>
|
||||
<interface-language-dropdown class="interface-language-dropdown"></interface-language-dropdown>
|
||||
<interface-language-dropdown class="interface-language-dropdown" />
|
||||
|
||||
<h1>
|
||||
<span v-if="configLoaded && !titleImageUrl">{{ indexName }}</span>
|
||||
|
||||
<img class="title-image" :src="titleImageUrl" :alt="indexName" />
|
||||
<img
|
||||
class="title-image"
|
||||
:src="titleImageUrl"
|
||||
:alt="indexName"
|
||||
>
|
||||
</h1>
|
||||
|
||||
<template v-if="!smallFormat">
|
||||
<h4>
|
||||
<div v-translate>A search engine of <a href="https://joinpeertube.org" target="_blank">PeerTube</a> videos, channels and playlists</div>
|
||||
<div v-translate>
|
||||
A search engine of <a
|
||||
href="https://joinpeertube.org"
|
||||
target="_blank"
|
||||
>PeerTube</a> videos, channels and playlists
|
||||
</div>
|
||||
|
||||
<div v-translate>Developed by <a href="https://framasoft.org" target="_blank">Framasoft</a></div>
|
||||
<div v-translate>
|
||||
Developed by <a
|
||||
href="https://framasoft.org"
|
||||
target="_blank"
|
||||
>Framasoft</a>
|
||||
</div>
|
||||
</h4>
|
||||
|
||||
<div class="search-home">
|
||||
<img v-if="searchImageUrl" :src="searchImageUrl" alt="">
|
||||
<img
|
||||
v-if="searchImageUrl"
|
||||
:src="searchImageUrl"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</header>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { getConfig } from '../shared/config'
|
||||
import { buildApiUrl } from '../shared/utils'
|
||||
import InterfaceLanguageDropdown from './InterfaceLanguageDropdown.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
'interface-language-dropdown': InterfaceLanguageDropdown
|
||||
},
|
||||
|
||||
props: {
|
||||
indexName: String,
|
||||
smallFormat: Boolean,
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
configLoaded: false,
|
||||
titleImageUrl: '',
|
||||
searchImageUrl: ''
|
||||
}
|
||||
},
|
||||
|
||||
async mounted () {
|
||||
const config = await getConfig()
|
||||
|
||||
this.titleImageUrl = config.searchInstanceNameImage
|
||||
? buildApiUrl(config.searchInstanceNameImage)
|
||||
: ''
|
||||
|
||||
this.searchImageUrl = config.searchInstanceSearchImage
|
||||
? buildApiUrl(config.searchInstanceSearchImage)
|
||||
: buildApiUrl('/img/search-home.png')
|
||||
|
||||
this.configLoaded = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
|
@ -108,43 +166,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { getConfig } from '../shared/config'
|
||||
import { buildApiUrl } from '../shared/utils'
|
||||
import InterfaceLanguageDropdown from './InterfaceLanguageDropdown.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
'interface-language-dropdown': InterfaceLanguageDropdown
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
configLoaded: false,
|
||||
titleImageUrl: '',
|
||||
searchImageUrl: ''
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
indexName: String,
|
||||
smallFormat: Boolean,
|
||||
},
|
||||
|
||||
async mounted () {
|
||||
const config = await getConfig()
|
||||
|
||||
this.titleImageUrl = config.searchInstanceNameImage
|
||||
? buildApiUrl(config.searchInstanceNameImage)
|
||||
: ''
|
||||
|
||||
this.searchImageUrl = config.searchInstanceSearchImage
|
||||
? buildApiUrl(config.searchInstanceSearchImage)
|
||||
: buildApiUrl('/img/search-home.png')
|
||||
|
||||
this.configLoaded = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,21 +1,80 @@
|
|||
<template>
|
||||
<div class="interface-language-dropdown">
|
||||
<img :title="imgTitle" v-on:click="toggleShow()" class="interface-language" src="/img/interface-languages.svg" alt="Change interface language">
|
||||
<img
|
||||
:title="imgTitle"
|
||||
class="interface-language"
|
||||
src="/img/interface-languages.svg"
|
||||
alt="Change interface language"
|
||||
@click="toggleShow()"
|
||||
>
|
||||
|
||||
<div v-if="showMenu" class="menu">
|
||||
<a v-for="(lang, locale) in availableLanguages" :key="locale" :href="buildLanguageRoute(locale)" class="menu-item">
|
||||
<div
|
||||
v-if="showMenu"
|
||||
class="menu"
|
||||
>
|
||||
<a
|
||||
v-for="(lang, locale) in availableLanguages"
|
||||
:key="locale"
|
||||
:href="buildLanguageRoute(locale)"
|
||||
class="menu-item"
|
||||
>
|
||||
{{ lang }}
|
||||
</a>
|
||||
|
||||
<hr />
|
||||
<hr>
|
||||
|
||||
<a class="menu-item add-your-language" target="_blank" href="https://weblate.framasoft.org/projects/peertube-search-index/client/">
|
||||
<a
|
||||
class="menu-item add-your-language"
|
||||
target="_blank"
|
||||
href="https://weblate.framasoft.org/projects/peertube-search-index/client/"
|
||||
>
|
||||
Translate
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
data () {
|
||||
return {
|
||||
showMenu: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
imgTitle () {
|
||||
return this.$gettext('Change interface language')
|
||||
},
|
||||
|
||||
availableLanguages (): { [id: string]: string } {
|
||||
const { available } = useGettext()
|
||||
|
||||
return available
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleShow () {
|
||||
this.showMenu = !this.showMenu;
|
||||
},
|
||||
|
||||
buildLanguageRoute(locale: string | number) {
|
||||
const paths = this.$route.fullPath.split('/')
|
||||
|
||||
if (paths.length > 0 && Object.prototype.hasOwnProperty.call(this.availableLanguages, paths[0])) {
|
||||
return '/' + locale + '/' + paths.slice(1).join('/')
|
||||
}
|
||||
|
||||
return '/' + locale + this.$route.fullPath
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
|
@ -67,44 +126,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { useGettext } from '@jshmrtn/vue3-gettext'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
data () {
|
||||
return {
|
||||
showMenu: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
imgTitle () {
|
||||
return this.$gettext('Change interface language')
|
||||
},
|
||||
|
||||
availableLanguages (): { [id: string]: string } {
|
||||
const { available } = useGettext()
|
||||
|
||||
return available
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleShow () {
|
||||
this.showMenu = !this.showMenu;
|
||||
},
|
||||
|
||||
buildLanguageRoute(locale: string) {
|
||||
const paths = this.$route.fullPath.split('/')
|
||||
|
||||
if (paths.length > 0 && this.availableLanguages.hasOwnProperty(paths[0])) {
|
||||
return "/" + locale + "/" + paths.slice(1).join("/")
|
||||
} else {
|
||||
return "/" + locale + this.$route.fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,29 +1,69 @@
|
|||
<template>
|
||||
|
||||
<div class="pagination" v-if="searchDone">
|
||||
<router-link class="previous" v-bind:class="{ 'none-opacity': modelValue === 1 }" :to="{ query: buildPageUrlQuery(modelValue - 1) }">
|
||||
<translate>Previous page</translate>
|
||||
<div
|
||||
v-if="searchDone"
|
||||
class="pagination"
|
||||
>
|
||||
<router-link
|
||||
class="previous"
|
||||
:class="{ 'none-opacity': modelValue === 1 }"
|
||||
:to="{ query: buildPageUrlQuery(modelValue - 1) }"
|
||||
>
|
||||
{{ $gettext('Previous page') }}
|
||||
</router-link>
|
||||
|
||||
<div class="pages">
|
||||
<template v-for="page in pages">
|
||||
|
||||
<router-link v-if="page !== modelValue" class="go-to-page" :to="{ query: buildPageUrlQuery(page) }" :key="page">
|
||||
<template
|
||||
v-for="page in pages"
|
||||
:key="page"
|
||||
>
|
||||
<router-link
|
||||
v-if="page !== modelValue"
|
||||
class="go-to-page"
|
||||
:to="{ query: buildPageUrlQuery(page) }"
|
||||
>
|
||||
{{ page }}
|
||||
</router-link>
|
||||
|
||||
<div v-else class="current">{{ page }}</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="current"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<router-link class="next" v-bind:class="{ 'none-opacity': modelValue >= maxPage }" :to="{ query: buildPageUrlQuery(+modelValue + 1) }">
|
||||
<translate>Next page</translate>
|
||||
<router-link
|
||||
class="next"
|
||||
:class="{ 'none-opacity': modelValue >= maxPage }"
|
||||
:to="{ query: buildPageUrlQuery(+modelValue + 1) }"
|
||||
>
|
||||
{{ $gettext('Next page') }}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
maxPage: Number,
|
||||
searchDone: Boolean,
|
||||
modelValue: Number,
|
||||
pages: Array as () => number[]
|
||||
},
|
||||
|
||||
methods: {
|
||||
buildPageUrlQuery (page: number) {
|
||||
const query = this.$route.query
|
||||
|
||||
return Object.assign({}, query, { page })
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
|
@ -61,26 +101,4 @@
|
|||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
maxPage: Number,
|
||||
searchDone: Boolean,
|
||||
modelValue: Number,
|
||||
pages: Array as () => number[]
|
||||
},
|
||||
|
||||
methods: {
|
||||
buildPageUrlQuery (page: number) {
|
||||
const query = this.$route.query
|
||||
|
||||
return Object.assign({}, query, { page })
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
<template>
|
||||
<div class="playlist root-result">
|
||||
|
||||
<div class="thumbnail">
|
||||
<a class="img" :title="watchMessage" target="_blank" rel="nofollow noreferrer noopener" v-bind:href="playlist.url">
|
||||
<img v-bind:src="playlist.thumbnailUrl" alt="">
|
||||
<a
|
||||
class="img"
|
||||
:title="watchMessage"
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="playlist.url"
|
||||
>
|
||||
<img
|
||||
:src="playlist.thumbnailUrl"
|
||||
alt=""
|
||||
>
|
||||
|
||||
<span class="videos-length">{{ videosLengthLabel }}</span>
|
||||
</a>
|
||||
|
@ -11,41 +19,105 @@
|
|||
|
||||
<div class="information">
|
||||
<h5 class="title">
|
||||
<a :title="watchMessage" target="_blank" rel="nofollow noreferrer noopener" v-bind:href="playlist.url">{{ playlist.displayName }}</a>
|
||||
<a
|
||||
:title="watchMessage"
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="playlist.url"
|
||||
>{{ playlist.displayName }}</a>
|
||||
</h5>
|
||||
|
||||
<div class="description" v-html="renderMarkdown(playlist.description)"></div>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div
|
||||
class="description"
|
||||
v-html="renderMarkdown(playlist.description)"
|
||||
/>
|
||||
<!-- eslint-enable -->
|
||||
|
||||
<div class="metadatas">
|
||||
<div class="metadata">
|
||||
<div class="by-account">
|
||||
<label v-translate>Created by</label>
|
||||
<actor-miniature type="account" v-bind:actor="playlist.ownerAccount"></actor-miniature>
|
||||
<actor-miniature
|
||||
type="account"
|
||||
:actor="playlist.ownerAccount"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="by-channel">
|
||||
<label v-translate>In</label>
|
||||
|
||||
<actor-miniature type="channel" v-bind:actor="playlist.videoChannel"></actor-miniature>
|
||||
<actor-miniature
|
||||
type="channel"
|
||||
:actor="playlist.videoChannel"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="publishedAt">
|
||||
<label v-translate>Updated on</label>
|
||||
|
||||
<div class="value">{{ updateDate }}</div>
|
||||
|
||||
<div class="value">
|
||||
{{ updateDate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button">
|
||||
<a class="button-link" target="_blank" rel="nofollow noreferrer noopener" v-bind:href="playlist.url">
|
||||
<a
|
||||
class="button-link"
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="playlist.url"
|
||||
>
|
||||
{{ watchMessage }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import ActorMiniature from './ActorMiniature.vue'
|
||||
import { VideoPlaylist } from '../../../PeerTube/shared/models'
|
||||
import { renderMarkdown } from '../shared/markdown-render'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
'actor-miniature': ActorMiniature
|
||||
},
|
||||
|
||||
props: {
|
||||
playlist: Object as PropType<VideoPlaylist>
|
||||
},
|
||||
|
||||
computed: {
|
||||
host (): string {
|
||||
const url = this.playlist.url
|
||||
|
||||
return new URL(url as string).host
|
||||
},
|
||||
|
||||
updateDate (): string {
|
||||
return new Date(this.playlist.updatedAt).toLocaleDateString()
|
||||
},
|
||||
|
||||
watchMessage (): string {
|
||||
return this.$gettextInterpolate(this.$gettext('Watch the playlist on %{host}'), { host: this.host })
|
||||
},
|
||||
|
||||
videosLengthLabel (): string {
|
||||
return this.$gettextInterpolate(this.$gettext('%{videosLength} videos'), { videosLength: this.playlist.videosLength })
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
renderMarkdown(markdown: string) {
|
||||
return renderMarkdown(markdown)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
|
@ -100,47 +172,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import ActorMiniature from './ActorMiniature.vue'
|
||||
import { VideoPlaylist } from '../../../PeerTube/shared/models'
|
||||
import { renderMarkdown } from '../shared/markdown-render'
|
||||
import { useGettext } from '@jshmrtn/vue3-gettext'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
'actor-miniature': ActorMiniature
|
||||
},
|
||||
|
||||
props: {
|
||||
playlist: Object as PropType<VideoPlaylist>
|
||||
},
|
||||
|
||||
computed: {
|
||||
host (): string {
|
||||
const url = this.playlist.url
|
||||
|
||||
return new URL(url as string).host
|
||||
},
|
||||
|
||||
updateDate (): string {
|
||||
return new Date(this.playlist.updatedAt).toLocaleDateString()
|
||||
},
|
||||
|
||||
watchMessage (): string {
|
||||
return this.$gettextInterpolate(this.$gettext('Watch the playlist on %{host}'), { host: this.host })
|
||||
},
|
||||
|
||||
videosLengthLabel (): string {
|
||||
return this.$gettextInterpolate(this.$gettext('%{videosLength} videos'), { videosLength: this.playlist.videosLength })
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
renderMarkdown(markdown: string) {
|
||||
return renderMarkdown(markdown)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
<template>
|
||||
<div class="block-warning" v-bind:class="{ highlight: highlight }" >
|
||||
<img src="/img/sepia-warning.svg" alt="">
|
||||
<div
|
||||
class="block-warning"
|
||||
:class="{ highlight: highlight }"
|
||||
>
|
||||
<img
|
||||
src="/img/sepia-warning.svg"
|
||||
alt=""
|
||||
>
|
||||
|
||||
<div v-translate>
|
||||
<strong>%{indexName}</strong> displays videos and channels that match your search but is not the publisher, nor the owner.
|
||||
|
@ -9,6 +15,17 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
indexName: String,
|
||||
highlight: Boolean
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
|
@ -44,17 +61,4 @@
|
|||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
indexName: String,
|
||||
highlight: Boolean
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,124 +1,109 @@
|
|||
<template>
|
||||
<div class="video root-result">
|
||||
|
||||
<div class="thumbnail">
|
||||
<a class="img" :title="watchVideoMessage" target="_blank" rel="nofollow noreferrer noopener" v-bind:href="video.url">
|
||||
<img v-bind:src="getVideoThumbnailUrl()" alt="" @error="setThumbnailError()" :class="{ error: thumbnailError }">
|
||||
<a
|
||||
class="img"
|
||||
:title="watchVideoMessage"
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="video.url"
|
||||
>
|
||||
<img
|
||||
:src="getVideoThumbnailUrl()"
|
||||
alt=""
|
||||
:class="{ error: thumbnailError }"
|
||||
@error="setThumbnailError()"
|
||||
>
|
||||
|
||||
<span v-if="video.isLive" class="live-info" v-translate>LIVE</span>
|
||||
<span v-else class="duration">{{ formattedDuration }}</span>
|
||||
<span
|
||||
v-if="video.isLive"
|
||||
v-translate
|
||||
class="live-info"
|
||||
>LIVE</span>
|
||||
<span
|
||||
v-else
|
||||
class="duration"
|
||||
>{{ formattedDuration }}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="information">
|
||||
<h5 class="title">
|
||||
<a :title="watchVideoMessage" target="_blank" rel="nofollow noreferrer noopener" v-bind:href="video.url">{{ video.name }}</a>
|
||||
<a
|
||||
:title="watchVideoMessage"
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="video.url"
|
||||
>{{ video.name }}</a>
|
||||
</h5>
|
||||
|
||||
<div class="description" v-html="renderMarkdown(video.description)"></div>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div
|
||||
class="description"
|
||||
v-html="renderMarkdown(video.description)"
|
||||
/>
|
||||
<!-- eslint-enable -->
|
||||
|
||||
<div class="metadatas">
|
||||
<div class="metadata">
|
||||
<div class="by-account">
|
||||
<label v-translate>Created by</label>
|
||||
<actor-miniature type="account" v-bind:actor="video.account"></actor-miniature>
|
||||
<actor-miniature
|
||||
type="account"
|
||||
:actor="video.account"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="by-channel">
|
||||
<label v-translate>In</label>
|
||||
|
||||
<actor-miniature type="channel" v-bind:actor="video.channel"></actor-miniature>
|
||||
<actor-miniature
|
||||
type="channel"
|
||||
:actor="video.channel"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="publishedAt">
|
||||
<label v-translate>On</label>
|
||||
|
||||
<div class="value">{{ publicationDate }}</div>
|
||||
|
||||
<div class="value">
|
||||
{{ publicationDate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="language">
|
||||
<label v-translate>Language</label>
|
||||
|
||||
<div class="value">{{ video.language.label }}</div>
|
||||
<div class="value">
|
||||
{{ video.language.label }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tags" v-if="video.tags && video.tags.length !== 0">
|
||||
<div
|
||||
v-if="video.tags && video.tags.length !== 0"
|
||||
class="tags"
|
||||
>
|
||||
<label v-translate>Tags</label>
|
||||
|
||||
<div class="value">{{ video.tags.join(', ') }}</div>
|
||||
<div class="value">
|
||||
{{ video.tags.join(', ') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button">
|
||||
<a class="button-link" target="_blank" rel="nofollow noreferrer noopener" v-bind:href="video.url">
|
||||
<a
|
||||
class="button-link"
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer noopener"
|
||||
:href="video.url"
|
||||
>
|
||||
{{ watchVideoMessage }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
.video {
|
||||
|
||||
.thumbnail {
|
||||
margin-right: 20px;
|
||||
|
||||
--thumbnail-width: #{$thumbnail-width};
|
||||
--thumbnail-height: #{$thumbnail-height};
|
||||
|
||||
// For the duration overlay
|
||||
.img {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
img {
|
||||
background-color: #E5E5E5;
|
||||
width: var(--thumbnail-width);
|
||||
height: var(--thumbnail-height);
|
||||
border-radius: 3px;
|
||||
|
||||
&.error {
|
||||
border: 1px solid #E5E5E5;
|
||||
}
|
||||
}
|
||||
|
||||
.duration,
|
||||
.live-info {
|
||||
position: absolute;
|
||||
padding: 2px 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.duration {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.live-info {
|
||||
background-color: rgba(224, 8, 8 ,.8);
|
||||
font-weight: $font-semibold;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $small-view) {
|
||||
--thumbnail-width: calc(100% + 10px);
|
||||
--thumbnail-height: auto;
|
||||
|
||||
img {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import ActorMiniature from './ActorMiniature.vue'
|
||||
|
@ -184,3 +169,63 @@
|
|||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../scss/_variables';
|
||||
|
||||
.video {
|
||||
|
||||
.thumbnail {
|
||||
margin-right: 20px;
|
||||
|
||||
--thumbnail-width: #{$thumbnail-width};
|
||||
--thumbnail-height: #{$thumbnail-height};
|
||||
|
||||
// For the duration overlay
|
||||
.img {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
img {
|
||||
background-color: #E5E5E5;
|
||||
width: var(--thumbnail-width);
|
||||
height: var(--thumbnail-height);
|
||||
border-radius: 3px;
|
||||
|
||||
&.error {
|
||||
border: 1px solid #E5E5E5;
|
||||
}
|
||||
}
|
||||
|
||||
.duration,
|
||||
.live-info {
|
||||
position: absolute;
|
||||
padding: 2px 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.duration {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.live-info {
|
||||
background-color: rgba(224, 8, 8 ,.8);
|
||||
font-weight: $font-semibold;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $small-view) {
|
||||
--thumbnail-width: calc(100% + 10px);
|
||||
--thumbnail-height: auto;
|
||||
|
||||
img {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import './scss/main.scss'
|
||||
import { createApp } from 'vue'
|
||||
import VueMatomo from 'vue-matomo'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createGettext } from 'vue3-gettext'
|
||||
import App from './App.vue'
|
||||
import Search from './views/Search.vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createGettext, useGettext } from '@jshmrtn/vue3-gettext'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
@ -42,7 +42,7 @@ const allLocales = Object.keys(availableLanguages).concat(Object.keys(aliasesLan
|
|||
const defaultLanguage = 'en_US'
|
||||
let currentLanguage = defaultLanguage
|
||||
|
||||
const basePath = process.env.BASE_URL
|
||||
const basePath = import.meta.env.BASE_URL
|
||||
const startRegexp = new RegExp('^' + basePath)
|
||||
|
||||
const paths = window.location.pathname
|
||||
|
@ -111,10 +111,7 @@ buildTranslationsPromise(defaultLanguage, currentLanguage)
|
|||
})
|
||||
|
||||
// Stats Matomo
|
||||
if (!(navigator.doNotTrack === 'yes' ||
|
||||
navigator.doNotTrack === '1' ||
|
||||
window.doNotTrack === '1')
|
||||
) {
|
||||
if (!(navigator.doNotTrack === 'yes' || navigator.doNotTrack === '1')) {
|
||||
app.use(VueMatomo, {
|
||||
// Configure your matomo server and site
|
||||
host: 'https://stats.framasoft.org/',
|
||||
|
@ -137,26 +134,6 @@ buildTranslationsPromise(defaultLanguage, currentLanguage)
|
|||
|
||||
enableLinkTracking: true
|
||||
})
|
||||
|
||||
const _paq = []
|
||||
|
||||
// CNIL conformity
|
||||
_paq.push([ function piwikCNIL () {
|
||||
// @ts-expect-error
|
||||
const self = this
|
||||
|
||||
function getOriginalVisitorCookieTimeout () {
|
||||
const now = new Date()
|
||||
const nowTs = Math.round(now.getTime() / 1000)
|
||||
const visitorInfo = self.getVisitorInfo()
|
||||
const createTs = parseInt(visitorInfo[2], 10)
|
||||
const cookieTimeout = 33696000 // 13 months in seconds
|
||||
return (createTs + cookieTimeout) - nowTs
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
this.setVisitorCookieTimeout(getOriginalVisitorCookieTimeout())
|
||||
} ])
|
||||
}
|
||||
|
||||
app.use(router)
|
||||
|
|
|
@ -188,7 +188,7 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.metadatas {
|
||||
.metadata {
|
||||
> div {
|
||||
min-height: 27px;
|
||||
display: flex;
|
||||
|
@ -228,7 +228,7 @@ body {
|
|||
margin: 0 0 20px -10px !important;
|
||||
}
|
||||
|
||||
.metadatas {
|
||||
.metadata {
|
||||
label {
|
||||
min-width: 70px;
|
||||
margin-right: 10px;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import * as MarkdownIt from 'markdown-it'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
const TEXT_RULES = [
|
||||
'linkify',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
function buildApiUrl (path: string) {
|
||||
const normalizedPath = path.startsWith('/') ? path : '/' + path
|
||||
|
||||
const base = process.env.VUE_APP_API_URL || ''
|
||||
const base = import.meta.env.VITE_APP_API_URL || ''
|
||||
return base + normalizedPath
|
||||
}
|
||||
|
||||
|
@ -83,11 +83,11 @@ function publishedDateRangeToAPIParams (publishedDateRange: string) {
|
|||
return { startDate: date.toISOString(), endDate: undefined }
|
||||
}
|
||||
|
||||
function extractTagsFromQuery (value: any | any[]) {
|
||||
function extractTagsFromQuery <T> (value: T | T[]) {
|
||||
if (!value) return []
|
||||
|
||||
if (Array.isArray(value) === true) {
|
||||
return (value as any[]).map(v => ({ text: v }))
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(v => ({ text: v }))
|
||||
}
|
||||
|
||||
return [ { text: value } ]
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import { Language } from '@jshmrtn/vue3-gettext'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface ComponentCustomProperties {
|
||||
$gettext: Language['$gettext']
|
||||
$pgettext: Language['$pgettext']
|
||||
$ngettext: Language['$ngettext']
|
||||
$npgettext: Language['$npgettext']
|
||||
$gettextInterpolate: Language['interpolate']
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,35 +1,23 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": false,
|
||||
"noImplicitThis": true,
|
||||
"jsx": "preserve",
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2015",
|
||||
"es2016",
|
||||
"es2017"
|
||||
],
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["esnext", "dom"],
|
||||
"paths": {
|
||||
"@shared/*": [ "../PeerTube/shared/*" ],
|
||||
"@/*": [
|
||||
"src/*"
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 8080
|
||||
}
|
||||
})
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = {
|
||||
publicPath: '/'
|
||||
}
|
6741
client/yarn.lock
6741
client/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -36,9 +36,8 @@ const apiRoute = '/api/' + API_VERSION
|
|||
app.use(apiRoute, apiRouter)
|
||||
|
||||
// Static client files
|
||||
app.use('/js/', express.static(join(__dirname, '../client/dist/js'), { maxAge: '30d' }))
|
||||
app.use('/css/', express.static(join(__dirname, '../client/dist/css'), { maxAge: '30d' }))
|
||||
app.use('/img/', express.static(join(__dirname, '../client/dist/img'), { maxAge: '30d' }))
|
||||
app.use('/assets/', express.static(join(__dirname, '../client/dist/assets'), { maxAge: '30d' }))
|
||||
app.use('/theme/', express.static(join(__dirname, './themes'), { maxAge: '30d' }))
|
||||
|
||||
app.use('/opensearch.xml', async function (req, res) {
|
||||
|
|
Loading…
Reference in New Issue