diff --git a/src/App.scss b/src/App.scss
index 9f7ef860f..ae6561a94 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -63,6 +63,8 @@ button{
box-shadow: 0px 0px 2px black;
font-size: 14px;
font-family: sans-serif;
+ min-width: 10em;
+ min-height: 2em;
&:hover {
box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3);
@@ -441,3 +443,23 @@ nav {
text-align: right;
padding-right: 20px;
}
+
+.visibility-tray {
+ font-size: 1.2em;
+ padding: 3px;
+ cursor: pointer;
+
+ .selected {
+ color: $fallback--lightFg;
+ color: var(--lightFg, $fallback--lightFg);
+ }
+}
+
+.visibility-notice {
+ padding: .5em;
+ border: 1px solid $fallback--faint;
+ border: 1px solid var(--faint, $fallback--faint);
+ border-radius: $fallback--inputRadius;
+ border-radius: var(--inputRadius, $fallback--inputRadius);
+}
+
diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue
index b7fed48af..d2bdffcb4 100644
--- a/src/components/login_form/login_form.vue
+++ b/src/components/login_form/login_form.vue
@@ -34,11 +34,6 @@
@import '../../_variables.scss';
.login-form {
- .btn {
- min-height: 28px;
- width: 10em;
- }
-
.error {
text-align: center;
}
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 61f2ac0a0..ff3bb9062 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -54,7 +54,7 @@ const PostStatusForm = {
newStatus: {
status: statusText,
files: [],
- visibility: this.messageScope || 'public'
+ visibility: this.messageScope || this.$store.state.users.currentUser.default_scope
},
caret: 0
}
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index ce078fe13..1e1c6f1da 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -101,35 +101,12 @@
}
}
-.post-status-form .visibility-tray {
- font-size: 1.2em;
- padding: 3px;
- cursor: pointer;
-
- .selected {
- color: $fallback--lightFg;
- color: var(--lightFg, $fallback--lightFg);
- }
-}
-
-.visibility-notice {
- padding: .5em;
- border: 1px solid $fallback--faint;
- border: 1px solid var(--faint, $fallback--faint);
- border-radius: $fallback--inputRadius;
- border-radius: var(--inputRadius, $fallback--inputRadius);
-}
-
.post-status-form, .login {
.form-bottom {
display: flex;
padding: 0.5em;
height: 32px;
- button {
- width: 10em;
- }
-
p {
margin: 0.35em;
padding: 0.35em;
diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js
index 169b90804..c85ef59f6 100644
--- a/src/components/settings/settings.js
+++ b/src/components/settings/settings.js
@@ -15,6 +15,7 @@ const settings = {
streamingLocal: this.$store.state.config.streaming,
pauseOnUnfocusedLocal: this.$store.state.config.pauseOnUnfocused,
hoverPreviewLocal: this.$store.state.config.hoverPreview,
+ collapseMessageWithSubjectLocal: this.$store.state.config.collapseMessageWithSubject,
stopGifs: this.$store.state.config.stopGifs,
loopSilentAvailable:
// Firefox
@@ -65,6 +66,9 @@ const settings = {
value = filter(value.split('\n'), (word) => trim(word).length > 0)
this.$store.dispatch('setOption', { name: 'muteWords', value })
},
+ collapseMessageWithSubjectLocal (value) {
+ this.$store.dispatch('setOption', { name: 'collapseMessageWithSubject', value })
+ },
stopGifs (value) {
this.$store.dispatch('setOption', { name: 'stopGifs', value })
}
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index d6aec2ffb..170f57738 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -16,6 +16,10 @@
{{$t('nav.timeline')}}
+ -
+
+
+
-
@@ -113,8 +117,6 @@
.btn {
margin-top: 1em;
- min-height: 28px;
- width: 10em;
}
}
.setting-list {
diff --git a/src/components/status/status.js b/src/components/status/status.js
index a2d6f41f9..9670f69d2 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -22,15 +22,18 @@ const Status = {
'noHeading',
'inlineExpanded'
],
- data: () => ({
- replying: false,
- expanded: false,
- unmuted: false,
- userExpanded: false,
- preview: null,
- showPreview: false,
- showingTall: false
- }),
+ data () {
+ return {
+ replying: false,
+ expanded: false,
+ unmuted: false,
+ userExpanded: false,
+ preview: null,
+ showPreview: false,
+ showingTall: false,
+ expandingSubject: !this.$store.state.config.collapseMessageWithSubject
+ }
+ },
computed: {
muteWords () {
return this.$store.state.config.muteWords
@@ -98,12 +101,27 @@ const Status = {
//
// Using max-height + overflow: auto for status components resulted in false positives
// very often with japanese characters, and it was very annoying.
+ tallStatus () {
+ const lengthScore = this.status.statusnet_html.split(/
20
+ },
+ hideSubjectStatus () {
+ if (this.tallStatus && !this.$store.state.config.collapseMessageWithSubject) {
+ return false
+ }
+ return !this.expandingSubject && this.status.summary
+ },
hideTallStatus () {
+ if (this.status.summary && this.$store.state.config.collapseMessageWithSubject) {
+ return false
+ }
if (this.showingTall) {
return false
}
- const lengthScore = this.status.statusnet_html.split(/
20
+ return this.tallStatus
+ },
+ showingMore () {
+ return this.showingTall || (this.status.summary && this.expandingSubject)
},
attachmentSize () {
if ((this.$store.state.config.hideAttachments && !this.inConversation) ||
@@ -163,8 +181,16 @@ const Status = {
toggleUserExpanded () {
this.userExpanded = !this.userExpanded
},
- toggleShowTall () {
- this.showingTall = !this.showingTall
+ toggleShowMore () {
+ if (this.showingTall) {
+ this.showingTall = false
+ } else if (this.expandingSubject) {
+ this.expandingSubject = false
+ } else if (this.hideTallStatus) {
+ this.showingTall = true
+ } else if (this.hideSubjectStatus) {
+ this.expandingSubject = true
+ }
},
replyEnter (id, event) {
this.showPreview = true
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index b8993b0d4..e7d5ed7ad 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -76,9 +76,11 @@
@@ -310,7 +312,7 @@
}
}
- .tall-status-unhider {
+ .status-unhider, .cw-status-hider {
width: 100%;
text-align: center;
}
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 6f4845c44..95c15b496 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -5,6 +5,7 @@ export default {
return {
availableStyles: [],
selected: this.$store.state.config.theme,
+ invalidThemeImported: false,
bgColorLocal: '',
btnColorLocal: '',
textColorLocal: '',
@@ -32,25 +33,61 @@ export default {
})
},
mounted () {
- this.bgColorLocal = rgbstr2hex(this.$store.state.config.colors.bg)
- this.btnColorLocal = rgbstr2hex(this.$store.state.config.colors.btn)
- this.textColorLocal = rgbstr2hex(this.$store.state.config.colors.fg)
- this.linkColorLocal = rgbstr2hex(this.$store.state.config.colors.link)
-
- this.redColorLocal = rgbstr2hex(this.$store.state.config.colors.cRed)
- this.blueColorLocal = rgbstr2hex(this.$store.state.config.colors.cBlue)
- this.greenColorLocal = rgbstr2hex(this.$store.state.config.colors.cGreen)
- this.orangeColorLocal = rgbstr2hex(this.$store.state.config.colors.cOrange)
-
- this.btnRadiusLocal = this.$store.state.config.radii.btnRadius || 4
- this.inputRadiusLocal = this.$store.state.config.radii.inputRadius || 4
- this.panelRadiusLocal = this.$store.state.config.radii.panelRadius || 10
- this.avatarRadiusLocal = this.$store.state.config.radii.avatarRadius || 5
- this.avatarAltRadiusLocal = this.$store.state.config.radii.avatarAltRadius || 50
- this.tooltipRadiusLocal = this.$store.state.config.radii.tooltipRadius || 2
- this.attachmentRadiusLocal = this.$store.state.config.radii.attachmentRadius || 5
+ this.normalizeLocalState(this.$store.state.config.colors, this.$store.state.config.radii)
},
methods: {
+ exportCurrentTheme () {
+ const stringified = JSON.stringify({
+ // To separate from other random JSON files and possible future theme formats
+ _pleroma_theme_version: 1,
+ colors: this.$store.state.config.colors,
+ radii: this.$store.state.config.radii
+ }, null, 2) // Pretty-print and indent with 2 spaces
+
+ // Create an invisible link with a data url and simulate a click
+ const e = document.createElement('a')
+ e.setAttribute('download', 'pleroma_theme.json')
+ e.setAttribute('href', 'data:application/json;base64,' + window.btoa(stringified))
+ e.style.display = 'none'
+
+ document.body.appendChild(e)
+ e.click()
+ document.body.removeChild(e)
+ },
+
+ importTheme () {
+ this.invalidThemeImported = false
+ const filePicker = document.createElement('input')
+ filePicker.setAttribute('type', 'file')
+ filePicker.setAttribute('accept', '.json')
+
+ filePicker.addEventListener('change', event => {
+ if (event.target.files[0]) {
+ // eslint-disable-next-line no-undef
+ const reader = new FileReader()
+ reader.onload = ({target}) => {
+ try {
+ const parsed = JSON.parse(target.result)
+ if (parsed._pleroma_theme_version === 1) {
+ this.normalizeLocalState(parsed.colors, parsed.radii)
+ } else {
+ // A theme from the future, spooky
+ this.invalidThemeImported = true
+ }
+ } catch (e) {
+ // This will happen both if there is a JSON syntax error or the theme is missing components
+ this.invalidThemeImported = true
+ }
+ }
+ reader.readAsText(event.target.files[0])
+ }
+ })
+
+ document.body.appendChild(filePicker)
+ filePicker.click()
+ document.body.removeChild(filePicker)
+ },
+
setCustomTheme () {
if (!this.bgColorLocal && !this.btnColorLocal && !this.linkColorLocal) {
// reset to picked themes
@@ -95,6 +132,26 @@ export default {
attachmentRadius: this.attachmentRadiusLocal
}})
}
+ },
+
+ normalizeLocalState (colors, radii) {
+ this.bgColorLocal = rgbstr2hex(colors.bg)
+ this.btnColorLocal = rgbstr2hex(colors.btn)
+ this.textColorLocal = rgbstr2hex(colors.fg)
+ this.linkColorLocal = rgbstr2hex(colors.link)
+
+ this.redColorLocal = rgbstr2hex(colors.cRed)
+ this.blueColorLocal = rgbstr2hex(colors.cBlue)
+ this.greenColorLocal = rgbstr2hex(colors.cGreen)
+ this.orangeColorLocal = rgbstr2hex(colors.cOrange)
+
+ this.btnRadiusLocal = radii.btnRadius || 4
+ this.inputRadiusLocal = radii.inputRadius || 4
+ this.panelRadiusLocal = radii.panelRadius || 10
+ this.avatarRadiusLocal = radii.avatarRadius || 5
+ this.avatarAltRadiusLocal = radii.avatarAltRadius || 50
+ this.tooltipRadiusLocal = radii.tooltipRadius || 2
+ this.attachmentRadiusLocal = radii.attachmentRadius || 5
}
},
watch: {
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 112bbc1e1..59bd2971d 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -11,6 +11,11 @@
+
+
+
+
{{ $t('settings.invalid_theme_imported') }}
+
{{$t('settings.theme_help')}}
@@ -134,6 +139,11 @@
margin-right: 1em;
}
+.import-warning {
+ color: $fallback--cRed;
+ color: var(--cRed, $fallback--cRed);
+}
+
.radius-container,
.color-container {
display: flex;
diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js
index 443e63dd2..f046885ed 100644
--- a/src/components/user_settings/user_settings.js
+++ b/src/components/user_settings/user_settings.js
@@ -6,6 +6,7 @@ const UserSettings = {
newname: this.$store.state.users.currentUser.name,
newbio: this.$store.state.users.currentUser.description,
newlocked: this.$store.state.users.currentUser.locked,
+ newdefaultScope: this.$store.state.users.currentUser.default_scope,
followList: null,
followImportError: false,
followsImported: false,
@@ -17,7 +18,8 @@ const UserSettings = {
deleteAccountError: false,
changePasswordInputs: [ '', '', '' ],
changedPassword: false,
- changePasswordError: false
+ changePasswordError: false,
+ activeTab: 'profile'
}
},
components: {
@@ -29,6 +31,17 @@ const UserSettings = {
},
pleromaBackend () {
return this.$store.state.config.pleromaBackend
+ },
+ scopeOptionsEnabled () {
+ return this.$store.state.config.scopeOptionsEnabled
+ },
+ vis () {
+ return {
+ public: { selected: this.newdefaultScope === 'public' },
+ unlisted: { selected: this.newdefaultScope === 'unlisted' },
+ private: { selected: this.newdefaultScope === 'private' },
+ direct: { selected: this.newdefaultScope === 'direct' }
+ }
}
},
methods: {
@@ -36,12 +49,18 @@ const UserSettings = {
const name = this.newname
const description = this.newbio
const locked = this.newlocked
- this.$store.state.api.backendInteractor.updateProfile({params: {name, description, locked}}).then((user) => {
+ /* eslint-disable camelcase */
+ const default_scope = this.newdefaultScope
+ this.$store.state.api.backendInteractor.updateProfile({params: {name, description, locked, default_scope}}).then((user) => {
if (!user.error) {
this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user)
}
})
+ /* eslint-enable camelcase */
+ },
+ changeVis (visibility) {
+ this.newdefaultScope = visibility
},
uploadFile (slot, e) {
const file = e.target.files[0]
@@ -217,6 +236,9 @@ const UserSettings = {
this.changePasswordError = res.error
}
})
+ },
+ activateTab (tabName) {
+ this.activeTab = tabName
}
}
}
diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue
index 881b0fa18..c3ca1dbd3 100644
--- a/src/components/user_settings/user_settings.vue
+++ b/src/components/user_settings/user_settings.vue
@@ -4,19 +4,33 @@
{{$t('settings.user_settings')}}
-
+
+
+
+
+
+
{{$t('settings.name_bio')}}
{{$t('settings.name')}}
{{$t('settings.bio')}}
-
+
+
+
+
+
+
+
+
+
+
-
+
{{$t('settings.avatar')}}
{{$t('settings.current_avatar')}}
![]()
@@ -29,7 +43,7 @@
-
+
{{$t('settings.profile_banner')}}
{{$t('settings.current_profile_banner')}}
![]()
@@ -42,7 +56,7 @@
-
+
{{$t('settings.profile_background')}}
{{$t('settings.set_new_profile_background')}}
![]()
@@ -53,7 +67,7 @@
-
+
{{$t('settings.change_password')}}
{{$t('settings.current_password')}}
@@ -72,7 +86,7 @@
{{$t('settings.change_password_error')}}
{{changePasswordError}}
-
+
{{$t('settings.follow_import')}}
{{$t('settings.import_followers_from_a_csv_file')}}
-
+
{{$t('settings.follow_export')}}
-
+
{{$t('settings.follow_export_processing')}}
-
+
{{$t('settings.delete_account')}}
{{$t('settings.delete_account_description')}}
@@ -137,4 +151,13 @@
margin: 0.25em;
}
}
+
+.tab-switcher {
+ margin: 7px 7px;
+ display: inline-block;
+
+ button {
+ height: 30px;
+ }
+}
diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index e8f77ca12..d0fc50137 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -48,6 +48,9 @@ const de = {
settings: 'Einstellungen',
theme: 'Farbschema',
presets: 'Voreinstellungen',
+ export_theme: 'Aktuelles Theme exportieren',
+ import_theme: 'Gespeichertes Theme laden',
+ invalid_theme_imported: 'Die ausgewählte Datei ist kein unterstütztes Pleroma-Theme. Keine Änderungen wurden vorgenommen.',
theme_help: 'Benutze HTML Farbcodes (#rrggbb) um dein Farbschema anzupassen',
radii_help: 'Kantenrundung (in Pixel) der Oberfläche anpassen',
background: 'Hintergrund',
@@ -288,7 +291,10 @@ const en = {
settings: 'Settings',
theme: 'Theme',
presets: 'Presets',
+ export_theme: 'Export current theme',
+ import_theme: 'Load saved theme',
theme_help: 'Use hex color codes (#rrggbb) to customize your color theme.',
+ invalid_theme_imported: 'The selected file is not a supported Pleroma theme. No changes to your theme were made.',
radii_help: 'Set up interface edge rounding (in pixels)',
background: 'Background',
foreground: 'Foreground',
@@ -311,6 +317,7 @@ const en = {
hide_attachments_in_tl: 'Hide attachments in timeline',
hide_attachments_in_convo: 'Hide attachments in conversations',
nsfw_clickthrough: 'Enable clickthrough NSFW attachment hiding',
+ collapse_subject: 'Collapse posts with subjects',
stop_gifs: 'Play-on-hover GIFs',
autoload: 'Enable automatic loading when scrolled to the bottom',
streaming: 'Enable automatic streaming of new posts when scrolled to the top',
@@ -336,7 +343,11 @@ const en = {
changed_password: 'Password changed successfully!',
change_password_error: 'There was an issue changing your password.',
lock_account_description: 'Restrict your account to approved followers only',
- limited_availability: 'Unavailable in your browser'
+ limited_availability: 'Unavailable in your browser',
+ default_vis: 'Default visibility scope',
+ profile_tab: 'Profile',
+ security_tab: 'Security',
+ data_import_export_tab: 'Data Import / Export'
},
notifications: {
notifications: 'Notifications',
diff --git a/src/main.js b/src/main.js
index 76f3061cf..d4fbaa7b1 100644
--- a/src/main.js
+++ b/src/main.js
@@ -45,6 +45,7 @@ Vue.use(VueChatScroll)
const persistedStateOptions = {
paths: [
+ 'config.collapseMessageWithSubject',
'config.hideAttachments',
'config.hideAttachmentsInConv',
'config.hideNsfw',
@@ -96,7 +97,7 @@ window.fetch('/api/statusnet/config.json')
window.fetch('/static/config.json')
.then((res) => res.json())
.then((data) => {
- const {theme, background, logo, showWhoToFollowPanel, whoToFollowProvider, whoToFollowLink, showInstanceSpecificPanel, scopeOptionsEnabled} = data
+ const {theme, background, logo, showWhoToFollowPanel, whoToFollowProvider, whoToFollowLink, showInstanceSpecificPanel, scopeOptionsEnabled, collapseMessageWithSubject} = data
store.dispatch('setOption', { name: 'theme', value: theme })
store.dispatch('setOption', { name: 'background', value: background })
store.dispatch('setOption', { name: 'logo', value: logo })
@@ -105,6 +106,7 @@ window.fetch('/static/config.json')
store.dispatch('setOption', { name: 'whoToFollowLink', value: whoToFollowLink })
store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
store.dispatch('setOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled })
+ store.dispatch('setOption', { name: 'collapseMessageWithSubject', value: collapseMessageWithSubject })
if (data['chatDisabled']) {
store.dispatch('disableChat')
}
diff --git a/src/modules/config.js b/src/modules/config.js
index fe31ab011..60210a950 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -4,6 +4,7 @@ import StyleSetter from '../services/style_setter/style_setter.js'
const defaultState = {
name: 'Pleroma FE',
colors: {},
+ collapseMessageWithSubject: false,
hideAttachments: false,
hideAttachmentsInConv: false,
hideNsfw: true,
diff --git a/static/config.json b/static/config.json
index bf16068a4..316b2af58 100644
--- a/static/config.json
+++ b/static/config.json
@@ -13,5 +13,6 @@
"whoToFollowLinkDummy2": "https://followlink.osa-p.net/recommend.html",
"showInstanceSpecificPanel": true,
"scopeOptionsEnabled": true,
- "registrationOpen": true
+ "registrationOpen": true,
+ "collapseMessageWithSubject": false
}