This commit is contained in:
Troplo 2022-10-02 17:12:25 +11:00
parent 87976eac86
commit 1598214e2d
10 changed files with 765 additions and 708 deletions

View File

@ -13,9 +13,9 @@
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@mapbox/node-pre-gyp@^1.0.0", "@mapbox/node-pre-gyp@^1.0.9":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc"
integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==
version "1.0.10"
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c"
integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==
dependencies:
detect-libc "^2.0.0"
https-proxy-agent "^5.0.0"
@ -59,9 +59,9 @@
integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==
"@rushstack/ts-command-line@^4.12.2":
version "4.12.2"
resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.12.2.tgz#59b7450c5d75190778cce8b159c7d7043c32cc4e"
integrity sha512-poBtnumLuWmwmhCEkVAgynWgtnF9Kygekxyp4qtQUSbBrkuyPQTL85c8Cva1YfoUpOdOXxezMAkUt0n5SNKGqw==
version "4.12.4"
resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.12.4.tgz#e4bedd4890bca415f90fec8f33c51404c4039410"
integrity sha512-ckZHEfPiJCmBdWd/syve5zu2TNsPIqbFie3jWzM/izZa6ZOkDwex/K1ww+kJ12hFBnN44lMD7voJvKXajUCEDA==
dependencies:
"@types/argparse" "1.0.38"
argparse "~1.0.9"
@ -162,9 +162,9 @@
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/node@*", "@types/node@>=10.0.0":
version "18.7.14"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.14.tgz#0fe081752a3333392d00586d815485a17c2cf3c9"
integrity sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA==
version "18.7.23"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.23.tgz#75c580983846181ebe5f4abc40fe9dfb2d65665f"
integrity sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==
"@types/node@^17.0.10":
version "17.0.45"
@ -179,9 +179,9 @@
"@types/node" "*"
"@types/validator@^13.7.1":
version "13.7.6"
resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.6.tgz#631f1acd15cbac9cb0a114da7e87575f1c95b46a"
integrity sha512-uBsnWETsUagQ0n6G2wcXNIufpTNJir0zqzG4p62fhnwzs48d/iuOWEEo0d3iUxN7D+9R/8CSvWGKS+KmaD0mWA==
version "13.7.7"
resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.7.tgz#e87cf34dd08522d21acf30130fd8941f433b81b5"
integrity sha512-jiEw2kTUJ8Jsh4A1K4b5Pkjj9Xz6FktLLOQ36ZVLRkmxFbpTvAV2VRoKMojz8UlZxNg/2dZqzpigH4JYn1bkQg==
"@yarnpkg/lockfile@^1.1.0":
version "1.1.0"
@ -753,7 +753,7 @@ clean-stack@^2.0.0:
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
cli-color@^2.0.1:
cli-color@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-2.0.3.tgz#73769ba969080629670f3f2ef69a4bf4e7cc1879"
integrity sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==
@ -1212,9 +1212,9 @@ domutils@^3.0.1:
domhandler "^5.0.1"
dotenv@^16.0.0:
version "16.0.2"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.2.tgz#0b0f8652c016a3858ef795024508cddc4bffc5bf"
integrity sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==
version "16.0.3"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
dottie@^2.0.2:
version "2.0.2"
@ -1401,9 +1401,9 @@ exit-hook@^1.0.0:
integrity sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg==
express-rate-limit@^6.4.0:
version "6.5.2"
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-6.5.2.tgz#5d2322e680ed43ae303b775fa7e19496c9014b58"
integrity sha512-N0cG/5ccbXfNC+FxRu7ujm2HjKkygF2PL7KLAf/hct9uqKB5QkZVizb/hEst6tUBXnfhblYWgOorN2eY+Saerw==
version "6.6.0"
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-6.6.0.tgz#3bbc2546540d327b1b0bfa9ab5f1b2c49075af98"
integrity sha512-HFN2+4ZGdkQOS8Qli4z6knmJFnw6lZed67o6b7RGplWeb1Z0s8VXaj3dUgPIdm9hrhZXTRpCTHXA0/2Eqex0vA==
express@^4.16.3, express@^4.17.1:
version "4.18.1"
@ -1541,9 +1541,9 @@ find-yarn-workspace-root@^2.0.0:
micromatch "^4.0.2"
follow-redirects@^1.14.9:
version "1.15.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
forever-agent@~0.6.1:
version "0.6.1"
@ -1662,9 +1662,9 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5:
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.0.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
version "1.1.3"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
@ -1918,9 +1918,9 @@ infer-owner@^1.0.4:
integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
inflection@^1.13.2:
version "1.13.2"
resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.2.tgz#15e8c797c6c3dadf31aa658f8df8a4ea024798b0"
integrity sha512-cmZlljCRTBFouT8UzMzrGcVEvkv6D/wBdcdKG7J1QH5cXjtU75Dm+P27v9EKu/Y43UYyCJd1WC4zLebRrC8NBw==
version "1.13.4"
resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.4.tgz#65aa696c4e2da6225b148d7a154c449366633a32"
integrity sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==
inflight@^1.0.4:
version "1.0.6"
@ -2120,7 +2120,7 @@ jake@^10.8.5:
filelist "^1.0.1"
minimatch "^3.0.4"
js-beautify@^1.14.0:
js-beautify@^1.14.5:
version "1.14.6"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.6.tgz#b23ca5d74a462c282c7711bb51150bcc97f2b507"
integrity sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==
@ -2663,9 +2663,9 @@ node-xwhois@^2.0.10:
whois latest
nodemailer@^6.7.7:
version "6.7.8"
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.8.tgz#9f1af9911314960c0b889079e1754e8d9e3f740a"
integrity sha512-2zaTFGqZixVmTxpJRCFC+Vk5eGRd/fYtvIR+dl5u9QXLTQWGIf48x/JXvo58g9sa0bU6To04XUv554Paykum3g==
version "6.8.0"
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.8.0.tgz#804bcc5256ee5523bc914506ee59f8de8f0b1cd5"
integrity sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==
nopt@^5.0.0:
version "5.0.0"
@ -3199,7 +3199,7 @@ resolve-alpn@^1.0.0:
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
resolve@^1.20.0:
resolve@^1.22.1:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@ -3223,10 +3223,10 @@ restore-cursor@^1.0.1:
exit-hook "^1.0.0"
onetime "^1.0.0"
retry-as-promised@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-5.0.0.tgz#f4ecc25133603a2d2a7aff4a128691d7bc506d54"
integrity sha512-6S+5LvtTl2ggBumk04hBo/4Uf6fRJUwIgunGZ7CYEBCeufGFW1Pu6ucUf/UskHeWOIsUcLOGLFXPig5tR5V1nA==
retry-as-promised@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-6.1.0.tgz#11eca9a0f97804d552ec8e74bc4eb839bd226dc4"
integrity sha512-Hj/jY+wFC+SB9SDlIIFWiGOHnNG0swYbGYsOj2BJ8u2HKUaobNKab0OIC0zOLYzDy0mb7A4xA5BMo4LMz5YtEA==
retry@^0.12.0:
version "0.12.0"
@ -3323,15 +3323,15 @@ send@0.18.0:
statuses "2.0.1"
sequelize-cli@^6.4.1:
version "6.4.1"
resolved "https://registry.yarnpkg.com/sequelize-cli/-/sequelize-cli-6.4.1.tgz#fb9fbbde733ae887970316a700d264fcf0683770"
integrity sha512-gIzzFitUGUErq6DYd1JDnsmx7z7XcxzRNe4Py3AqeaxcyjpCAZU2BQnsNPGPMKAaXfMtKi/d9Tu4MtLrehVzIQ==
version "6.5.1"
resolved "https://registry.yarnpkg.com/sequelize-cli/-/sequelize-cli-6.5.1.tgz#e084c82b11e86ed9bd7e47fde4e44cfbc6e81e2c"
integrity sha512-36hfZKNeZkIshp6L0jPVQ27xNLzgDPpiZokQsvo0M882AtAm+KhGOIViR0BecWb0Xz8+uSq03xxcl7RfMgyIRA==
dependencies:
cli-color "^2.0.1"
cli-color "^2.0.3"
fs-extra "^9.1.0"
js-beautify "^1.14.0"
js-beautify "^1.14.5"
lodash "^4.17.21"
resolve "^1.20.0"
resolve "^1.22.1"
umzug "^2.3.0"
yargs "^16.2.0"
@ -3341,9 +3341,9 @@ sequelize-pool@^7.1.0:
integrity sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==
sequelize@^6.21.3:
version "6.21.4"
resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.21.4.tgz#8f5cb248d7cfc86ca9bf7e1f8306ac4bd83167de"
integrity sha512-5A0+giRhGHerTDRMsZ54TYRB8oQPWxeVscbc4USG9wRtw2Eqik0Vk0p2EVDrhoq7tmNBh2nHpd9YMfvGdwPEJw==
version "6.23.2"
resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.23.2.tgz#bd343ac8326725845e071b1dd782bbf6c02be476"
integrity sha512-0jy5pkRV7LZlBArIrYKfpKa+DowC+fIcI6LrWDfvdqFmuXZfmS4qq8gzFmIu0C210ts2Mmw/dghzRhX73xPoMg==
dependencies:
"@types/debug" "^4.1.7"
"@types/validator" "^13.7.1"
@ -3354,7 +3354,7 @@ sequelize@^6.21.3:
moment "^2.29.1"
moment-timezone "^0.5.34"
pg-connection-string "^2.5.0"
retry-as-promised "^5.0.0"
retry-as-promised "^6.1.0"
semver "^7.3.5"
sequelize-pool "^7.1.0"
toposort-class "^1.0.1"
@ -3473,9 +3473,9 @@ socks-proxy-agent@^6.0.0:
socks "^2.6.2"
socks@^2.2.2, socks@^2.6.2:
version "2.7.0"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.0.tgz#f9225acdb841e874dca25f870e9130990f3913d0"
integrity sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==
version "2.7.1"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55"
integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==
dependencies:
ip "^2.0.0"
smart-buffer "^4.2.0"
@ -3508,9 +3508,9 @@ sprintf-js@~1.0.2:
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
sqlite3@^5.0.10:
version "5.0.11"
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.11.tgz#102c835d70be66da9d95a383fd6ea084a082ef7f"
integrity sha512-4akFOr7u9lJEeAWLJxmwiV43DJcGV7w3ab7SjQFAFaTVyknY3rZjvXTKIVtWqUoY4xwhjwoHKYs2HDW2SoHVsA==
version "5.1.1"
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.1.tgz#c6561220fd875fd88eb2ef717631e0a11af1ec38"
integrity sha512-mMinkrQr/LKJqFiFF+AF7imPSzRCCpTCreusZO3D/ssJHVjZOrbu2Caz+zPH5KTmGGXBxXMGSRDssL+44CLxvg==
dependencies:
"@mapbox/node-pre-gyp" "^1.0.0"
node-addon-api "^4.2.0"
@ -3843,9 +3843,9 @@ umzug@^3.1.1:
type-fest "^2.18.0"
underscore@^1.13.1, underscore@^1.9.1:
version "1.13.4"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.4.tgz#7886b46bbdf07f768e0052f1828e1dcab40c0dee"
integrity sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==
version "1.13.6"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441"
integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==
unique-filename@^1.1.1:
version "1.1.1"

View File

@ -1,6 +1,6 @@
{
"name": "colubrina",
"version": "1.0.30",
"version": "1.0.31",
"description": "Simple instant communication.",
"private": true,
"author": "Troplo <troplo@troplo.com>",
@ -25,6 +25,7 @@
"core-js": "^3.6.5",
"dayjs": "^1.11.0",
"ejs": "^3.1.7",
"electron-window-state": "^5.0.3",
"glob-parent": "^5.1.2",
"highlight.js": "^11.6.0",
"markdown-it": "^13.0.1",

View File

@ -7,6 +7,7 @@ const {
VUEJS_DEVTOOLS
} = require("electron-devtools-installer")
const isDevelopment = process.env.NODE_ENV !== "production"
const windowStateKeeper = require("electron-window-state")
// Scheme must be registered before the app is ready
electron.protocol.registerSchemesAsPrivileged([
@ -22,11 +23,17 @@ async function createWindow() {
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)
let mainWindowState = windowStateKeeper({
defaultWidth: width,
defaultHeight: height,
x: x,
y: y
})
const win = new electron.BrowserWindow({
width,
height,
x,
y,
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
@ -39,6 +46,7 @@ async function createWindow() {
enableBlinkFeatures: "MiddleClickAutoscroll"
}
})
mainWindowState.manage(win)
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode

View File

@ -0,0 +1,202 @@
<template>
<div>
<v-card
:min-width="!$vuetify.breakpoint.mobile ? 400 : 0"
elevation="0"
color="card"
v-if="embed.type === 'image'"
>
<v-hover v-slot="{ hover }">
<div>
<v-img
@click="setImagePreview(embed)"
contain
:max-width="500"
:max-height="500"
:min-height="250"
:min-width="250"
:src="$store.state.baseURL + embed.mediaProxyLink"
>
<template v-slot:placeholder>
<v-row class="fill-height ma-0" align="center" justify="center">
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
<template v-slot:default>
<v-fade-transition v-if="hover">
<v-overlay absolute>
<v-icon large>mdi-arrow-expand-all</v-icon>
</v-overlay>
</v-fade-transition>
</template>
</v-img>
</div>
</v-hover>
</v-card>
<v-card
v-if="embed.type !== 'image'"
elevation="0"
:color="embed.type === 'embed-v1' ? embed.backgroundColor : 'bg'"
:max-width="400"
:min-width="!$vuetify.breakpoint.mobile ? 300 : 0"
class="ml-1 rounded-xl mb-1 mr-1"
>
<v-container fluid>
<v-row v-if="embed.type === 'openGraph'">
<v-col
cols="12"
class="text-xs-center"
v-if="embed.openGraph.ogImage"
>
<v-img
:src="
embed.openGraph.ogImage?.url || embed.openGraph.ogImage[0]?.url
"
class="elevation-1"
contain
:aspect-ratio="16 / 9"
>
<template v-slot:placeholder>
<v-row class="fill-height ma-0" align="center" justify="center">
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-col>
<v-col cols="12" class="text-xs-center">
<h4>
{{ embed.openGraph.ogSiteName }}
</h4>
<a :href="embed.link" target="_blank" style="text-decoration: none">
<h3>
{{ embed.openGraph.ogTitle }}
</h3>
</a>
<p v-if="embed.openGraph.ogDescription">
{{ embed.openGraph.ogDescription }}
</p>
</v-col>
</v-row>
<v-row v-else-if="embed.type === 'embed-v1'">
<v-col cols="12" class="text-xs-center" v-if="embed.headerImage">
<v-img
:src="
embed.openGraph.headerImage?.url ||
embed.openGraph.headerImage[0]?.url
"
class="elevation-1"
contain
:aspect-ratio="16 / 9"
>
<template v-slot:placeholder>
<v-row class="fill-height ma-0" align="center" justify="center">
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-col>
<v-col cols="12" class="text-xs-center">
<h4 v-if="embed.title">
{{ embed.title }}
</h4>
<p v-if="embed.description">
{{ embed.description }}
</p>
<v-row
v-for="(graph, index) in embed.graphs"
:key="'graph-' + index"
>
<v-col cols="12" class="text-xs-center">
<h3>
{{ graph.name }}
</h3>
<Chart
:chart-data="graph.data"
v-if="graph.data"
:options="graphOptions"
></Chart>
<p v-else>Chart data could not be loaded.</p>
</v-col>
</v-row>
<v-row
v-for="(field, index) in embed.fields"
:key="'field-' + index"
:id="'field-' + index"
class="mt-1"
>
<v-col
cols="12"
class="text-xs-center"
style="white-space: pre-wrap"
>
<h4>{{ field.name }}</h4>
<p>{{ field.value }}</p>
</v-col>
</v-row>
<a
:href="embed.link.url"
v-if="embed.link"
target="_blank"
style="text-decoration: none"
>
<h3>
{{ embed.link.title }}
</h3>
</a>
<small v-if="embed.footer">
{{ embed.footer }}
</small>
</v-col>
</v-row>
<v-row v-else>
<v-container>
<h4>You must update Colubrina to see this embed.</h4>
</v-container>
</v-row>
</v-container>
</v-card>
</div>
</template>
<script>
import { Line as Chart } from "vue-chartjs/legacy"
import {
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineElement,
PointElement,
Title,
Tooltip
} from "chart.js"
ChartJS.register(
Title,
Tooltip,
Legend,
CategoryScale,
LinearScale,
PointElement,
LineElement
)
export default {
name: "Embed",
props: ["embed", "setImagePreview"],
components: {
Chart
}
}
</script>
<style scoped></style>

View File

@ -159,246 +159,10 @@
:id="'embed-' + index"
no-gutters
>
<v-card
:min-width="!$vuetify.breakpoint.mobile ? 400 : 0"
elevation="0"
color="card"
v-if="embed.type === 'image'"
>
<v-hover v-slot="{ hover }">
<div>
<v-img
@click="setImagePreview(embed)"
contain
:max-width="500"
:max-height="500"
:min-height="250"
:min-width="250"
:src="$store.state.baseURL + embed.mediaProxyLink"
>
<template v-slot:placeholder>
<v-row
class="fill-height ma-0"
align="center"
justify="center"
>
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
<template v-slot:default>
<v-fade-transition v-if="hover">
<v-overlay absolute>
<v-icon large>mdi-arrow-expand-all</v-icon>
</v-overlay>
</v-fade-transition>
</template>
</v-img>
</div>
</v-hover>
</v-card>
<v-card
v-if="embed.type !== 'image'"
elevation="0"
:color="
embed.type === 'embed-v1' ? embed.backgroundColor : 'bg'
"
:max-width="400"
:min-width="!$vuetify.breakpoint.mobile ? 300 : 0"
class="ml-1 rounded-xl mb-1 mr-1"
>
<v-container fluid>
<v-row v-if="embed.type === 'openGraph'">
<v-col
cols="12"
class="text-xs-center"
v-if="embed.openGraph.ogImage"
>
<v-img
:src="
embed.openGraph.ogImage?.url ||
embed.openGraph.ogImage[0]?.url
"
class="elevation-1"
contain
:aspect-ratio="16 / 9"
>
<template v-slot:placeholder>
<v-row
class="fill-height ma-0"
align="center"
justify="center"
>
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-col>
<v-col cols="12" class="text-xs-center">
<h4>
{{ embed.openGraph.ogSiteName }}
</h4>
<a
:href="embed.link"
target="_blank"
style="text-decoration: none"
>
<h3>
{{ embed.openGraph.ogTitle }}
</h3>
</a>
<p v-if="embed.openGraph.ogDescription">
{{ embed.openGraph.ogDescription }}
</p>
</v-col>
</v-row>
<v-row v-else-if="embed.type === 'embed-v1'">
<v-col
cols="12"
class="text-xs-center"
v-if="embed.headerImage"
>
<v-img
:src="
embed.openGraph.headerImage?.url ||
embed.openGraph.headerImage[0]?.url
"
class="elevation-1"
contain
:aspect-ratio="16 / 9"
>
<template v-slot:placeholder>
<v-row
class="fill-height ma-0"
align="center"
justify="center"
>
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-col>
<v-col cols="12" class="text-xs-center">
<h4 v-if="embed.title">
{{ embed.title }}
</h4>
<p v-if="embed.description">
{{ embed.description }}
</p>
<v-row
v-for="(graph, index) in embed.graphs"
:key="'graph-' + index"
>
<v-col cols="12" class="text-xs-center">
<h3>
{{ graph.name }}
</h3>
<Chart
:chart-data="graph.data"
v-if="graph.data"
:options="graphOptions"
></Chart>
<p v-else>Chart data could not be loaded.</p>
</v-col>
</v-row>
<v-row
v-for="(field, index) in embed.fields"
:key="'field-' + index"
:id="'field-' + index"
class="mt-1"
>
<v-col
cols="12"
class="text-xs-center"
style="white-space: pre-wrap"
>
<h4>{{ field.name }}</h4>
<p>{{ field.value }}</p>
</v-col>
</v-row>
<a
:href="embed.link.url"
v-if="embed.link"
target="_blank"
style="text-decoration: none"
>
<h3>
{{ embed.link.title }}
</h3>
</a>
<small v-if="embed.footer">
{{ embed.footer }}
</small>
</v-col>
</v-row>
<v-row v-else>
<v-container>
<h4>You must update Colubrina to see this embed.</h4>
</v-container>
</v-row>
</v-container>
</v-card>
<Embed :embed="embed" :setImagePreview="setImagePreview"></Embed>
</v-row>
<v-row v-if="message.poll" no-gutters>
<v-card
elevation="0"
:max-width="500"
:min-width="!$vuetify.breakpoint.mobile ? 400 : 200"
class="ml-1 mb-1 mr-1 rounded-l"
color="card lighten-1"
>
<v-toolbar color="toolbar" height="45">
<v-toolbar-title>
Poll: {{ message.poll.title }}
</v-toolbar-title>
</v-toolbar>
<v-card-text>
{{ message.poll.description }}
<v-progress-linear
v-for="option in message.poll.options"
:key="option.id"
block
class="mb-1 rounded-xl"
height="30"
text
:value="
percentageVotes.find(
(percentage) => percentage.id === option.id
).percentage
"
color="success darken-1"
background-opacity="0.2"
outlined
style="text-transform: none; cursor: pointer"
@click="votePoll(option.id)"
>
<span style="float: left !important">
<v-icon v-if="option.id === myVote?.answer">
mdi-check-circle
</v-icon>
{{ option.value }} ({{
percentageVotes.find(
(percentage) => percentage.id === option.id
).percentage
}}% /
{{
message.poll.answers.filter(
(answer) => answer.answer === option.id
)?.length || 0
}})
</span>
</v-progress-linear>
{{ message.poll.answers.length }} votes
</v-card-text>
</v-card>
<Poll :message="message"></Poll>
</v-row>
</template>
<template v-if="edit.id !== message.id">
@ -618,28 +382,11 @@
</template>
<script>
import Embed from "./Embed.vue"
import CommsInput from "./CommsInput.vue"
import { Line as Chart } from "vue-chartjs/legacy"
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
CategoryScale,
LinearScale,
PointElement,
LineElement
} from "chart.js"
import AjaxErrorHandler from "@/lib/errorHandler"
ChartJS.register(
Title,
Tooltip,
Legend,
CategoryScale,
LinearScale,
PointElement,
LineElement
)
import Poll from "@/components/Poll"
export default {
name: "Message",
props: [
@ -659,8 +406,9 @@ export default {
"lastMessage"
],
components: {
Poll,
CommsInput,
Chart
Embed
},
data() {
return {
@ -710,25 +458,6 @@ export default {
}
},
computed: {
myVote() {
return this.message.poll.answers.find(
(vote) => vote.userId === this.$store.state.user.id
)
},
percentageVotes() {
return this.message.poll.options.map((option) => {
return {
id: option.id,
percentage: Math.round(
((this.message.poll.answers?.filter(
(answer) => answer?.answer === option.id
).length || 0) /
this.message.poll.answers.length) *
100 || 0
)
}
})
},
mentioned() {
return this.message.content
.toLowerCase()
@ -736,15 +465,6 @@ export default {
}
},
methods: {
votePoll(option) {
this.axios
.post(`/api/v1/polls/${this.message.poll.id}/vote`, {
option
})
.catch((e) => {
AjaxErrorHandler(this.$store)(e)
})
},
pinMessage() {
this.axios
.post(`/api/v1/communications/${this.chat.id}/pins`, {
@ -768,18 +488,6 @@ export default {
return (size / 1073741824).toFixed(2) + " GB"
}
}
},
mounted() {
if (this.message.poll) {
this.$socket.on(`pollAnswer-${this.message.id}`, (data) => {
this.message.poll.answers = this.message.poll.answers.filter(
(answer) => answer.id !== data.id
)
if (data.answer) {
this.message.poll.answers.push(data.answer)
}
})
}
}
}
</script>

View File

@ -0,0 +1,101 @@
<template>
<v-card
elevation="0"
:max-width="500"
:min-width="!$vuetify.breakpoint.mobile ? 400 : 200"
class="ml-1 mb-1 mr-1 rounded-l"
color="card lighten-1"
>
<v-toolbar color="toolbar" height="45">
<v-toolbar-title> Poll: {{ message.poll.title }} </v-toolbar-title>
</v-toolbar>
<v-card-text>
{{ message.poll.description }}
<v-progress-linear
v-for="option in message.poll.options"
:key="option.id"
block
class="mb-1 rounded-xl"
height="30"
text
:value="
percentageVotes.find((percentage) => percentage.id === option.id)
.percentage
"
color="success darken-1"
background-opacity="0.2"
outlined
style="text-transform: none; cursor: pointer"
@click="votePoll(option.id)"
>
<span style="float: left !important">
<v-icon v-if="option.id === myVote?.answer">
mdi-check-circle
</v-icon>
{{ option.value }} ({{
percentageVotes.find((percentage) => percentage.id === option.id)
.percentage
}}% /
{{
message.poll.answers.filter((answer) => answer.answer === option.id)
?.length || 0
}})
</span>
</v-progress-linear>
{{ message.poll.answers.length }} votes
</v-card-text>
</v-card>
</template>
<script>
import AjaxErrorHandler from "@/lib/errorHandler"
export default {
name: "Poll",
props: ["message"],
computed: {
myVote() {
return this.message.poll.answers.find(
(vote) => vote.userId === this.$store.state.user.id
)
},
percentageVotes() {
return this.message.poll.options.map((option) => {
return {
id: option.id,
percentage: Math.round(
((this.message.poll.answers?.filter(
(answer) => answer?.answer === option.id
).length || 0) /
this.message.poll.answers.length) *
100 || 0
)
}
})
}
},
methods: {
votePoll(option) {
this.axios
.post(`/api/v1/polls/${this.message.poll.id}/vote`, {
option
})
.catch((e) => {
AjaxErrorHandler(this.$store)(e)
})
}
},
mounted() {
this.$socket.on(`pollAnswer-${this.message.id}`, (data) => {
this.message.poll.answers = this.message.poll.answers.filter(
(answer) => answer.id !== data.id
)
if (data.answer) {
this.message.poll.answers.push(data.answer)
}
})
}
}
</script>
<style scoped></style>

View File

@ -37,9 +37,9 @@
<span>Bot</span>
</v-tooltip>
<div class="subheading subtitle-1 text--lighten-2">
<template v-if="user.item.nickname"
>{{ user.item.username }}</template
>
<template v-if="user.item.nickname">{{
user.item.username
}}</template>
</div>
</v-toolbar-title>
</v-toolbar>
@ -108,7 +108,10 @@
<v-list-item
v-for="item in mutualGroups"
:key="item.id"
@click="$router.push('/communications/' + item.associationId)"
@click="
$router.push('/communications/' + item.associationId)
user.value = false
"
>
<v-list-item-title>
{{ item.name }}
@ -147,25 +150,28 @@ export default {
}
},
methods: {
openUserPanel(user) {
this.user.item = user
this.onMounted()
},
getName(user) {
if (user.nickname?.nickname) {
return user.nickname.nickname
} else {
return user.username
}
}
},
mounted() {
if(this.user?.item?.id) {
this.mutualGroups = []
this.mutualFriends = []
this.loading = {
mutualGroups: true,
mutualFriends: true
}
this.axios
},
onMounted() {
if (this.user?.item?.id) {
this.mutualGroups = []
this.mutualFriends = []
this.loading = {
mutualGroups: true,
mutualFriends: true
}
this.axios
.get(
process.env.VUE_APP_BASE_URL +
process.env.VUE_APP_BASE_URL +
"/api/v1/communications/mutual/" +
this.user.item.id +
"/groups"
@ -177,9 +183,9 @@ export default {
.catch((e) => {
AjaxErrorHandler(this.$store)(e)
})
this.axios
this.axios
.get(
process.env.VUE_APP_BASE_URL +
process.env.VUE_APP_BASE_URL +
"/api/v1/communications/mutual/" +
this.user.item.id +
"/friends"
@ -191,7 +197,11 @@ export default {
.catch((e) => {
AjaxErrorHandler(this.$store)(e)
})
}
}
},
mounted() {
this.onMounted()
}
}
</script>

View File

@ -10,31 +10,27 @@ const routes = [
name: "Communications"
},
{
path: "/communications",
name: "Communications",
children: [
{
path: "friends",
name: "Friends",
component: () =>
import(
/* webpackChunkName: "communicationsFriends" */ "../views/Communications/CommunicationsFriends"
)
},
{
path: ":id",
name: "Communications",
component: () =>
import(
/* webpackChunkName: "communicationsChat" */ "../views/Communications/CommunicationsChat"
)
}
],
path: "/communications/friends",
name: "Friends",
component: () =>
import(
/* webpackChunkName: "communications" */ "../views/Communications/Communications"
/* webpackChunkName: "communicationsFriends" */ "../views/Communications/CommunicationsFriends"
)
},
{
path: "/communications",
name: "Communications",
component: () =>
import(
/* webpackChunkName: "communicationsChat" */ "../views/Communications/CommunicationsChat"
),
children: [
{
path: ":id",
name: "Communications"
}
]
},
{
path: "/login",
name: "Login",

View File

@ -114,20 +114,11 @@
</v-container>
</v-card>
</v-dialog>
<v-card
color="card"
v-if="loading"
style="overflow: scroll; height: calc(100vh - 24px - 40px - 40px)"
>
<v-overlay :value="loading" absolute>
<v-progress-circular indeterminate size="64"></v-progress-circular>
</v-overlay>
</v-card>
<v-navigation-drawer
v-model="$store.state.userPanel"
color="bg"
floating
v-if="!loading && $vuetify.breakpoint.mobile"
v-if="$vuetify.breakpoint.mobile"
app
right
style="z-index: 100"
@ -171,8 +162,12 @@
</v-list-item-group>
</v-list>
</v-navigation-drawer>
<v-row v-if="!loading" @drop="handleDrag" no-gutters>
<v-col class="flex-grow-1 flex-shrink-1 pb-0" id="chat-col">
<v-row @drop="handleDrag" no-gutters style="overflow: hidden">
<v-col
class="flex-grow-1 flex-shrink-1 pb-0"
id="chat-col"
style="overflow: hidden"
>
<v-card
class="d-flex flex-column-reverse fill-height rounded-0 mb-n3 chat-col"
style="overflow: auto; height: calc(100vh - 24px - 40px)"
@ -605,7 +600,6 @@ export default {
NicknameDialog,
CommsInput
},
props: ["chat", "loading", "items"],
data: () => ({
interval: null,
pins: [],
@ -719,6 +713,15 @@ export default {
lastRead: 0
}),
computed: {
chat() {
try {
return this.$store.state.chats.find(
(item) => item.id === parseInt(this.$route.params.id)
)
} catch {
return null
}
},
offsetValue() {
return this.offset || this.messages[0]?.id || 0
},
@ -1125,6 +1128,12 @@ export default {
}
},
mounted() {
this.$socket.on("memberListUpdate", () => {
this.$store.dispatch("getChats")
})
if (!this.$route.params.id) {
this.$router.push("/communications/friends")
}
document.addEventListener("keypress", this.focusKey)
document
.getElementById("message-list")

File diff suppressed because it is too large Load Diff