start on content warnings
This commit is contained in:
parent
1de9e49f78
commit
2f5e19bd44
6
routes/_actions/contentWarnings.js
Normal file
6
routes/_actions/contentWarnings.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { store } from '../_store/store'
|
||||||
|
|
||||||
|
export function toggleContentWarningShown (realm) {
|
||||||
|
let shown = store.getComposeData(realm, 'contentWarningShown')
|
||||||
|
store.setComposeData(realm, {contentWarningShown: !shown})
|
||||||
|
}
|
|
@ -12,7 +12,7 @@
|
||||||
}
|
}
|
||||||
.compose-box-display-name {
|
.compose-box-display-name {
|
||||||
color: var(--deemphasized-text-color);
|
color: var(--deemphasized-text-color);
|
||||||
grid-area: display-name;
|
grid-area: name;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<div class="compose-box {{overLimit ? 'over-char-limit' : ''}}">
|
<div class="compose-box {{overLimit ? 'over-char-limit' : ''}}">
|
||||||
<ComposeAuthor />
|
<ComposeAuthor />
|
||||||
|
{{#if contentWarningShown}}
|
||||||
|
<ComposeContentWarning :realm :contentWarning />
|
||||||
|
{{/if}}
|
||||||
<ComposeInput :realm :text />
|
<ComposeInput :realm :text />
|
||||||
<ComposeLengthGauge :textLength :textOverLimit />
|
<ComposeLengthGauge :textLength :textOverLimit />
|
||||||
<ComposeToolbar :realm :postPrivacy :media />
|
<ComposeToolbar :realm :postPrivacy :media :contentWarningShown />
|
||||||
<ComposeLengthIndicator :textLength :textOverLimit />
|
<ComposeLengthIndicator :textLength :textOverLimit />
|
||||||
<ComposeMedia :realm :media />
|
<ComposeMedia :realm :media />
|
||||||
<ComposeButton :textLength :textOverLimit />
|
<ComposeButton :textLength :textOverLimit />
|
||||||
|
@ -14,12 +17,13 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"avatar display-name handle handle"
|
"avatar name handle handle"
|
||||||
"avatar input input input"
|
"avatar cw cw cw"
|
||||||
"avatar gauge gauge gauge"
|
"avatar input input input"
|
||||||
"avatar toolbar toolbar length"
|
"avatar gauge gauge gauge"
|
||||||
"avatar media media media"
|
"avatar toolbar toolbar length"
|
||||||
"avatar button button button";
|
"avatar media media media"
|
||||||
|
"avatar button button button";
|
||||||
grid-template-columns: min-content minmax(0, max-content) 1fr 1fr;
|
grid-template-columns: min-content minmax(0, max-content) 1fr 1fr;
|
||||||
border-bottom: 1px solid var(--main-border);
|
border-bottom: 1px solid var(--main-border);
|
||||||
width: 560px;
|
width: 560px;
|
||||||
|
@ -42,6 +46,7 @@
|
||||||
import ComposeInput from './ComposeInput.html'
|
import ComposeInput from './ComposeInput.html'
|
||||||
import ComposeButton from './ComposeButton.html'
|
import ComposeButton from './ComposeButton.html'
|
||||||
import ComposeMedia from './ComposeMedia.html'
|
import ComposeMedia from './ComposeMedia.html'
|
||||||
|
import ComposeContentWarning from './ComposeContentWarning.html'
|
||||||
import { measureText } from '../../_utils/measureText'
|
import { measureText } from '../../_utils/measureText'
|
||||||
import { CHAR_LIMIT, POST_PRIVACY_OPTIONS } from '../../_static/statuses'
|
import { CHAR_LIMIT, POST_PRIVACY_OPTIONS } from '../../_static/statuses'
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
|
@ -54,7 +59,8 @@
|
||||||
ComposeLengthIndicator,
|
ComposeLengthIndicator,
|
||||||
ComposeInput,
|
ComposeInput,
|
||||||
ComposeButton,
|
ComposeButton,
|
||||||
ComposeMedia
|
ComposeMedia,
|
||||||
|
ComposeContentWarning
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -65,7 +71,9 @@
|
||||||
defaultPostPrivacyKey: ($currentVerifyCredentials) => $currentVerifyCredentials.source.privacy,
|
defaultPostPrivacyKey: ($currentVerifyCredentials) => $currentVerifyCredentials.source.privacy,
|
||||||
postPrivacyKey: (composeData, defaultPostPrivacyKey) => composeData.postPrivacy || defaultPostPrivacyKey,
|
postPrivacyKey: (composeData, defaultPostPrivacyKey) => composeData.postPrivacy || defaultPostPrivacyKey,
|
||||||
textLength: (text) => measureText(text),
|
textLength: (text) => measureText(text),
|
||||||
textOverLimit: (textLength) => textLength > CHAR_LIMIT
|
textOverLimit: (textLength) => textLength > CHAR_LIMIT,
|
||||||
|
contentWarningShown: (composeData) => composeData.contentWarningShown,
|
||||||
|
contentWarning: (composeData) => composeData.contentWarning || ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
49
routes/_components/compose/ComposeContentWarning.html
Normal file
49
routes/_components/compose/ComposeContentWarning.html
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<input class="content-warning-input"
|
||||||
|
type="text"
|
||||||
|
placeholder="Content warning"
|
||||||
|
aria-label="Content warning"
|
||||||
|
bind:value=rawText
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
.content-warning-input {
|
||||||
|
grid-area: cw;
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin: 10px 0 0 5px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid var(--input-border);
|
||||||
|
width: calc(100% - 5px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import { store } from '../../_store/store'
|
||||||
|
import debounce from 'lodash/debounce'
|
||||||
|
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
oncreate() {
|
||||||
|
this.setupSyncFromStore()
|
||||||
|
this.setupSyncToStore()
|
||||||
|
},
|
||||||
|
store: () => store,
|
||||||
|
data: () => ({
|
||||||
|
rawText: ''
|
||||||
|
}),
|
||||||
|
methods: {
|
||||||
|
setupSyncFromStore() {
|
||||||
|
this.observe('contentWarning', contentWarning => {
|
||||||
|
this.set({rawText: contentWarning})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setupSyncToStore() {
|
||||||
|
const saveText = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
|
||||||
|
|
||||||
|
this.observe('rawText', rawText => {
|
||||||
|
this.store.setComposeData(this.get('realm'), {
|
||||||
|
contentWarning: rawText
|
||||||
|
})
|
||||||
|
saveText()
|
||||||
|
}, {init: false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -17,8 +17,11 @@
|
||||||
on:click="onPostPrivacyClick()"
|
on:click="onPostPrivacyClick()"
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
label="Add content warning"
|
label="{{contentWarningShown ? 'Remove content warning' : 'Add content warning'}}"
|
||||||
href="#fa-exclamation-triangle"
|
href="#fa-exclamation-triangle"
|
||||||
|
on:click="onContentWarningClick()"
|
||||||
|
pressable="true"
|
||||||
|
pressed="{{contentWarningShown}}"
|
||||||
/>
|
/>
|
||||||
<input ref:input
|
<input ref:input
|
||||||
on:change="onFileChange(event)"
|
on:change="onFileChange(event)"
|
||||||
|
@ -40,7 +43,7 @@
|
||||||
import { updateCustomEmojiForInstance } from '../../_actions/emoji'
|
import { updateCustomEmojiForInstance } from '../../_actions/emoji'
|
||||||
import { importDialogs } from '../../_utils/asyncModules'
|
import { importDialogs } from '../../_utils/asyncModules'
|
||||||
import { doMediaUpload } from '../../_actions/media'
|
import { doMediaUpload } from '../../_actions/media'
|
||||||
import { POST_PRIVACY_OPTIONS } from '../../_static/statuses'
|
import { toggleContentWarningShown } from '../../_actions/contentWarnings'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate() {
|
oncreate() {
|
||||||
|
@ -75,6 +78,9 @@
|
||||||
async onPostPrivacyClick() {
|
async onPostPrivacyClick() {
|
||||||
let dialogs = await importDialogs()
|
let dialogs = await importDialogs()
|
||||||
dialogs.showPostPrivacyDialog(this.get('realm'))
|
dialogs.showPostPrivacyDialog(this.get('realm'))
|
||||||
|
},
|
||||||
|
onContentWarningClick() {
|
||||||
|
toggleContentWarningShown(this.get('realm'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ test('inserts media', async t => {
|
||||||
test('removes media', async t => {
|
test('removes media', async t => {
|
||||||
await t.useRole(foobarRole)
|
await t.useRole(foobarRole)
|
||||||
await (uploadKittenImage(1)())
|
await (uploadKittenImage(1)())
|
||||||
|
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
||||||
await (uploadKittenImage(2)())
|
await (uploadKittenImage(2)())
|
||||||
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
||||||
.expect(getNthMedia(2).getAttribute('alt')).eql('kitten2.jpg')
|
.expect(getNthMedia(2).getAttribute('alt')).eql('kitten2.jpg')
|
||||||
|
|
Loading…
Reference in a new issue