start on content warnings

This commit is contained in:
Nolan Lawson 2018-03-03 15:44:43 -08:00
parent 1de9e49f78
commit 2f5e19bd44
6 changed files with 82 additions and 12 deletions

View 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})
}

View file

@ -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;

View file

@ -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,7 +17,8 @@
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 cw cw cw"
"avatar input input input" "avatar input input input"
"avatar gauge gauge gauge" "avatar gauge gauge gauge"
"avatar toolbar toolbar length" "avatar toolbar toolbar length"
@ -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>

View 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>

View file

@ -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'))
} }
} }
} }

View file

@ -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')