forked from AkkomaGang/akkoma-fe
Compare commits
No commits in common. "b60bcbd06d06071dcf7ed6923f0da2f01929a988" and "1619c118122ce770de9deb400b4a494d1f4e8312" have entirely different histories.
b60bcbd06d
...
1619c11812
15 changed files with 141 additions and 12 deletions
|
@ -18,19 +18,21 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime": "7.17.8",
|
||||
"@chenfengyuan/vue-qrcode": "2.0.0",
|
||||
"@floatingghost/pinch-zoom-element": "^1.3.1",
|
||||
"@fortawesome/fontawesome-svg-core": "1.3.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
||||
"@fortawesome/vue-fontawesome": "3.0.1",
|
||||
"@floatingghost/pinch-zoom-element": "^1.3.1",
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"blurhash": "^2.0.4",
|
||||
"body-scroll-lock": "2.7.1",
|
||||
"chromatism": "3.0.0",
|
||||
"click-outside-vue3": "4.0.1",
|
||||
"cropperjs": "1.5.12",
|
||||
"diff": "3.5.0",
|
||||
"escape-html": "1.0.3",
|
||||
"iso-639-1": "^2.1.15",
|
||||
"js-cookie": "^3.0.1",
|
||||
"localforage": "1.10.0",
|
||||
"parse-link-header": "^2.0.0",
|
||||
|
@ -82,7 +84,6 @@
|
|||
"html-webpack-plugin": "^5.5.0",
|
||||
"http-proxy-middleware": "0.21.0",
|
||||
"inject-loader": "2.0.1",
|
||||
"iso-639-1": "2.1.15",
|
||||
"isparta-loader": "2.0.0",
|
||||
"json-loader": "0.5.7",
|
||||
"karma": "6.3.17",
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
faPencilAlt,
|
||||
faAlignRight
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import Blurhash from '../blurhash/Blurhash.vue'
|
||||
|
||||
library.add(
|
||||
faFile,
|
||||
|
@ -63,7 +64,8 @@ const Attachment = {
|
|||
components: {
|
||||
Flash,
|
||||
StillImage,
|
||||
VideoAttachment
|
||||
VideoAttachment,
|
||||
Blurhash
|
||||
},
|
||||
computed: {
|
||||
classNames () {
|
||||
|
@ -84,6 +86,9 @@ const Attachment = {
|
|||
useContainFit () {
|
||||
return this.$store.getters.mergedConfig.useContainFit
|
||||
},
|
||||
useBlurhash () {
|
||||
return this.$store.getters.mergedConfig.useBlurhash
|
||||
},
|
||||
placeholderName () {
|
||||
if (this.attachment.description === '' || !this.attachment.description) {
|
||||
return this.type.toUpperCase()
|
||||
|
|
|
@ -64,7 +64,15 @@
|
|||
:title="attachment.description"
|
||||
@click.prevent.stop="toggleHidden"
|
||||
>
|
||||
<Blurhash
|
||||
v-if="useBlurhash && attachment.blurhash"
|
||||
:height="512"
|
||||
:width="1024"
|
||||
:hash="attachment.blurhash"
|
||||
:punch="1"
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
:key="nsfwImage"
|
||||
class="nsfw"
|
||||
:src="nsfwImage"
|
||||
|
|
66
src/components/blurhash/Blurhash.vue
Normal file
66
src/components/blurhash/Blurhash.vue
Normal file
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<canvas
|
||||
ref="canvas"
|
||||
class="blurhash"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { decode } from "blurhash";
|
||||
|
||||
export default {
|
||||
name: 'Blurhash',
|
||||
props: {
|
||||
hash: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
punch: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
canvas: null,
|
||||
ctx: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.canvas = this.$refs.canvas;
|
||||
this.ctx = this.canvas.getContext('2d');
|
||||
this.canvas.width = 1024;
|
||||
this.canvas.height = 512;
|
||||
this.draw();
|
||||
},
|
||||
methods: {
|
||||
draw() {
|
||||
const pixels = decode(this.hash, this.width, this.height, this.punch);
|
||||
const imageData = this.ctx.createImageData(this.width, this.height);
|
||||
imageData.data.set(pixels);
|
||||
this.ctx.putImageData(imageData, 0, 0);
|
||||
fetch("/static/blurhash-overlay.png")
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => {
|
||||
const img = new Image();
|
||||
img.src = URL.createObjectURL(blob);
|
||||
img.onload = () => {
|
||||
this.ctx.drawImage(img, 0, 0, this.width, this.height);
|
||||
};
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -144,6 +144,7 @@ const ExtraButtons = {
|
|||
statusPoll: this.status.poll,
|
||||
statusFiles: [...this.status.attachments],
|
||||
statusScope: this.status.visibility,
|
||||
statusLanguage: this.status.language,
|
||||
statusContentType: data.content_type
|
||||
}))
|
||||
this.doDeleteStatus()
|
||||
|
|
|
@ -13,6 +13,7 @@ import suggestor from '../emoji_input/suggestor.js'
|
|||
import { mapGetters, mapState } from 'vuex'
|
||||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
import Select from '../select/select.vue'
|
||||
import iso6391 from 'iso-639-1'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -63,6 +64,7 @@ const PostStatusForm = {
|
|||
'statusMediaDescriptions',
|
||||
'statusScope',
|
||||
'statusContentType',
|
||||
'statusLanguage',
|
||||
'replyTo',
|
||||
'quoteId',
|
||||
'repliedUser',
|
||||
|
@ -128,7 +130,7 @@ const PostStatusForm = {
|
|||
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
|
||||
}
|
||||
|
||||
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject } = this.$store.getters.mergedConfig
|
||||
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage } = this.$store.getters.mergedConfig
|
||||
|
||||
let statusParams = {
|
||||
spoilerText: this.subject || '',
|
||||
|
@ -139,6 +141,7 @@ const PostStatusForm = {
|
|||
poll: {},
|
||||
mediaDescriptions: {},
|
||||
visibility: this.suggestedVisibility(),
|
||||
language: interfaceLanguage,
|
||||
contentType
|
||||
}
|
||||
|
||||
|
@ -153,6 +156,7 @@ const PostStatusForm = {
|
|||
poll: this.statusPoll || {},
|
||||
mediaDescriptions: this.statusMediaDescriptions || {},
|
||||
visibility: this.statusScope || this.suggestedVisibility(),
|
||||
language: this.statusLanguage || interfaceLanguage,
|
||||
contentType: statusContentType
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +263,10 @@ const PostStatusForm = {
|
|||
...mapGetters(['mergedConfig']),
|
||||
...mapState({
|
||||
mobileLayout: state => state.interface.mobileLayout
|
||||
})
|
||||
}),
|
||||
isoLanguages () {
|
||||
return iso6391.getAllCodes();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'newStatus': {
|
||||
|
@ -282,6 +289,7 @@ const PostStatusForm = {
|
|||
files: [],
|
||||
visibility: newStatus.visibility,
|
||||
contentType: newStatus.contentType,
|
||||
language: newStatus.language,
|
||||
poll: {},
|
||||
mediaDescriptions: {}
|
||||
}
|
||||
|
@ -341,6 +349,7 @@ const PostStatusForm = {
|
|||
inReplyToStatusId: this.replyTo,
|
||||
quoteId: this.quoteId,
|
||||
contentType: newStatus.contentType,
|
||||
language: newStatus.language,
|
||||
poll,
|
||||
idempotencyKey: this.idempotencyKey
|
||||
}
|
||||
|
@ -375,6 +384,7 @@ const PostStatusForm = {
|
|||
inReplyToStatusId: this.replyTo,
|
||||
quoteId: this.quoteId,
|
||||
contentType: newStatus.contentType,
|
||||
language: newStatus.language,
|
||||
poll: {},
|
||||
preview: true
|
||||
}).then((data) => {
|
||||
|
|
|
@ -194,6 +194,23 @@
|
|||
:on-scope-change="changeVis"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="language-selector"
|
||||
>
|
||||
<Select
|
||||
id="post-language"
|
||||
v-model="newStatus.language"
|
||||
class="form-control"
|
||||
>
|
||||
<option
|
||||
v-for="language in isoLanguages"
|
||||
:key="language"
|
||||
:value="language"
|
||||
>
|
||||
{{ language }}
|
||||
</option>
|
||||
</Select>
|
||||
</div>
|
||||
<div
|
||||
v-if="postFormats.length > 1"
|
||||
class="text-format"
|
||||
|
|
|
@ -407,6 +407,15 @@
|
|||
{{ $t('settings.preload_images') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path="useBlurhash"
|
||||
expert="1"
|
||||
:disabled="!hideNsfw"
|
||||
>
|
||||
{{ $t('settings.use_blurhash') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path="useOneClickNsfw"
|
||||
|
|
|
@ -939,6 +939,7 @@
|
|||
"title": "Version"
|
||||
},
|
||||
"virtual_scrolling": "Optimize timeline rendering",
|
||||
"use_blurhash": "Use blurhashes for NSFW thumbnails",
|
||||
"word_filter": "Word filter",
|
||||
"wordfilter": "Wordfilter"
|
||||
},
|
||||
|
|
|
@ -117,7 +117,8 @@ export const defaultState = {
|
|||
maxDepthInThread: undefined, // instance default
|
||||
translationLanguage: undefined, // instance default,
|
||||
supportedTranslationLanguages: {}, // instance default
|
||||
userProfileDefaultTab: 'statuses'
|
||||
userProfileDefaultTab: 'statuses',
|
||||
useBlurhash: true,
|
||||
}
|
||||
|
||||
// caching the instance default properties
|
||||
|
|
|
@ -872,7 +872,8 @@ const postStatus = ({
|
|||
quoteId,
|
||||
contentType,
|
||||
preview,
|
||||
idempotencyKey
|
||||
idempotencyKey,
|
||||
language
|
||||
}) => {
|
||||
const form = new FormData()
|
||||
const pollOptions = poll.options || []
|
||||
|
@ -883,6 +884,7 @@ const postStatus = ({
|
|||
if (visibility) form.append('visibility', visibility)
|
||||
if (sensitive) form.append('sensitive', sensitive)
|
||||
if (contentType) form.append('content_type', contentType)
|
||||
if (language) form.append('language', language)
|
||||
mediaIds.forEach(val => {
|
||||
form.append('media_ids[]', val)
|
||||
})
|
||||
|
|
|
@ -235,13 +235,14 @@ export const parseAttachment = (data) => {
|
|||
if (masto) {
|
||||
// Not exactly same...
|
||||
output.mimetype = data.pleroma ? data.pleroma.mime_type : data.type
|
||||
output.meta = data.meta // not present in BE yet
|
||||
output.meta = data.meta
|
||||
output.id = data.id
|
||||
} else {
|
||||
output.mimetype = data.mimetype
|
||||
// output.meta = ??? missing
|
||||
}
|
||||
|
||||
output.blurhash = data.blurhash
|
||||
output.url = data.url
|
||||
output.large_thumb_url = data.preview_url
|
||||
output.description = data.description
|
||||
|
|
|
@ -13,7 +13,8 @@ const postStatus = ({
|
|||
quoteId = undefined,
|
||||
contentType = 'text/plain',
|
||||
preview = false,
|
||||
idempotencyKey = ''
|
||||
idempotencyKey = '',
|
||||
language
|
||||
}) => {
|
||||
const mediaIds = map(media, 'id')
|
||||
|
||||
|
@ -29,7 +30,8 @@ const postStatus = ({
|
|||
contentType,
|
||||
poll,
|
||||
preview,
|
||||
idempotencyKey
|
||||
idempotencyKey,
|
||||
language
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data.error && !preview) {
|
||||
|
|
BIN
static/blurhash-overlay.png
Executable file
BIN
static/blurhash-overlay.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
|
@ -2494,6 +2494,11 @@ binary-extensions@^2.0.0:
|
|||
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
|
||||
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
||||
|
||||
blurhash@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-2.0.4.tgz#60642a823b50acaaf3732ddb6c7dfd721bdfef2a"
|
||||
integrity sha512-r/As72u2FbucLoK5NTegM/GucxJc3d8GvHc4ngo13IO/nt2HU4gONxNLq1XPN6EM/V8Y9URIa7PcSz2RZu553A==
|
||||
|
||||
body-parser@1.19.2:
|
||||
version "1.19.2"
|
||||
resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz"
|
||||
|
@ -5090,9 +5095,9 @@ isexe@^2.0.0:
|
|||
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
|
||||
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
|
||||
|
||||
iso-639-1@2.1.15:
|
||||
iso-639-1@^2.1.15:
|
||||
version "2.1.15"
|
||||
resolved "https://registry.npmjs.org/iso-639-1/-/iso-639-1-2.1.15.tgz"
|
||||
resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.1.15.tgz#20cf78a4f691aeb802c16f17a6bad7d99271e85d"
|
||||
integrity sha512-7c7mBznZu2ktfvyT582E2msM+Udc1EjOyhVRE/0ZsjD9LBtWSm23h3PtiRh2a35XoUsTQQjJXaJzuLjXsOdFDg==
|
||||
|
||||
isobject@^3.0.1:
|
||||
|
|
Loading…
Reference in a new issue