mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2024-11-08 08:10:08 +00:00
Add TS config and I18n
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
da0e0742f7
commit
55ab9ddf5d
17 changed files with 322 additions and 1137 deletions
1107
package-lock.json
generated
1107
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -5,13 +5,16 @@
|
|||
"codejar": "^4.2.0",
|
||||
"mitt": "^3.0.1",
|
||||
"prismjs": "^1.29.0",
|
||||
"vue": "^3.4.27",
|
||||
"vue": "^3.4.28",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-router": "^4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.24.7",
|
||||
"@types/bootstrap": "^5.2.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.13.0",
|
||||
"@typescript-eslint/parser": "^7.13.0",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"esbuild": "^0.21.5",
|
||||
"esbuild-plugin-vue3": "^0.4.2",
|
||||
"esbuild-sass-plugin": "^3.3.1",
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
class="dropdown-item"
|
||||
href="#"
|
||||
@click.prevent="logout"
|
||||
>Sign-out</a>
|
||||
>{{ $t('nav.signOut') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
@ -64,7 +64,7 @@ import { Dropdown } from 'bootstrap'
|
|||
export default defineComponent({
|
||||
computed: {
|
||||
profileImage(): string {
|
||||
return this.$root.userInfo?.profile_image_url || ''
|
||||
return this.$root?.userInfo?.profile_image_url || ''
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -76,7 +76,7 @@ export default defineComponent({
|
|||
|
||||
mounted() {
|
||||
if (this.isLoggedIn) {
|
||||
new Dropdown(this.$refs.userMenuToggle)
|
||||
new Dropdown(this.$refs.userMenuToggle as Element)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
87
src/components/_sideNav.vue
Normal file
87
src/components/_sideNav.vue
Normal file
|
@ -0,0 +1,87 @@
|
|||
<template>
|
||||
<div class="nav flex-grow-1">
|
||||
<template
|
||||
v-for="section in navigation"
|
||||
:key="section.header"
|
||||
>
|
||||
<div class="navHeading">
|
||||
{{ section.header }}
|
||||
</div>
|
||||
<RouterLink
|
||||
v-for="link in section.links"
|
||||
:key="link.target"
|
||||
:to="{name: link.target}"
|
||||
class="nav-link"
|
||||
>
|
||||
<i :class="`${link.icon} fa-fw me-1`" />
|
||||
{{ link.name }}
|
||||
</RouterLink>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
|
||||
export default defineComponent({
|
||||
components: { RouterLink },
|
||||
|
||||
data() {
|
||||
return {
|
||||
navigation: [
|
||||
{
|
||||
header: this.$t('menu.headers.core'),
|
||||
links: [
|
||||
{ icon: 'fas fa-chart-area', name: this.$t('menu.dashboard'), target: 'dashboard' },
|
||||
{ icon: 'fas fa-cog', name: this.$t('menu.generalSettings'), target: 'generalSettings' },
|
||||
],
|
||||
},
|
||||
{
|
||||
header: this.$t('menu.headers.chatInteraction'),
|
||||
links: [
|
||||
{ icon: 'fas fa-envelope-open-text', name: this.$t('menu.autoMessages'), target: 'autoMessagesList' },
|
||||
{ icon: 'fas fa-inbox', name: this.$t('menu.rules'), target: 'rulesList' },
|
||||
],
|
||||
},
|
||||
{
|
||||
header: this.$t('menu.headers.modules'),
|
||||
links: [{ icon: 'fas fa-dice', name: this.$t('menu.raffles'), target: 'rafflesList' }],
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
name: 'TwitchBotEditorSideNav',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.nav {
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.nav>.nav-link {
|
||||
align-items: center;
|
||||
color: inherit;
|
||||
display: flex;
|
||||
padding-bottom: 0.75rem;
|
||||
padding-left: 1.5rem;
|
||||
padding-top: 0.75rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav>.nav-link.disabled {
|
||||
color: var(--bs-nav-link-disabled-color);
|
||||
}
|
||||
|
||||
.navHeading {
|
||||
color: color-mix(in srgb, var(--bs-body-color) 50%, transparent);
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
padding: 1.75rem 1rem 0.75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
11
src/components/_template.vue
Normal file
11
src/components/_template.vue
Normal file
|
@ -0,0 +1,11 @@
|
|||
<template>
|
||||
<!---->
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TwitchBotEditor...',
|
||||
})
|
||||
</script>
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { defineComponent, type PropType } from 'vue'
|
||||
import { Toast } from 'bootstrap'
|
||||
|
||||
export type ToastContent = {
|
||||
|
@ -36,7 +36,7 @@ export type ToastContent = {
|
|||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
hdl: null,
|
||||
hdl: null as Toast | null,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -72,11 +72,15 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.$refs.toast.addEventListener('hidden.bs.toast', () => this.$emit('hidden'))
|
||||
this.hdl = new Toast(this.$refs.toast, {
|
||||
const t: Element = this.$refs.toast as Element
|
||||
|
||||
t.addEventListener('hidden.bs.toast', () => this.$emit('hidden'))
|
||||
|
||||
this.hdl = new Toast(t, {
|
||||
autohide: this.toast.autoHide !== false,
|
||||
delay: this.toast.delay || 5000,
|
||||
})
|
||||
|
||||
this.hdl.show()
|
||||
},
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Toast, { ToastContent } from './_toast.vue'
|
||||
import Toast, { type ToastContent } from './_toast.vue'
|
||||
import BusEventTypes from '../helpers/busevents'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
|
@ -30,9 +30,9 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.bus.on(BusEventTypes.Toast, (toast: ToastContent) => this.toasts.push({
|
||||
...toast,
|
||||
id: toast.id || crypto.randomUUID(),
|
||||
this.bus.on(BusEventTypes.Toast, (toast: unknown) => this.toasts.push({
|
||||
...toast as ToastContent,
|
||||
id: (toast as ToastContent).id || crypto.randomUUID(),
|
||||
}))
|
||||
},
|
||||
|
||||
|
|
|
@ -4,47 +4,7 @@
|
|||
|
||||
<div class="layout">
|
||||
<div class="layoutNav bg-body-tertiary d-flex">
|
||||
<div class="nav flex-grow-1">
|
||||
<div class="layoutNavHeading">
|
||||
Core
|
||||
</div>
|
||||
<a
|
||||
href="#"
|
||||
class="nav-link"
|
||||
>
|
||||
<i class="fas fa-cog fa-fw me-1" />
|
||||
General Settings
|
||||
</a>
|
||||
|
||||
<div class="layoutNavHeading">
|
||||
Chat Interaction
|
||||
</div>
|
||||
<a
|
||||
href="#"
|
||||
class="nav-link"
|
||||
>
|
||||
<i class="fas fa-envelope-open-text fa-fw me-1" />
|
||||
Auto-Messages
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="nav-link"
|
||||
>
|
||||
<i class="fas fa-inbox fa-fw me-1" />
|
||||
Rules
|
||||
</a>
|
||||
|
||||
<div class="layoutNavHeading">
|
||||
Modules
|
||||
</div>
|
||||
<a
|
||||
href="#"
|
||||
class="nav-link"
|
||||
>
|
||||
<i class="fas fa-dice fa-fw me-1" />
|
||||
Raffle
|
||||
</a>
|
||||
</div>
|
||||
<SideNav />
|
||||
</div>
|
||||
<div class="layoutContent">
|
||||
<router-view />
|
||||
|
@ -55,17 +15,10 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
<script setup lang="ts">
|
||||
import HeadNav from './_headNav.vue'
|
||||
import SideNav from './_sideNav.vue'
|
||||
import Toaster from './_toaster.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { HeadNav, Toaster },
|
||||
|
||||
name: 'TwitchBotEditorApp',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -93,32 +46,4 @@ export default defineComponent({
|
|||
width: 225px;
|
||||
z-index: 900;
|
||||
}
|
||||
|
||||
.layoutNav>.nav {
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.layoutNav>.nav>.nav-link {
|
||||
align-items: center;
|
||||
color: inherit;
|
||||
display: flex;
|
||||
padding-bottom: 0.75rem;
|
||||
padding-left: 1.5rem;
|
||||
padding-top: 0.75rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layoutNav>.nav>.nav-link.disabled {
|
||||
color: var(--bs-nav-link-disabled-color);
|
||||
}
|
||||
|
||||
.layoutNavHeading {
|
||||
color: color-mix(in srgb, var(--bs-body-color) 50%, transparent);
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
padding: 1.75rem 1rem 0.75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
|
|
13
src/components/dashboard.vue
Normal file
13
src/components/dashboard.vue
Normal file
|
@ -0,0 +1,13 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<!---->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TwitchBotEditorDashboard',
|
||||
})
|
||||
</script>
|
|
@ -27,10 +27,10 @@ export default defineComponent({
|
|||
|
||||
computed: {
|
||||
authURL() {
|
||||
const scopes = []
|
||||
const scopes: string[] = []
|
||||
|
||||
const params = new URLSearchParams()
|
||||
params.set('client_id', this.$root.vars.TwitchClientID)
|
||||
params.set('client_id', this.$root?.vars?.TwitchClientID || '')
|
||||
params.set('redirect_uri', window.location.href.split('#')[0].split('?')[0])
|
||||
params.set('response_type', 'token')
|
||||
params.set('scope', scopes.join(' '))
|
||||
|
@ -52,8 +52,8 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.bus.on(BusEventTypes.LoginProcessing, (loading: boolean) => {
|
||||
this.loading = loading
|
||||
this.bus.on(BusEventTypes.LoginProcessing as string, (loading: unknown) => {
|
||||
this.loading = loading as boolean
|
||||
})
|
||||
},
|
||||
|
||||
|
|
31
src/global.d.ts
vendored
Normal file
31
src/global.d.ts
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* eslint-disable no-unused-vars */
|
||||
|
||||
import { Emitter, EventType } from 'mitt'
|
||||
|
||||
type EditorVars = {
|
||||
DefaultBotScopes: string[]
|
||||
IRCBadges: string[]
|
||||
KnownEvents: string[]
|
||||
TemplateFunctions: string[]
|
||||
TwitchClientID: string
|
||||
Version: string
|
||||
}
|
||||
|
||||
type UserInfo = {
|
||||
display_name: string
|
||||
id: string
|
||||
login: string
|
||||
profile_image_url: string
|
||||
}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
bus: Emitter<Record<EventType, unknown>>
|
||||
|
||||
// On the $root
|
||||
userInfo: UserInfo | null
|
||||
vars: EditorVars | null
|
||||
}
|
||||
}
|
||||
|
||||
export {} // Important! See note.
|
|
@ -1,4 +1,4 @@
|
|||
import { ToastContent } from '../components/_toast.vue'
|
||||
import { type ToastContent } from '../components/_toast.vue'
|
||||
|
||||
/**
|
||||
* Create the content of an error-toast
|
||||
|
|
16
src/i18n.ts
Normal file
16
src/i18n.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { createI18n } from 'vue-i18n'
|
||||
import en from './langs/en.json'
|
||||
|
||||
const cookieSet = Object.fromEntries(document.cookie.split('; ')
|
||||
.map(el => el.split('=')
|
||||
.map(el => decodeURIComponent(el))))
|
||||
|
||||
export default createI18n({
|
||||
fallbackLocale: 'en',
|
||||
globalInjection: true,
|
||||
legacy: false,
|
||||
locale: cookieSet.lang || navigator?.language || 'en',
|
||||
messages: {
|
||||
en,
|
||||
},
|
||||
})
|
17
src/langs/en.json
Normal file
17
src/langs/en.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"menu": {
|
||||
"headers": {
|
||||
"chatInteraction": "Chat Interaction",
|
||||
"core": "Core",
|
||||
"modules": "Modules"
|
||||
},
|
||||
"autoMessages": "Auto-Messages",
|
||||
"dashboard": "Dashboard",
|
||||
"generalSettings": "General Settings",
|
||||
"raffles": "Raffles",
|
||||
"rules": "Rules"
|
||||
},
|
||||
"nav": {
|
||||
"signOut": "Sign-Out"
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import BusEventTypes from './helpers/busevents'
|
|||
import ConfigNotifyListener from './helpers/configNotify'
|
||||
import { errorToast } from './helpers/toasts'
|
||||
|
||||
import i18n from './i18n'
|
||||
import router from './router'
|
||||
import App from './components/app.vue'
|
||||
import Login from './components/login.vue'
|
||||
|
@ -188,5 +189,7 @@ const app = createApp({
|
|||
})
|
||||
|
||||
app.config.globalProperties.bus = mitt()
|
||||
app.config.globalProperties.$foo = 'bare'
|
||||
app.use(i18n)
|
||||
app.use(router)
|
||||
app.mount('#app')
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
import { createRouter, createMemoryHistory } from 'vue-router'
|
||||
import { createRouter, createWebHashHistory, type RouteRecordRaw } from 'vue-router'
|
||||
|
||||
//import AuthView from './components/auth.vue'
|
||||
//import ChatView from './components/chatview.vue'
|
||||
|
||||
const Root = {}
|
||||
import Dashboard from './components/dashboard.vue'
|
||||
|
||||
const routes = [
|
||||
// {
|
||||
// component: AuthView,
|
||||
// path: '/',
|
||||
// },
|
||||
// {
|
||||
// component: ChatView,
|
||||
// path: '/chat',
|
||||
// },
|
||||
{
|
||||
component: Root,
|
||||
name: 'root',
|
||||
path: '/',
|
||||
}
|
||||
]
|
||||
{ component: Dashboard, name: 'dashboard', path: '/' },
|
||||
|
||||
// General settings
|
||||
{ component: {}, name: 'generalSettings', path: '/general-settings' },
|
||||
|
||||
// Auto-Messages
|
||||
{ component: {}, name: 'autoMessagesList', path: '/auto-messages' },
|
||||
{ component: {}, name: 'autoMessageEdit', path: '/auto-messages/edit/{id}' },
|
||||
{ component: {}, name: 'autoMessageNew', path: '/auto-messages/new' },
|
||||
|
||||
// Rules
|
||||
{ component: {}, name: 'rulesList', path: '/rules' },
|
||||
{ component: {}, name: 'rulesEdit', path: '/rules/edit/{id}' },
|
||||
{ component: {}, name: 'rulesNew', path: '/rules/new' },
|
||||
|
||||
// Raffles
|
||||
{ component: {}, name: 'rafflesList', path: '/raffles' },
|
||||
{ component: {}, name: 'rafflesEdit', path: '/raffles/edit/{id}' },
|
||||
{ component: {}, name: 'rafflesNew', path: '/raffles/new' },
|
||||
] as RouteRecordRaw[]
|
||||
|
||||
const router = createRouter({
|
||||
history: createMemoryHistory(),
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
|
|
9
tsconfig.json
Normal file
9
tsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"src/components/_template.vue"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue