Add CI
This commit is contained in:
parent
c6fb1528ea
commit
ee532dfd30
|
@ -0,0 +1,38 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
name: build
|
||||
|
||||
steps:
|
||||
- name: install
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- apk add git
|
||||
- npm install
|
||||
|
||||
- name: build
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- npm run build
|
||||
depends_on:
|
||||
- install
|
||||
|
||||
- name: publish
|
||||
image: alpine
|
||||
depends_on:
|
||||
- build
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
environment:
|
||||
USERNAME:
|
||||
from_secret: ftp_username
|
||||
PASSWORD:
|
||||
from_secret: ftp_password
|
||||
APIKEY:
|
||||
from_secret: api_key
|
||||
commands:
|
||||
- apk --no-cache add lftp curl
|
||||
- cd dist
|
||||
- 'curl -X DELETE -H "AccessKey: $PASSWORD" https://storage.bunnycdn.com/mercuryapp/'
|
||||
- 'lftp -e "mirror -P 10 -R" -u $USERNAME,$PASSWORD storage.bunnycdn.com'
|
||||
- 'curl -X POST -H "AccessKey: $APIKEY" https://bunnycdn.com/api/pullzone/733874/purgeCache --data ""'
|
|
@ -17,6 +17,7 @@
|
|||
"reconnecting-websocket": "^4.4.0",
|
||||
"romulus-js": "git+https://git.jacknet.io/TerribleCodeClub/romulus-js.git",
|
||||
"uuid": "^8.3.2",
|
||||
"vanilla-picker": "^2.12.1",
|
||||
"vue": "^3.2.25",
|
||||
"vue-router": "^4.0.14"
|
||||
},
|
||||
|
@ -46,6 +47,11 @@
|
|||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@sphinxxxx/color-conversion": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz",
|
||||
"integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw=="
|
||||
},
|
||||
"node_modules/@types/color": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.3.tgz",
|
||||
|
@ -878,6 +884,14 @@
|
|||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vanilla-picker": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.1.tgz",
|
||||
"integrity": "sha512-2qrEP9VYylKXbyzXKsbu2dferBTvqnlsr29XjHwFE+/MEp0VNj6oEUESLDtKZ7DWzGdSv1x/+ujqFZF+KsO3cg==",
|
||||
"dependencies": {
|
||||
"@sphinxxxx/color-conversion": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "2.8.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-2.8.6.tgz",
|
||||
|
@ -954,6 +968,11 @@
|
|||
"integrity": "sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==",
|
||||
"peer": true
|
||||
},
|
||||
"@sphinxxxx/color-conversion": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz",
|
||||
"integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw=="
|
||||
},
|
||||
"@types/color": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.3.tgz",
|
||||
|
@ -1479,6 +1498,14 @@
|
|||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"vanilla-picker": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.1.tgz",
|
||||
"integrity": "sha512-2qrEP9VYylKXbyzXKsbu2dferBTvqnlsr29XjHwFE+/MEp0VNj6oEUESLDtKZ7DWzGdSv1x/+ujqFZF+KsO3cg==",
|
||||
"requires": {
|
||||
"@sphinxxxx/color-conversion": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"vite": {
|
||||
"version": "2.8.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-2.8.6.tgz",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"reconnecting-websocket": "^4.4.0",
|
||||
"romulus-js": "git+https://git.jacknet.io/TerribleCodeClub/romulus-js.git",
|
||||
"uuid": "^8.3.2",
|
||||
"vanilla-picker": "^2.12.1",
|
||||
"vue": "^3.2.25",
|
||||
"vue-router": "^4.0.14"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<template>
|
||||
|
||||
<div ref="picker" id="picker" class="btn"><div class="label">Set username color</div></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Color from 'color';
|
||||
import Picker from 'vanilla-picker'
|
||||
import { inject, onMounted, ref } from 'vue';
|
||||
import { useUserStore } from '../../stores/userStore';
|
||||
|
||||
const requestUserData = inject('requestUserData')
|
||||
const userStore = useUserStore()
|
||||
|
||||
const self = userStore.getSelf()
|
||||
|
||||
const picker = ref(null)
|
||||
const usernameColor = ref(Color())
|
||||
|
||||
const bootstrapPrimaryColor = getComputedStyle(document.documentElement).getPropertyValue('--bs-primary')
|
||||
|
||||
onMounted(() => {
|
||||
const p = new Picker(picker.value)
|
||||
|
||||
p.setOptions({
|
||||
alpha: false,
|
||||
color: self.color.hex() ?? bootstrapPrimaryColor
|
||||
})
|
||||
|
||||
picker.value.style.backgroundColor = self.color.hex() ?? bootstrapPrimaryColor
|
||||
|
||||
p.onChange = function(color) {
|
||||
picker.value.style.backgroundColor = color.rgbaString
|
||||
}
|
||||
|
||||
p.onOpen = function(color) {
|
||||
usernameColor.value = Color(color.hex)
|
||||
}
|
||||
|
||||
p.onDone = function(color) {
|
||||
usernameColor.value = Color(color.hex)
|
||||
picker.value.style.backgroundColor = color.rgbaString
|
||||
|
||||
userStore.setColor(-1, Color(color.hex))
|
||||
requestUserData()
|
||||
}
|
||||
|
||||
p.onClose = function(color) {
|
||||
picker.value.style.backgroundColor = usernameColor.value.hex()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
#picker .label {
|
||||
background: inherit;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
filter: invert(1) grayscale(1) contrast(9);
|
||||
}
|
||||
</style>
|
|
@ -8,5 +8,13 @@ import { computed } from 'vue'
|
|||
const props = defineProps(['user'])
|
||||
const user = props.user
|
||||
|
||||
const color = computed(() => { return user.color?.hex() ?? '#6c757d' })
|
||||
const bootstrapSecondaryColor = getComputedStyle(document.documentElement).getPropertyValue('--bs-secondary')
|
||||
|
||||
const color = computed(() => { return user.color?.hex() ?? bootstrapSecondaryColor })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
span:hover {
|
||||
color: white !important;
|
||||
}
|
||||
</style>
|
|
@ -5,6 +5,7 @@ import { useUserStore } from '../stores/userStore'
|
|||
import { useMessageStore } from '../stores/messageStore'
|
||||
import { useChannelStore } from '../stores/channelStore'
|
||||
import { decrypt } from 'romulus-js'
|
||||
import { provide } from 'vue'
|
||||
|
||||
const CLIENT_ID = 'Mercury'
|
||||
const SUBSCRIBED_MESSAGE_TYPES = [MessageTypes.Basic, MessageTypes.UserDataRequest, MessageTypes.UserDataResponse]
|
||||
|
@ -105,6 +106,8 @@ export default {
|
|||
})
|
||||
}
|
||||
|
||||
app.provide('requestUserData', requestUserData)
|
||||
|
||||
// Keepalive timeout.
|
||||
var timeout = setInterval(() => {
|
||||
ws.send(packers[MessageTypes.Keepalive]())
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
<template v-slot:title>Welcome to Mercury!</template>
|
||||
<template v-slot:content>
|
||||
<div class="d-flex flex-column text-center align-items-center px-5 overflow-hidden">
|
||||
<img class="animate__animated animate__rotateIn py-5 w-25" id="logo" src="../assets/logo-light.png" />
|
||||
<h1 class="animate__animated animate__fadeInDown animate__delay-1s">
|
||||
<img class="animate__animated animate__rollIn py-5 w-25" id="logo" src="../assets/logo-light.png" />
|
||||
<h1 class="animate__animated animate__zoomIn">
|
||||
Mercury is a web-based BENNC client.
|
||||
</h1>
|
||||
<h2 class="animate__animated animate__fadeInDown animate__delay-2s">
|
||||
<h2 class="animate__animated animate__zoomIn">
|
||||
Go to <router-link :to="{ name: 'Settings' }" class="text-muted"><i class="bi bi-gear-fill"></i> Settings</router-link> to configure your client.
|
||||
</h2>
|
||||
</div>
|
||||
|
@ -26,10 +26,10 @@ import Content from '../components/Content.vue'
|
|||
#logo {
|
||||
filter: invert(80%);
|
||||
}
|
||||
h1 {
|
||||
/* h1 {
|
||||
--animate-delay: 0.5s;
|
||||
}
|
||||
h2 {
|
||||
--animate-delay: 0.5s;
|
||||
}
|
||||
} */
|
||||
</style>
|
|
@ -3,8 +3,16 @@
|
|||
<Content>
|
||||
<template v-slot:title>Settings</template>
|
||||
<template v-slot:content>
|
||||
<h3>User</h3>
|
||||
<div class="mb-5">
|
||||
<div class="input-group mb-3">
|
||||
<input @keyup.enter="saveUsername" v-model="username" type="text" class="form-control" placeholder="Username" aria-label="Username">
|
||||
<button @click="saveUsername" class="btn btn-primary" type="button">Save</button>
|
||||
</div>
|
||||
<ColorPicker></ColorPicker>
|
||||
</div>
|
||||
<h3>Channels</h3>
|
||||
<table class="table">
|
||||
<table class="table mb-5">
|
||||
<thead>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Key</th>
|
||||
|
@ -38,8 +46,23 @@ import { useChannelStore } from '../stores/channelStore'
|
|||
import Key from '../components/common/Key.vue'
|
||||
import Sidebar from '../components/Sidebar.vue'
|
||||
import Content from '../components/Content.vue'
|
||||
import ColorPicker from '../components/settings/ColorPicker.vue';
|
||||
import { inject, ref } from 'vue';
|
||||
import { useUserStore } from '../stores/userStore';
|
||||
|
||||
const channelStore = useChannelStore()
|
||||
const userStore = useUserStore()
|
||||
const requestUserData = inject('requestUserData')
|
||||
|
||||
const self = userStore.getSelf()
|
||||
|
||||
const username = ref('')
|
||||
username.value = self.name
|
||||
|
||||
function saveUsername() {
|
||||
userStore.setName(-1, username.value)
|
||||
requestUserData()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scope>
|
||||
|
|
Loading…
Reference in New Issue