mirror of
https://github.com/Troplo/Colubrina.git
synced 2024-11-23 03:36:42 +11:00
v1.0.13
This commit is contained in:
parent
344fce43ab
commit
e2cb2adff6
22 changed files with 436 additions and 532 deletions
|
@ -4,8 +4,6 @@ let express = require("express")
|
||||||
let app = express()
|
let app = express()
|
||||||
let bodyParser = require("body-parser")
|
let bodyParser = require("body-parser")
|
||||||
let os = require("os")
|
let os = require("os")
|
||||||
const cookieParser = require("cookie-parser")
|
|
||||||
app.use(cookieParser())
|
|
||||||
app.set("trust proxy", true)
|
app.set("trust proxy", true)
|
||||||
const socket = require("./lib/socket")
|
const socket = require("./lib/socket")
|
||||||
const server = require("http").createServer(app)
|
const server = require("http").createServer(app)
|
||||||
|
@ -45,7 +43,6 @@ app.all("/api/*", (req, res) => {
|
||||||
console.log(os.hostname())
|
console.log(os.hostname())
|
||||||
|
|
||||||
app.use(require("./lib/errorHandler"))
|
app.use(require("./lib/errorHandler"))
|
||||||
|
|
||||||
server.listen(23998, () => {
|
server.listen(23998, () => {
|
||||||
console.log("Initialized")
|
console.log("Initialized")
|
||||||
console.log("Listening on port 0.0.0.0:" + 23998)
|
console.log("Listening on port 0.0.0.0:" + 23998)
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
const { User, Theme, Session } = require("../models")
|
const { User, Theme, Session } = require("../models")
|
||||||
const Errors = require("./errors")
|
const Errors = require("./errors")
|
||||||
|
const { Op } = require("sequelize")
|
||||||
module.exports = async function (req, res, next) {
|
module.exports = async function (req, res, next) {
|
||||||
try {
|
try {
|
||||||
if (req.header("Authorization") && req.header("Authorization") !== "null") {
|
if (req.header("Authorization") && req.header("Authorization") !== "null") {
|
||||||
const token = req.header("Authorization")
|
const token = req.header("Authorization")
|
||||||
const session = await Session.findOne({ where: { session: token } })
|
const session = await Session.findOne({
|
||||||
|
where: {
|
||||||
|
session: token,
|
||||||
|
expiredAt: {
|
||||||
|
[Op.gt]: new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
if (session) {
|
if (session) {
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
where: { id: session.userId },
|
where: { id: session.userId },
|
||||||
|
|
|
@ -1,53 +1,37 @@
|
||||||
const { User, Theme, Session } = require("../models")
|
const { User, Theme, Session } = require("../models")
|
||||||
|
const { Op } = require("sequelize")
|
||||||
|
|
||||||
const parseCookie = (str) =>
|
|
||||||
str
|
|
||||||
.split(";")
|
|
||||||
.map((v) => v.split("="))
|
|
||||||
.reduce((acc, v) => {
|
|
||||||
acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim())
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
module.exports = async function (socket, next) {
|
module.exports = async function (socket, next) {
|
||||||
try {
|
try {
|
||||||
const cookies = parseCookie(socket.handshake.headers.cookie)
|
const token = socket.handshake.auth.token
|
||||||
if (cookies["session"]) {
|
|
||||||
const session = await Session.findOne({
|
const session = await Session.findOne({
|
||||||
where: { session: cookies["session"] }
|
where: {
|
||||||
|
session: token,
|
||||||
|
expiredAt: {
|
||||||
|
[Op.gt]: new Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if (session) {
|
if (session) {
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
where: { id: session.userId },
|
where: { id: session.userId },
|
||||||
attributes: {
|
attributes: {
|
||||||
exclude: ["totp", "password", "emailToken"]
|
exclude: ["totp", "compassSession", "password"]
|
||||||
},
|
},
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: Theme,
|
model: Theme,
|
||||||
as: "themeObject"
|
as: "themeObject"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
raw: true
|
|
||||||
})
|
})
|
||||||
if (user) {
|
if (user) {
|
||||||
if (user.banned) {
|
await user.update({
|
||||||
socket.user = {
|
lastSeenAt: new Date().toISOString()
|
||||||
id: null,
|
})
|
||||||
username: "Not Authenticated"
|
|
||||||
}
|
|
||||||
next()
|
|
||||||
} else {
|
|
||||||
socket.user = user
|
socket.user = user
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
socket.user = {
|
|
||||||
id: null,
|
|
||||||
username: "Not Authenticated"
|
|
||||||
}
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
socket.user = {
|
socket.user = {
|
||||||
id: null,
|
id: null,
|
||||||
|
|
|
@ -45,7 +45,8 @@ let Errors = {
|
||||||
401
|
401
|
||||||
],
|
],
|
||||||
mailFail: ["There was an error sending the verification email.", 400],
|
mailFail: ["There was an error sending the verification email.", 400],
|
||||||
invalidToken: ["The token you provided is invalid.", 400]
|
invalidToken: ["The token you provided is invalid.", 400],
|
||||||
|
cannotFriendYourself: ["You cannot friend yourself.", 400]
|
||||||
}
|
}
|
||||||
|
|
||||||
function processErrors(errorName) {
|
function processErrors(errorName) {
|
||||||
|
|
|
@ -122,126 +122,10 @@ module.exports = {
|
||||||
socket.emit("unauthorized", {
|
socket.emit("unauthorized", {
|
||||||
message: "Please reauth."
|
message: "Please reauth."
|
||||||
})
|
})
|
||||||
socket.on("token", async (token) => {
|
socket.on("token", async () => {
|
||||||
const session = await Session.findOne({ where: { session: token } })
|
socket.emit("unsupported", {
|
||||||
if (session) {
|
message: "This authentication method is unsupported."
|
||||||
const user = await User.findOne({
|
|
||||||
where: { id: session.userId },
|
|
||||||
attributes: {
|
|
||||||
exclude: ["totp", "password", "emailToken"]
|
|
||||||
},
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Theme,
|
|
||||||
as: "themeObject"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
if (user) {
|
|
||||||
socket.user = user
|
|
||||||
socket.join(user.id)
|
|
||||||
socket.emit("authorized")
|
|
||||||
socket.join(user.id)
|
|
||||||
socket.emit("siteState", {
|
|
||||||
release: process.env.RELEASE,
|
|
||||||
notification: process.env.NOTIFICATION,
|
|
||||||
notificationType: process.env.NOTIFICATION_TYPE,
|
|
||||||
latestVersion: require("../../frontend/package.json").version
|
|
||||||
})
|
|
||||||
const friends = await Friend.findAll({
|
|
||||||
where: {
|
|
||||||
userId: user.id,
|
|
||||||
status: "accepted"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await user.update({
|
|
||||||
status:
|
|
||||||
user.storedStatus === "invisible"
|
|
||||||
? "offline"
|
|
||||||
: user.storedStatus
|
|
||||||
})
|
|
||||||
friends.forEach((friend) => {
|
|
||||||
io.to(friend.friendId).emit("userStatus", {
|
|
||||||
userId: user.id,
|
|
||||||
status:
|
|
||||||
user.storedStatus === "invisible"
|
|
||||||
? "offline"
|
|
||||||
: user.storedStatus
|
|
||||||
})
|
|
||||||
})
|
|
||||||
socket.on("ping", () => {
|
|
||||||
socket.emit("pong")
|
|
||||||
})
|
|
||||||
socket.on("bcBots/deleteMessage", (e) => {
|
|
||||||
if (socket.user.bot) {
|
|
||||||
socket.to(e.userId).emit("deleteMessage", e)
|
|
||||||
} else {
|
|
||||||
socket.emit("bcBots/deleteMessage", {
|
|
||||||
error: "You cannot perform this action."
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
socket.on("idle", async () => {
|
|
||||||
const user = await User.findOne({
|
|
||||||
where: {
|
|
||||||
id: socket.user.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (user.storedStatus === "online") {
|
|
||||||
friends.forEach((friend) => {
|
|
||||||
io.to(friend.friendId).emit("userStatus", {
|
|
||||||
userId: user.id,
|
|
||||||
status: "away"
|
|
||||||
})
|
|
||||||
})
|
|
||||||
io.to(user.id).emit("userStatus", {
|
|
||||||
userId: user.id,
|
|
||||||
status: "away"
|
|
||||||
})
|
|
||||||
await user.update({
|
|
||||||
status: "away"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
socket.on("online", async () => {
|
|
||||||
const user = await User.findOne({
|
|
||||||
where: {
|
|
||||||
id: socket.user.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (user.storedStatus === "online") {
|
|
||||||
friends.forEach((friend) => {
|
|
||||||
io.to(friend.friendId).emit("userStatus", {
|
|
||||||
userId: user.id,
|
|
||||||
status: "online"
|
|
||||||
})
|
|
||||||
})
|
|
||||||
io.to(user.id).emit("userStatus", {
|
|
||||||
userId: user.id,
|
|
||||||
status: "online"
|
|
||||||
})
|
|
||||||
await user.update({
|
|
||||||
status: "online"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
socket.on("disconnect", async function () {
|
|
||||||
const clients =
|
|
||||||
io.sockets.adapter.rooms.get(user.id) || new Set()
|
|
||||||
if (!clients.size || clients.size === 0) {
|
|
||||||
friends.forEach((friend) => {
|
|
||||||
io.to(friend.friendId).emit("userStatus", {
|
|
||||||
userId: user.id,
|
|
||||||
status: "offline"
|
|
||||||
})
|
|
||||||
})
|
|
||||||
await user.update({
|
|
||||||
status: "offline"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
console.log("Unauthenticated user")
|
console.log("Unauthenticated user")
|
||||||
socket.on("reAuth", async () => {
|
socket.on("reAuth", async () => {
|
||||||
|
|
|
@ -50,6 +50,9 @@ router.post("/", auth, async (req, res, next) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (user) {
|
if (user) {
|
||||||
|
if (user.id === req.user.id) {
|
||||||
|
throw Errors.cannotFriendYourself
|
||||||
|
}
|
||||||
const friend = await Friend.findOne({
|
const friend = await Friend.findOne({
|
||||||
where: {
|
where: {
|
||||||
userId: req.user.id,
|
userId: req.user.id,
|
||||||
|
|
|
@ -133,27 +133,29 @@ router.post("/verify/resend", auth, mailLimiter, async (req, res, next) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post("/verify/confirm/:token", auth, async (req, res, next) => {
|
router.post("/verify/confirm/:token", async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const user = await User.findOne({
|
|
||||||
where: {
|
|
||||||
id: req.user.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (process.env.EMAIL_VERIFICATION !== "true") {
|
if (process.env.EMAIL_VERIFICATION !== "true") {
|
||||||
throw Errors.invalidParameter("Email verification is disabled")
|
throw Errors.invalidParameter("Email verification is disabled")
|
||||||
}
|
}
|
||||||
if (!req.params.token) {
|
if (!req.params.token) {
|
||||||
throw Errors.invalidToken
|
throw Errors.invalidToken
|
||||||
}
|
}
|
||||||
if (req.params.token !== user.emailToken) {
|
const user = await User.findOne({
|
||||||
throw Errors.invalidToken
|
where: {
|
||||||
|
emailToken: req.params.token,
|
||||||
|
emailVerified: false
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
if (user) {
|
||||||
await user.update({
|
await user.update({
|
||||||
emailVerified: true,
|
emailVerified: true,
|
||||||
emailToken: null
|
emailToken: null
|
||||||
})
|
})
|
||||||
res.json({ success: true })
|
res.json({ success: true })
|
||||||
|
} else {
|
||||||
|
throw Errors.invalidToken
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
next(e)
|
next(e)
|
||||||
}
|
}
|
||||||
|
@ -198,12 +200,6 @@ router.post("/login", async (req, res, next) => {
|
||||||
osVersion: ua.os.version
|
osVersion: ua.os.version
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
res.cookie("session", session.session, {
|
|
||||||
maxAge: 1000 * 60 * 60 * 24 * 365,
|
|
||||||
httpOnly: true,
|
|
||||||
secure: false,
|
|
||||||
sameSite: "strict"
|
|
||||||
})
|
|
||||||
res.json({
|
res.json({
|
||||||
session: session.session,
|
session: session.session,
|
||||||
success: true,
|
success: true,
|
||||||
|
@ -287,12 +283,6 @@ router.post("/register", limiter, async (req, res, next) => {
|
||||||
osVersion: ua.os.version
|
osVersion: ua.os.version
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
res.cookie("session", session.session, {
|
|
||||||
maxAge: 1000 * 60 * 60 * 24 * 365,
|
|
||||||
httpOnly: true,
|
|
||||||
secure: false,
|
|
||||||
sameSite: "strict"
|
|
||||||
})
|
|
||||||
res.json({
|
res.json({
|
||||||
session: session.session,
|
session: session.session,
|
||||||
success: true,
|
success: true,
|
||||||
|
@ -371,15 +361,6 @@ router.delete("/sessions/:id", auth, async (req, res, next) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post("/logout", (req, res, next) => {
|
|
||||||
try {
|
|
||||||
res.clearCookie("session")
|
|
||||||
res.sendStatus(204)
|
|
||||||
} catch (e) {
|
|
||||||
next(e)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/settings/avatar",
|
"/settings/avatar",
|
||||||
auth,
|
auth,
|
||||||
|
|
|
@ -1,8 +1,26 @@
|
||||||
{
|
{
|
||||||
"name": "colubrina",
|
"name": "colubrina",
|
||||||
"version": "1.0.12",
|
"version": "1.0.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Troplo <troplo@troplo.com>",
|
"author": "Troplo <troplo@troplo.com>",
|
||||||
|
"build": {
|
||||||
|
"appId": "com.troplo.colubrina",
|
||||||
|
"win": {
|
||||||
|
"publish": [
|
||||||
|
"github"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"publish": [
|
||||||
|
"github"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mac": {
|
||||||
|
"publish": [
|
||||||
|
"github"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
|
@ -12,9 +30,11 @@
|
||||||
"postinstall": "patch-package && electron-builder install-app-deps",
|
"postinstall": "patch-package && electron-builder install-app-deps",
|
||||||
"postuninstall": "electron-builder install-app-deps"
|
"postuninstall": "electron-builder install-app-deps"
|
||||||
},
|
},
|
||||||
|
"main": "background.js",
|
||||||
"repository": "https://github.com/Troplo/Colubrina",
|
"repository": "https://github.com/Troplo/Colubrina",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/preset-env": "^7.17.10",
|
"@babel/preset-env": "^7.17.10",
|
||||||
|
"@mdi/font": "6.5.95",
|
||||||
"@mdi/js": "^6.6.95",
|
"@mdi/js": "^6.6.95",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"brace": "^0.11.1",
|
"brace": "^0.11.1",
|
||||||
|
@ -23,8 +43,6 @@
|
||||||
"dayjs": "^1.11.0",
|
"dayjs": "^1.11.0",
|
||||||
"ejs": "^3.1.7",
|
"ejs": "^3.1.7",
|
||||||
"glob-parent": "^5.1.2",
|
"glob-parent": "^5.1.2",
|
||||||
"graphql": "^16.3.0",
|
|
||||||
"graphql-tag": "^2.12.6",
|
|
||||||
"highlight.js": "^11.6.0",
|
"highlight.js": "^11.6.0",
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"markdown-it-emoji": "git+https://github.com/Troplo/markdown-it-unicode-emoji",
|
"markdown-it-emoji": "git+https://github.com/Troplo/markdown-it-unicode-emoji",
|
||||||
|
@ -39,16 +57,13 @@
|
||||||
"socket.io-client": "^4.5.1",
|
"socket.io-client": "^4.5.1",
|
||||||
"twemoji": "^14.0.2",
|
"twemoji": "^14.0.2",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-apollo": "^3.1.0",
|
|
||||||
"vue-axios": "^3.4.1",
|
"vue-axios": "^3.4.1",
|
||||||
"vue-chartjs": "^4.0.1",
|
"vue-chartjs": "^4.0.1",
|
||||||
"vue-final-modal": "^2.4.1",
|
"vue-final-modal": "^2.4.1",
|
||||||
"vue-matomo": "^4.1.0",
|
|
||||||
"vue-native-notification": "^1.1.1",
|
"vue-native-notification": "^1.1.1",
|
||||||
"vue-router": "^3.2.0",
|
"vue-router": "^3.2.0",
|
||||||
"vue-sanitize": "^0.2.1",
|
"vue-sanitize": "^0.2.1",
|
||||||
"vue-shortkey": "^3.1.7",
|
"vue-shortkey": "^3.1.7",
|
||||||
"vue-swatches": "^2.1.1",
|
|
||||||
"vue-toastification": "^1.7.14",
|
"vue-toastification": "^1.7.14",
|
||||||
"vue2-ace-editor": "^0.0.15",
|
"vue2-ace-editor": "^0.0.15",
|
||||||
"vuetify": "^2.6.4",
|
"vuetify": "^2.6.4",
|
||||||
|
@ -56,7 +71,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
||||||
"@mdi/font": "6.5.95",
|
|
||||||
"@vue/cli-plugin-babel": "~4.5.15",
|
"@vue/cli-plugin-babel": "~4.5.15",
|
||||||
"@vue/cli-plugin-eslint": "~4.5.15",
|
"@vue/cli-plugin-eslint": "~4.5.15",
|
||||||
"@vue/cli-plugin-pwa": "~4.5.15",
|
"@vue/cli-plugin-pwa": "~4.5.15",
|
||||||
|
|
|
@ -437,12 +437,15 @@
|
||||||
is limited.
|
is limited.
|
||||||
</v-alert>
|
</v-alert>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
<div @touchstart="touchStart" @touchend="touchEnd">
|
||||||
<router-view
|
<router-view
|
||||||
|
id="main"
|
||||||
:style="
|
:style="
|
||||||
'background-color: ' +
|
'background-color: ' +
|
||||||
$vuetify.theme.themes[$vuetify.theme.dark ? 'dark' : 'light'].bg
|
$vuetify.theme.themes[$vuetify.theme.dark ? 'dark' : 'light'].bg
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</v-main>
|
</v-main>
|
||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
@ -451,7 +454,7 @@
|
||||||
import AjaxErrorHandler from "@/lib/errorHandler"
|
import AjaxErrorHandler from "@/lib/errorHandler"
|
||||||
import { VueFinalModal } from "vue-final-modal"
|
import { VueFinalModal } from "vue-final-modal"
|
||||||
import Header from "@/components/Header"
|
import Header from "@/components/Header"
|
||||||
import Vue from "vue"
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: {
|
components: {
|
||||||
|
@ -479,7 +482,9 @@ export default {
|
||||||
results: [],
|
results: [],
|
||||||
searchInput: null,
|
searchInput: null,
|
||||||
themes: [],
|
themes: [],
|
||||||
cssTips: true
|
cssTips: true,
|
||||||
|
touchStartX: null,
|
||||||
|
touchEndX: null
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
creatorJSON: {
|
creatorJSON: {
|
||||||
|
@ -702,6 +707,19 @@ export default {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
touchEnd(event) {
|
||||||
|
this.touchEndX = event.changedTouches[0].screenX
|
||||||
|
if (this.touchEndX > this.touchStartX) {
|
||||||
|
if (this.touchEndX - this.touchStartX > 100) {
|
||||||
|
this.touchStartX = null
|
||||||
|
this.touchEndX = null
|
||||||
|
this.$store.state.drawer = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
touchStart(event) {
|
||||||
|
this.touchStartX = event.changedTouches[0].screenX
|
||||||
|
},
|
||||||
setTheme(theme) {
|
setTheme(theme) {
|
||||||
const name = theme.id
|
const name = theme.id
|
||||||
const dark = theme.dark
|
const dark = theme.dark
|
||||||
|
@ -728,23 +746,8 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
Vue.axios.defaults.headers.common["X-Colubrina"] = true
|
await this.$store.dispatch("doInit")
|
||||||
Vue.axios.defaults.headers.common["Authorization"] =
|
|
||||||
localStorage.getItem("session")
|
|
||||||
console.log(localStorage.getItem("instance"))
|
|
||||||
if (process.env.IS_ELECTRON) {
|
|
||||||
this.axios.defaults.baseURL = localStorage.getItem("instance")
|
|
||||||
this.$store.state.baseURL = localStorage.getItem("instance")
|
|
||||||
}
|
|
||||||
if (localStorage.getItem("customHeaders")) {
|
|
||||||
console.log(JSON.parse(localStorage.getItem("customHeaders")))
|
|
||||||
for (let header in JSON.parse(localStorage.getItem("customHeaders"))) {
|
|
||||||
Vue.axios.defaults.headers[header] = JSON.parse(
|
|
||||||
localStorage.getItem("customHeaders")
|
|
||||||
)[header]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.$vuetify.breakpoint.mobile) {
|
if (this.$vuetify.breakpoint.mobile) {
|
||||||
this.$store.state.drawer = false
|
this.$store.state.drawer = false
|
||||||
}
|
}
|
||||||
|
@ -772,7 +775,8 @@ export default {
|
||||||
})
|
})
|
||||||
this.$socket.connect()
|
this.$socket.connect()
|
||||||
this.$socket.on("unauthorized", () => {
|
this.$socket.on("unauthorized", () => {
|
||||||
this.$socket.emit("token", localStorage.getItem("session"))
|
console.log("Reauth requested")
|
||||||
|
this.$socket.emit("token", localStorage.getItem("token"))
|
||||||
})
|
})
|
||||||
document.title = this.$route.name
|
document.title = this.$route.name
|
||||||
? this.$route.name + " - " + this.$store.state.site.name
|
? this.$route.name + " - " + this.$store.state.site.name
|
||||||
|
@ -780,13 +784,10 @@ export default {
|
||||||
this.$store.commit("setLoading", true)
|
this.$store.commit("setLoading", true)
|
||||||
this.$vuetify.theme.dark = this.$store.state.user?.theme === "dark" || true
|
this.$vuetify.theme.dark = this.$store.state.user?.theme === "dark" || true
|
||||||
this.$store.dispatch("getState")
|
this.$store.dispatch("getState")
|
||||||
this.getThemes()
|
|
||||||
this.communicationsIdleCheck()
|
|
||||||
this.$store
|
this.$store
|
||||||
.dispatch("getUserInfo")
|
.dispatch("getUserInfo")
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log(window.location.pathname)
|
console.log(window.location.pathname)
|
||||||
// check if its /email/confirm/<token>
|
|
||||||
if (
|
if (
|
||||||
!window.location.pathname.includes("/email/confirm/") &&
|
!window.location.pathname.includes("/email/confirm/") &&
|
||||||
!window.location.pathname.includes("/email/verify") &&
|
!window.location.pathname.includes("/email/verify") &&
|
||||||
|
@ -797,10 +798,10 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
if (!["/login", "/register"].includes(this.$route.path)) {
|
|
||||||
this.$router.push("/login")
|
this.$router.push("/login")
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
this.getThemes()
|
||||||
|
this.communicationsIdleCheck()
|
||||||
this.registerSocket()
|
this.registerSocket()
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.offset-message {
|
.offset-message {
|
||||||
padding-left: 47px;
|
padding-left: 53px;
|
||||||
}
|
}
|
||||||
.message-action-card {
|
.message-action-card {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use strict"
|
"use strict"
|
||||||
|
|
||||||
import { app, protocol, BrowserWindow } from "electron"
|
import { app, protocol, BrowserWindow, screen } from "electron"
|
||||||
import { createProtocol } from "vue-cli-plugin-electron-builder/lib"
|
import { createProtocol } from "vue-cli-plugin-electron-builder/lib"
|
||||||
import installExtension, { VUEJS_DEVTOOLS } from "electron-devtools-installer"
|
import installExtension, { VUEJS_DEVTOOLS } from "electron-devtools-installer"
|
||||||
const isDevelopment = process.env.NODE_ENV !== "production"
|
const isDevelopment = process.env.NODE_ENV !== "production"
|
||||||
|
@ -12,15 +12,25 @@ protocol.registerSchemesAsPrivileged([
|
||||||
|
|
||||||
async function createWindow() {
|
async function createWindow() {
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
|
const { bounds } = screen.getDisplayNearestPoint(
|
||||||
|
screen.getCursorScreenPoint()
|
||||||
|
)
|
||||||
|
const height = Math.floor(bounds.height * (2 / 3))
|
||||||
|
const width = Math.floor(bounds.width * (2 / 3))
|
||||||
|
const y = Math.floor(bounds.y + (bounds.height - height) / 2)
|
||||||
|
const x = Math.floor(bounds.x + (bounds.width - width) / 2)
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 1400,
|
width,
|
||||||
height: 1000,
|
height,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
// Use pluginOptions.nodeIntegration, leave this alone
|
// Use pluginOptions.nodeIntegration, leave this alone
|
||||||
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
|
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
|
||||||
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
|
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
|
||||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||||
preload: "window-preload.js",
|
preload: "window-preload.js",
|
||||||
|
// required for multi-instance support
|
||||||
webSecurity: false
|
webSecurity: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
<v-textarea
|
<v-textarea
|
||||||
:style="
|
:style="
|
||||||
!$vuetify.breakpoint.mobile
|
!$vuetify.breakpoint.mobile
|
||||||
? 'margin-bottom: 3px'
|
? 'margin-bottom: 5px'
|
||||||
: 'margin-bottom: -17px'
|
: 'margin-bottom: 0px'
|
||||||
"
|
"
|
||||||
autofocus
|
autofocus
|
||||||
label="Type a message"
|
label="Type a message"
|
||||||
|
|
|
@ -307,7 +307,7 @@
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
<v-app-bar app color="bg">
|
<v-app-bar app color="dark" elevation="5" style="z-index: 15">
|
||||||
<v-app-bar-nav-icon
|
<v-app-bar-nav-icon
|
||||||
@click.stop="$store.state.drawer = !$store.state.drawer"
|
@click.stop="$store.state.drawer = !$store.state.drawer"
|
||||||
v-if="$vuetify.breakpoint.mobile || !$store.state.drawer"
|
v-if="$vuetify.breakpoint.mobile || !$store.state.drawer"
|
||||||
|
@ -381,10 +381,11 @@
|
||||||
</template>
|
</template>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
<v-navigation-drawer
|
<v-navigation-drawer
|
||||||
color="bg"
|
color="dark"
|
||||||
floating
|
|
||||||
app
|
app
|
||||||
style="max-height: 100%"
|
floating
|
||||||
|
style="max-height: 100%; z-index: 15"
|
||||||
|
class="elevation-5"
|
||||||
v-model="$store.state.drawer"
|
v-model="$store.state.drawer"
|
||||||
:width="$vuetify.breakpoint.mobile ? 270 : 320"
|
:width="$vuetify.breakpoint.mobile ? 270 : 320"
|
||||||
>
|
>
|
||||||
|
@ -414,7 +415,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="toolbar"
|
color="sheet"
|
||||||
to="/communications/friends"
|
to="/communications/friends"
|
||||||
block
|
block
|
||||||
class="mb-3 rounded-xl"
|
class="mb-3 rounded-xl"
|
||||||
|
@ -429,12 +430,12 @@
|
||||||
solo
|
solo
|
||||||
label="Search..."
|
label="Search..."
|
||||||
append-icon="mdi-magnify"
|
append-icon="mdi-magnify"
|
||||||
background-color="toolbar"
|
background-color="sheet"
|
||||||
style="margin-bottom: -18px"
|
style="margin-bottom: -18px"
|
||||||
elevation="2"
|
elevation="2"
|
||||||
v-model="search"
|
v-model="search"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
<v-toolbar color="toolbar" class="rounded-xl mb-3" elevation="2">
|
<v-toolbar color="sheet" class="rounded-xl mb-3" elevation="2">
|
||||||
<v-toolbar-title class="subtitle-1">
|
<v-toolbar-title class="subtitle-1">
|
||||||
CHATS ({{ chats.length }})
|
CHATS ({{ chats.length }})
|
||||||
</v-toolbar-title>
|
</v-toolbar-title>
|
||||||
|
@ -522,6 +523,7 @@
|
||||||
</v-container>
|
</v-container>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<v-card tile color="bg" elevation="0">
|
<v-card tile color="bg" elevation="0">
|
||||||
|
<v-divider></v-divider>
|
||||||
<v-overlay :value="!$store.state.wsConnected" absolute>
|
<v-overlay :value="!$store.state.wsConnected" absolute>
|
||||||
<v-progress-circular indeterminate size="48"></v-progress-circular>
|
<v-progress-circular indeterminate size="48"></v-progress-circular>
|
||||||
</v-overlay>
|
</v-overlay>
|
||||||
|
@ -985,7 +987,7 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
Vue.axios.defaults.headers.common["Authorization"] =
|
Vue.axios.defaults.headers.common["Authorization"] =
|
||||||
localStorage.getItem("session")
|
localStorage.getItem("token")
|
||||||
this.searchUsers()
|
this.searchUsers()
|
||||||
this.searchUsersForGroupAdmin()
|
this.searchUsersForGroupAdmin()
|
||||||
this.$store.dispatch("getChats")
|
this.$store.dispatch("getChats")
|
||||||
|
|
|
@ -37,12 +37,15 @@
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
:key="message.keyId"
|
:key="message.keyId"
|
||||||
:class="{ 'message-hover': hover }"
|
:class="{
|
||||||
|
'message-hover': hover,
|
||||||
|
'pa-0': $vuetify.breakpoint.mobile
|
||||||
|
}"
|
||||||
:id="'message-' + index"
|
:id="'message-' + index"
|
||||||
@contextmenu="show($event, 'message', message)"
|
@contextmenu="show($event, 'message', message)"
|
||||||
:style="lastMessage ? 'margin-bottom: -5px; margin-top: -5px;' : ''"
|
:style="lastMessage ? 'margin-bottom: -5px; margin-top: -5px;' : ''"
|
||||||
>
|
>
|
||||||
<v-avatar size="40" class="mr-2" v-if="!lastMessage">
|
<v-avatar size="45" class="mr-2" v-if="!lastMessage">
|
||||||
<v-img
|
<v-img
|
||||||
:src="
|
:src="
|
||||||
$store.state.baseURL + '/usercontent/' + message.user.avatar
|
$store.state.baseURL + '/usercontent/' + message.user.avatar
|
||||||
|
@ -124,7 +127,7 @@
|
||||||
no-gutters
|
no-gutters
|
||||||
>
|
>
|
||||||
<v-card
|
<v-card
|
||||||
elevaion="0"
|
elevation="0"
|
||||||
:color="
|
:color="
|
||||||
embed.type === 'embed-v1' ? embed.backgroundColor : 'bg'
|
embed.type === 'embed-v1' ? embed.backgroundColor : 'bg'
|
||||||
"
|
"
|
||||||
|
@ -308,7 +311,7 @@
|
||||||
:id="'attachment-' + index"
|
:id="'attachment-' + index"
|
||||||
:max-width="500"
|
:max-width="500"
|
||||||
:min-width="!$vuetify.breakpoint.mobile ? 400 : 0"
|
:min-width="!$vuetify.breakpoint.mobile ? 400 : 0"
|
||||||
elevaion="0"
|
elevation="0"
|
||||||
color="card"
|
color="card"
|
||||||
>
|
>
|
||||||
<v-hover
|
<v-hover
|
||||||
|
|
|
@ -69,7 +69,10 @@ Vue.use({
|
||||||
{
|
{
|
||||||
transports: ["websocket", "polling"],
|
transports: ["websocket", "polling"],
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: localStorage.getItem("session")
|
Authorization: localStorage.getItem("token")
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
token: localStorage.getItem("token")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,6 +25,7 @@ function getDirectRecipient(context, item) {
|
||||||
}
|
}
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
|
desktop: !!process.env.IS_ELECTRON,
|
||||||
online: true,
|
online: true,
|
||||||
selectedChat: null,
|
selectedChat: null,
|
||||||
chats: [],
|
chats: [],
|
||||||
|
@ -142,7 +143,7 @@ export default new Vuex.Store({
|
||||||
actions: {
|
actions: {
|
||||||
getChats(context) {
|
getChats(context) {
|
||||||
Vue.axios.defaults.headers.common["Authorization"] =
|
Vue.axios.defaults.headers.common["Authorization"] =
|
||||||
localStorage.getItem("session")
|
localStorage.getItem("token")
|
||||||
Vue.axios
|
Vue.axios
|
||||||
.get("/api/v1/communications")
|
.get("/api/v1/communications")
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -266,7 +267,7 @@ export default new Vuex.Store({
|
||||||
checkAuth() {
|
checkAuth() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
Vue.axios.defaults.headers.common["Authorization"] =
|
Vue.axios.defaults.headers.common["Authorization"] =
|
||||||
localStorage.getItem("session")
|
localStorage.getItem("token")
|
||||||
Vue.axios
|
Vue.axios
|
||||||
.get("/api/v1/user")
|
.get("/api/v1/user")
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -282,21 +283,13 @@ export default new Vuex.Store({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
logout(context) {
|
logout(context) {
|
||||||
Vue.axios
|
|
||||||
.post("/api/v1/user/logout")
|
|
||||||
.then(() => {
|
|
||||||
context.commit("setToken", null)
|
|
||||||
localStorage.removeItem("userCache")
|
localStorage.removeItem("userCache")
|
||||||
localStorage.removeItem("session")
|
localStorage.removeItem("token")
|
||||||
Vue.axios.defaults.headers.common["Authorization"] = null
|
Vue.axios.defaults.headers.common["Authorization"] = null
|
||||||
context.commit("setUser", {
|
context.commit("setUser", {
|
||||||
bcUser: null,
|
bcUser: null,
|
||||||
loggedIn: false
|
loggedIn: false
|
||||||
})
|
})
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
Vue.$toast.error("Failed to logout.")
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
generateCache() {
|
generateCache() {
|
||||||
// todo
|
// todo
|
||||||
|
@ -366,56 +359,26 @@ export default new Vuex.Store({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getUserInfo(context) {
|
doInit(context) {
|
||||||
|
if (context.state.desktop) {
|
||||||
|
Vue.axios.defaults.baseURL = localStorage.getItem("instance")
|
||||||
|
context.state.baseURL = localStorage.getItem("instance")
|
||||||
|
}
|
||||||
|
Vue.axios.defaults.headers.common["X-Colubrina"] = true
|
||||||
|
Vue.axios.defaults.headers.common["X-Colubrina-Version"] =
|
||||||
|
context.state.versioning.version
|
||||||
Vue.axios.defaults.headers.common["Authorization"] =
|
Vue.axios.defaults.headers.common["Authorization"] =
|
||||||
localStorage.getItem("session")
|
localStorage.getItem("token")
|
||||||
return new Promise((resolve, reject) => {
|
if (localStorage.getItem("customHeaders")) {
|
||||||
try {
|
for (let header in JSON.parse(localStorage.getItem("customHeaders"))) {
|
||||||
const user = JSON.parse(localStorage.getItem("userCache"))
|
Vue.axios.defaults.headers[header] = JSON.parse(
|
||||||
if (user?.id) {
|
localStorage.getItem("customHeaders")
|
||||||
context.commit("setUser", user)
|
)[header]
|
||||||
const name = user.themeObject.id
|
|
||||||
const dark = user.themeObject.theme.dark
|
|
||||||
const light = user.themeObject.theme.light
|
|
||||||
if (user.accentColor) {
|
|
||||||
user.themeObject.theme.dark.primary = user.accentColor
|
|
||||||
user.themeObject.theme.light.primary = user.accentColor
|
|
||||||
}
|
|
||||||
Vuetify.framework.theme.themes.dark = dark
|
|
||||||
Vuetify.framework.theme.themes.light = light
|
|
||||||
Vuetify.framework.theme.themes.name = name
|
|
||||||
Vuetify.framework.theme.themes.primaryType =
|
|
||||||
user.themeObject.theme.primaryType
|
|
||||||
const themeElement = document.getElementById("user-theme")
|
|
||||||
if (!themeElement) {
|
|
||||||
const style = document.createElement("style")
|
|
||||||
style.id = "user-theme"
|
|
||||||
style.innerHTML = user.themeObject.theme.css
|
|
||||||
document.head.appendChild(style)
|
|
||||||
}
|
|
||||||
const fontElement = document.getElementById("user-font")
|
|
||||||
if (!fontElement) {
|
|
||||||
const style = document.createElement("style")
|
|
||||||
style.id = "user-font"
|
|
||||||
style.innerHTML = `/* Stop from font breaking CSS code editor */
|
|
||||||
.ace_editor div {
|
|
||||||
font-family: "JetBrains Mono" !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
font-family: "${user.font}", sans-serif;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
document.head.appendChild(style)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
},
|
||||||
//
|
getUserInfo(context) {
|
||||||
}
|
function setUser(user) {
|
||||||
Vue.axios
|
|
||||||
.get("/api/v1/user")
|
|
||||||
.then((res) => {
|
|
||||||
context.commit("setUser", res.data)
|
|
||||||
try {
|
try {
|
||||||
Vue.$socket.emit("connection", {
|
Vue.$socket.emit("connection", {
|
||||||
message: true
|
message: true
|
||||||
|
@ -423,48 +386,7 @@ div {
|
||||||
} catch {
|
} catch {
|
||||||
console.log("Socket not connected")
|
console.log("Socket not connected")
|
||||||
}
|
}
|
||||||
localStorage.setItem("userCache", JSON.stringify(res.data))
|
localStorage.setItem("userCache", JSON.stringify(user))
|
||||||
const name = res.data.themeObject.id
|
|
||||||
const dark = res.data.themeObject.theme.dark
|
|
||||||
const light = res.data.themeObject.theme.light
|
|
||||||
if (res.data.accentColor) {
|
|
||||||
res.data.themeObject.theme.dark.primary = res.data.accentColor
|
|
||||||
res.data.themeObject.theme.light.primary = res.data.accentColor
|
|
||||||
}
|
|
||||||
Vuetify.framework.theme.themes.dark = dark
|
|
||||||
Vuetify.framework.theme.themes.light = light
|
|
||||||
Vuetify.framework.theme.themes.name = name
|
|
||||||
Vuetify.framework.theme.themes.primaryType =
|
|
||||||
res.data.themeObject.theme.primaryType
|
|
||||||
const themeElement = document.getElementById("user-theme")
|
|
||||||
if (!themeElement) {
|
|
||||||
const style = document.createElement("style")
|
|
||||||
style.id = "user-theme"
|
|
||||||
style.innerHTML = res.data.themeObject.theme.css
|
|
||||||
document.head.appendChild(style)
|
|
||||||
}
|
|
||||||
const fontElement = document.getElementById("user-font")
|
|
||||||
if (!fontElement) {
|
|
||||||
const style = document.createElement("style")
|
|
||||||
style.id = "user-font"
|
|
||||||
style.innerHTML = `/* Stop from font breaking CSS code editor */
|
|
||||||
.ace_editor div {
|
|
||||||
font-family: "JetBrains Mono" !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
font-family: "${res.data.font}", sans-serif;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
document.head.appendChild(style)
|
|
||||||
}
|
|
||||||
context.commit("setLoading", false)
|
|
||||||
context.commit("setOnline", true)
|
|
||||||
resolve(res.data)
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
if (JSON.parse(localStorage.getItem("userCache"))?.id) {
|
|
||||||
const user = JSON.parse(localStorage.getItem("userCache"))
|
|
||||||
const name = user.themeObject.id
|
const name = user.themeObject.id
|
||||||
const dark = user.themeObject.theme.dark
|
const dark = user.themeObject.theme.dark
|
||||||
const light = user.themeObject.theme.light
|
const light = user.themeObject.theme.light
|
||||||
|
@ -501,8 +423,128 @@ div {
|
||||||
}
|
}
|
||||||
context.commit("setLoading", false)
|
context.commit("setLoading", false)
|
||||||
context.commit("setUser", user)
|
context.commit("setUser", user)
|
||||||
resolve(user)
|
}
|
||||||
|
Vue.axios.defaults.headers.common["Authorization"] =
|
||||||
|
localStorage.getItem("token")
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const user = JSON.parse(localStorage.getItem("userCache"))
|
||||||
|
if (user?.id) {
|
||||||
|
setUser(user)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
Vue.axios
|
||||||
|
.get("/api/v1/user")
|
||||||
|
.then((res) => {
|
||||||
|
setUser(res.data)
|
||||||
|
context.commit("setLoading", false)
|
||||||
|
context.commit("setOnline", true)
|
||||||
|
resolve(res.data)
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
try {
|
||||||
|
const user = JSON.parse(localStorage.getItem("userCache"))
|
||||||
|
if (user?.id && !e?.response?.data?.errors?.length) {
|
||||||
|
setUser(user)
|
||||||
} else {
|
} else {
|
||||||
|
const theme = {
|
||||||
|
id: 1,
|
||||||
|
name: "Colubrina Classic",
|
||||||
|
primaryType: "all",
|
||||||
|
dark: {
|
||||||
|
primary: "#0190ea",
|
||||||
|
secondary: "#757575",
|
||||||
|
accent: "#000000",
|
||||||
|
error: "#ff1744",
|
||||||
|
info: "#2196F3",
|
||||||
|
success: "#4CAF50",
|
||||||
|
warning: "#ff9800",
|
||||||
|
card: "#151515",
|
||||||
|
toolbar: "#191919",
|
||||||
|
sheet: "#181818",
|
||||||
|
text: "#000000",
|
||||||
|
dark: "#151515",
|
||||||
|
bg: "#151515"
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
primary: "#0190ea",
|
||||||
|
secondary: "#757575",
|
||||||
|
accent: "#000000",
|
||||||
|
error: "#ff1744",
|
||||||
|
info: "#2196F3",
|
||||||
|
success: "#4CAF50",
|
||||||
|
warning: "#ff9800",
|
||||||
|
card: "#f8f8f8",
|
||||||
|
toolbar: "#f8f8f8",
|
||||||
|
sheet: "#f8f8f8",
|
||||||
|
text: "#000000",
|
||||||
|
dark: "#f8f8f8",
|
||||||
|
bg: "#f8f8f8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const name = theme.id
|
||||||
|
const dark = theme.dark
|
||||||
|
const light = theme.light
|
||||||
|
Vuetify.framework.theme.themes.dark = dark
|
||||||
|
Vuetify.framework.theme.themes.light = light
|
||||||
|
Vuetify.framework.theme.themes.name = name
|
||||||
|
this.name = name
|
||||||
|
console.log("Failed to load Colubrina Account")
|
||||||
|
context.user = null
|
||||||
|
localStorage.removeItem("userCache")
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
const theme = {
|
||||||
|
id: 1,
|
||||||
|
name: "Colubrina Classic",
|
||||||
|
primaryType: "all",
|
||||||
|
dark: {
|
||||||
|
primary: "#0190ea",
|
||||||
|
secondary: "#757575",
|
||||||
|
accent: "#000000",
|
||||||
|
error: "#ff1744",
|
||||||
|
info: "#2196F3",
|
||||||
|
success: "#4CAF50",
|
||||||
|
warning: "#ff9800",
|
||||||
|
card: "#151515",
|
||||||
|
toolbar: "#191919",
|
||||||
|
sheet: "#181818",
|
||||||
|
text: "#000000",
|
||||||
|
dark: "#151515",
|
||||||
|
bg: "#151515"
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
primary: "#0190ea",
|
||||||
|
secondary: "#757575",
|
||||||
|
accent: "#000000",
|
||||||
|
error: "#ff1744",
|
||||||
|
info: "#2196F3",
|
||||||
|
success: "#4CAF50",
|
||||||
|
warning: "#ff9800",
|
||||||
|
card: "#f8f8f8",
|
||||||
|
toolbar: "#f8f8f8",
|
||||||
|
sheet: "#f8f8f8",
|
||||||
|
text: "#000000",
|
||||||
|
dark: "#f8f8f8",
|
||||||
|
bg: "#f8f8f8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const name = theme.id
|
||||||
|
const dark = theme.dark
|
||||||
|
const light = theme.light
|
||||||
|
Vuetify.framework.theme.themes.dark = dark
|
||||||
|
Vuetify.framework.theme.themes.light = light
|
||||||
|
Vuetify.framework.theme.themes.name = name
|
||||||
|
this.name = name
|
||||||
|
console.log("Failed to load Colubrina Account")
|
||||||
|
localStorage.removeItem("userCache")
|
||||||
|
context.user = null
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
if (!localStorage.getItem("userCache")) {
|
||||||
const theme = {
|
const theme = {
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "Colubrina Classic",
|
name: "Colubrina Classic",
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="communications">
|
<div id="communications">
|
||||||
<v-container fluid>
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<router-view
|
<router-view
|
||||||
v-if="$route.params.id !== 'home'"
|
v-if="$route.params.id !== 'home'"
|
||||||
:chat="selectedChat"
|
:chat="selectedChat"
|
||||||
:loading="false"
|
:loading="false"
|
||||||
:items="$store.state.chats"
|
:items="$store.state.chats"
|
||||||
></router-view>
|
></router-view>
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -169,8 +169,8 @@
|
||||||
<v-row v-if="!loading" @drop="handleDrag" no-gutters>
|
<v-row v-if="!loading" @drop="handleDrag" no-gutters>
|
||||||
<v-col class="flex-grow-1 flex-shrink-1 pb-0" id="chat-col">
|
<v-col class="flex-grow-1 flex-shrink-1 pb-0" id="chat-col">
|
||||||
<v-card
|
<v-card
|
||||||
class="d-flex flex-column fill-height rounded-xl"
|
class="d-flex flex-column fill-height rounded-xl mb-n3"
|
||||||
style="overflow: auto; height: calc(100vh - 24px - 40px - 40px)"
|
style="overflow: auto; height: calc(100vh - 24px - 40px)"
|
||||||
color="card"
|
color="card"
|
||||||
elevation="0"
|
elevation="0"
|
||||||
>
|
>
|
||||||
|
@ -202,7 +202,6 @@
|
||||||
style="display: block; width: 100px; margin: 0 auto"
|
style="display: block; width: 100px; margin: 0 auto"
|
||||||
></v-progress-circular>
|
></v-progress-circular>
|
||||||
<template v-for="(message, index) in messages">
|
<template v-for="(message, index) in messages">
|
||||||
<div :key="'div-' + message.keyId">
|
|
||||||
<Message
|
<Message
|
||||||
:key="message.keyId"
|
:key="message.keyId"
|
||||||
:message="message"
|
:message="message"
|
||||||
|
@ -227,7 +226,6 @@
|
||||||
!message.replyId
|
!message.replyId
|
||||||
"
|
"
|
||||||
></Message>
|
></Message>
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
:key="'div2-' + message.keyId"
|
:key="'div2-' + message.keyId"
|
||||||
v-if="message.readReceipts.length"
|
v-if="message.readReceipts.length"
|
||||||
|
@ -277,6 +275,7 @@
|
||||||
</template>
|
</template>
|
||||||
<v-tooltip top>
|
<v-tooltip top>
|
||||||
<template v-slot:activator="{ on }">
|
<template v-slot:activator="{ on }">
|
||||||
|
<span>
|
||||||
<v-btn
|
<v-btn
|
||||||
icon
|
icon
|
||||||
small
|
small
|
||||||
|
@ -302,6 +301,7 @@
|
||||||
}}</span>
|
}}</span>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<span>
|
<span>
|
||||||
{{ $store.state.user.username }} has read up to this point.
|
{{ $store.state.user.username }} has read up to this point.
|
||||||
|
@ -368,25 +368,18 @@
|
||||||
v-model="usersTyping.length"
|
v-model="usersTyping.length"
|
||||||
v-if="$vuetify.breakpoint.mobile"
|
v-if="$vuetify.breakpoint.mobile"
|
||||||
>
|
>
|
||||||
<v-toolbar
|
<div
|
||||||
height="22"
|
|
||||||
color="toolbar"
|
|
||||||
elevation="0"
|
|
||||||
style="
|
style="
|
||||||
border-radius: 20px 20px 0 0;
|
border-radius: 0 0 20px 20px;
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -30px;
|
top: -30px;
|
||||||
margin-bottom: -27px;
|
margin-bottom: -22px;
|
||||||
"
|
"
|
||||||
width="100%"
|
|
||||||
v-if="usersTyping.length"
|
v-if="usersTyping.length"
|
||||||
>
|
>
|
||||||
<div>
|
|
||||||
{{ usersTyping.map((user) => getName(user)).join(", ") }}
|
{{ usersTyping.map((user) => getName(user)).join(", ") }}
|
||||||
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
|
{{ usersTyping.length > 1 ? " are" : " is" }} typing...
|
||||||
</div>
|
</div>
|
||||||
</v-toolbar>
|
|
||||||
</v-fade-transition>
|
</v-fade-transition>
|
||||||
<CommsInput
|
<CommsInput
|
||||||
:chat="chat"
|
:chat="chat"
|
||||||
|
@ -402,9 +395,9 @@
|
||||||
<div
|
<div
|
||||||
style="
|
style="
|
||||||
border-radius: 0 0 20px 20px;
|
border-radius: 0 0 20px 20px;
|
||||||
position: relative;
|
position: absolute;
|
||||||
margin-top: -22px;
|
margin-top: -2px;
|
||||||
bottom: -16px;
|
bottom: 1px;
|
||||||
"
|
"
|
||||||
v-if="usersTyping.length"
|
v-if="usersTyping.length"
|
||||||
>
|
>
|
||||||
|
@ -415,14 +408,6 @@
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-divider
|
|
||||||
vertical
|
|
||||||
style="z-index: 2; padding-right: 3px; padding-left: 3px"
|
|
||||||
v-if="
|
|
||||||
($store.state.userPanel && !$vuetify.breakpoint.mobile) ||
|
|
||||||
($store.state.searchPanel && !$vuetify.breakpoint.mobile)
|
|
||||||
"
|
|
||||||
></v-divider>
|
|
||||||
<v-col
|
<v-col
|
||||||
cols="3"
|
cols="3"
|
||||||
class=""
|
class=""
|
||||||
|
@ -431,7 +416,7 @@
|
||||||
>
|
>
|
||||||
<v-card
|
<v-card
|
||||||
class="d-flex flex-column fill-height"
|
class="d-flex flex-column fill-height"
|
||||||
style="overflow: scroll; height: calc(100vh - 24px - 40px - 40px)"
|
style="overflow: scroll; height: calc(100vh - 24px - 40px)"
|
||||||
color="card"
|
color="card"
|
||||||
elevation="0"
|
elevation="0"
|
||||||
>
|
>
|
||||||
|
@ -484,7 +469,6 @@
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col
|
<v-col
|
||||||
:cols="$vuetify.breakpoint.xl ? 2 : 3"
|
:cols="$vuetify.breakpoint.xl ? 2 : 3"
|
||||||
class="ml-2"
|
|
||||||
id="user-col"
|
id="user-col"
|
||||||
v-if="
|
v-if="
|
||||||
$store.state.userPanel &&
|
$store.state.userPanel &&
|
||||||
|
@ -493,10 +477,10 @@
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<v-card
|
<v-card
|
||||||
class="d-flex flex-column fill-height rounded-xl"
|
class="d-flex flex-column fill-height rounded-0"
|
||||||
elevation="0"
|
elevation="0"
|
||||||
style="overflow: scroll; height: calc(100vh - 24px - 40px - 40px)"
|
style="overflow: scroll; height: calc(100vh - 24px - 40px)"
|
||||||
color="card"
|
color="sheet"
|
||||||
>
|
>
|
||||||
<v-menu
|
<v-menu
|
||||||
v-model="context.user.value"
|
v-model="context.user.value"
|
||||||
|
@ -520,7 +504,7 @@
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
<v-list two-line color="card">
|
<v-list two-line color="sheet">
|
||||||
<v-list-item-group class="rounded-xl">
|
<v-list-item-group class="rounded-xl">
|
||||||
<template v-for="item in associations">
|
<template v-for="item in associations">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
|
|
|
@ -373,7 +373,8 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
|
await this.$store.dispatch("doInit")
|
||||||
this.getFriends()
|
this.getFriends()
|
||||||
this.getUsers()
|
this.getUsers()
|
||||||
this.$socket.on("friendRequest", () => {
|
this.$socket.on("friendRequest", () => {
|
||||||
|
|
|
@ -123,7 +123,8 @@ export default {
|
||||||
totp: "",
|
totp: "",
|
||||||
totpDialog: false,
|
totpDialog: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
instance: "https://colubrina.troplo.com",
|
instance:
|
||||||
|
localStorage.getItem("instance") || "https://colubrina.troplo.com",
|
||||||
customHeaders: {}
|
customHeaders: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -149,14 +150,17 @@ export default {
|
||||||
})
|
})
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
const session =
|
const session =
|
||||||
res.data.session || res.data.bcToken || res.data.cookieToken
|
res.data.session ||
|
||||||
|
res.data.token ||
|
||||||
localStorage.setItem("session", session)
|
res.data.bcToken ||
|
||||||
|
res.data.cookieToken
|
||||||
|
localStorage.setItem("token", session)
|
||||||
Vue.axios.defaults.headers.common["Authorization"] = session
|
Vue.axios.defaults.headers.common["Authorization"] = session
|
||||||
this.$store.commit("setToken", session)
|
this.$store.commit("setToken", session)
|
||||||
await this.$store.dispatch("getUserInfo")
|
await this.$store.dispatch("getUserInfo")
|
||||||
this.$store.dispatch("getChats")
|
this.$store.dispatch("getChats")
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
this.$socket.auth.token = session
|
||||||
this.$socket.disconnect()
|
this.$socket.disconnect()
|
||||||
this.$socket.connect()
|
this.$socket.connect()
|
||||||
if (this.isElectron()) {
|
if (this.isElectron()) {
|
||||||
|
@ -204,9 +208,17 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.$store.state.user?.id) {
|
this.$store
|
||||||
|
.dispatch("getUserInfo")
|
||||||
|
.then(() => {
|
||||||
this.$router.push("/")
|
this.$router.push("/")
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$store.state.user = {
|
||||||
|
bcUser: null,
|
||||||
|
loggedIn: false
|
||||||
}
|
}
|
||||||
|
})
|
||||||
this.testInstance()
|
this.testInstance()
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -96,7 +96,8 @@ export default {
|
||||||
totp: "",
|
totp: "",
|
||||||
totpDialog: false,
|
totpDialog: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
instance: "https://colubrina.troplo.com",
|
instance:
|
||||||
|
localStorage.getItem("instance") || "https://colubrina.troplo.com",
|
||||||
instanceString: ""
|
instanceString: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -131,11 +132,18 @@ export default {
|
||||||
totp: this.totp
|
totp: this.totp
|
||||||
})
|
})
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
localStorage.setItem("session", res.data.session)
|
const session =
|
||||||
Vue.axios.defaults.headers.common["Authorization"] = res.data.session
|
res.data.session ||
|
||||||
this.$store.commit("setToken", res.data.session)
|
res.data.token ||
|
||||||
|
res.data.bcToken ||
|
||||||
|
res.data.cookieToken
|
||||||
|
localStorage.setItem("token", session)
|
||||||
|
Vue.axios.defaults.headers.common["Authorization"] = session
|
||||||
|
this.$store.commit("setToken", session)
|
||||||
await this.$store.dispatch("getUserInfo")
|
await this.$store.dispatch("getUserInfo")
|
||||||
|
this.$store.dispatch("getChats")
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
this.$socket.auth.token = session
|
||||||
this.$socket.disconnect()
|
this.$socket.disconnect()
|
||||||
this.$socket.connect()
|
this.$socket.connect()
|
||||||
if (this.isElectron()) {
|
if (this.isElectron()) {
|
||||||
|
@ -169,9 +177,17 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.$store.state.user?.id) {
|
this.$store
|
||||||
|
.dispatch("getUserInfo")
|
||||||
|
.then(() => {
|
||||||
this.$router.push("/")
|
this.$router.push("/")
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$store.state.user = {
|
||||||
|
bcUser: null,
|
||||||
|
loggedIn: false
|
||||||
}
|
}
|
||||||
|
})
|
||||||
this.testInstance()
|
this.testInstance()
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -5311,18 +5311,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
|
||||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||||
integrity sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==
|
integrity sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==
|
||||||
|
|
||||||
graphql-tag@^2.12.6:
|
|
||||||
version "2.12.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1"
|
|
||||||
integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==
|
|
||||||
dependencies:
|
|
||||||
tslib "^2.1.0"
|
|
||||||
|
|
||||||
graphql@^16.3.0:
|
|
||||||
version "16.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.5.0.tgz#41b5c1182eaac7f3d47164fb247f61e4dfb69c85"
|
|
||||||
integrity sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA==
|
|
||||||
|
|
||||||
gzip-size@^5.0.0:
|
gzip-size@^5.0.0:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274"
|
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274"
|
||||||
|
@ -9802,11 +9790,6 @@ thread-loader@^2.1.3:
|
||||||
loader-utils "^1.1.0"
|
loader-utils "^1.1.0"
|
||||||
neo-async "^2.6.0"
|
neo-async "^2.6.0"
|
||||||
|
|
||||||
throttle-debounce@^2.1.0:
|
|
||||||
version "2.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2"
|
|
||||||
integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==
|
|
||||||
|
|
||||||
through2-filter@^3.0.0:
|
through2-filter@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
|
resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
|
||||||
|
@ -10393,15 +10376,6 @@ vm-browserify@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||||
|
|
||||||
vue-apollo@^3.1.0:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/vue-apollo/-/vue-apollo-3.1.0.tgz#d0370b64f928f488b7ad98177cca8e1a82fa725e"
|
|
||||||
integrity sha512-TkXMpgypbqM/27vKIpWNhL347QRtcu9kWkEmxplPGGMnZb+hSbbIwU07LjQVzFwrLBer0ha9zJP4hIW/fCQDuw==
|
|
||||||
dependencies:
|
|
||||||
chalk "^2.4.2"
|
|
||||||
serialize-javascript "^4.0.0"
|
|
||||||
throttle-debounce "^2.1.0"
|
|
||||||
|
|
||||||
vue-axios@^3.4.1:
|
vue-axios@^3.4.1:
|
||||||
version "3.4.1"
|
version "3.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/vue-axios/-/vue-axios-3.4.1.tgz#e092ec4060b42e941ea5059df9b8f09058c3eea9"
|
resolved "https://registry.yarnpkg.com/vue-axios/-/vue-axios-3.4.1.tgz#e092ec4060b42e941ea5059df9b8f09058c3eea9"
|
||||||
|
@ -10490,11 +10464,6 @@ vue-loader@^15.9.2:
|
||||||
vue-hot-reload-api "^2.3.0"
|
vue-hot-reload-api "^2.3.0"
|
||||||
vue-style-loader "^4.1.0"
|
vue-style-loader "^4.1.0"
|
||||||
|
|
||||||
vue-matomo@^4.1.0:
|
|
||||||
version "4.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/vue-matomo/-/vue-matomo-4.1.0.tgz#17b513bc8ac60e168bfa8190ad05b3257a3c441e"
|
|
||||||
integrity sha512-y+tdmhY835Ip3EAGfIAgA33+aBYrvRT7fNnBnA7bSM459XpoWXgqJKdbopVpEUrxCPIq8IkuF7g4KqSLc0Fa3w==
|
|
||||||
|
|
||||||
vue-native-notification@^1.1.1:
|
vue-native-notification@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/vue-native-notification/-/vue-native-notification-1.1.1.tgz#8a57950dded83b05b9e261f45bc2e027107eb9cd"
|
resolved "https://registry.yarnpkg.com/vue-native-notification/-/vue-native-notification-1.1.1.tgz#8a57950dded83b05b9e261f45bc2e027107eb9cd"
|
||||||
|
@ -10528,11 +10497,6 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
|
||||||
hash-sum "^1.0.2"
|
hash-sum "^1.0.2"
|
||||||
loader-utils "^1.0.2"
|
loader-utils "^1.0.2"
|
||||||
|
|
||||||
vue-swatches@^2.1.1:
|
|
||||||
version "2.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/vue-swatches/-/vue-swatches-2.1.1.tgz#26c467fb7648ff4ee0887aea36d1e03b15032b83"
|
|
||||||
integrity sha512-YugkNbByxMz1dnx1nZyHSL3VSf/TnBH3/NQD+t8JKxPSqUmX87sVGBxjEaqH5IMraOLfVmU0pHCHl2BfXNypQg==
|
|
||||||
|
|
||||||
vue-template-babel-compiler@^1.1.3:
|
vue-template-babel-compiler@^1.1.3:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/vue-template-babel-compiler/-/vue-template-babel-compiler-1.2.0.tgz#f77126886e868f64d2acefe5c0ecfd9c323bf943"
|
resolved "https://registry.yarnpkg.com/vue-template-babel-compiler/-/vue-template-babel-compiler-1.2.0.tgz#f77126886e868f64d2acefe5c0ecfd9c323bf943"
|
||||||
|
|
Loading…
Reference in a new issue