diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bfc41ac4..dbb1dc85 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,5 +10,5 @@ Contributors of this project. - shpuld (shpuld@shitposter.club): CSS and styling - Vincent Guth (https://unsplash.com/photos/XrwVIFy6rTw): Background images. - hj (hj@shigusegubu.club): Code -- Sean King (seanking@freespeechextremist.com): Code +- Sean King (seanking@kazv.moe): Code - Tusooa Zhu (tusooa@kazv.moe): Code diff --git a/build/build.js b/build/build.js index 35969eb6..8242bc5f 100644 --- a/build/build.js +++ b/build/build.js @@ -36,4 +36,8 @@ webpack(webpackConfig, function (err, stats) { chunks: false, chunkModules: false }) + '\n') + if (stats.hasErrors()) { + console.error('See above for errors.') + process.exit(1) + } }) diff --git a/package.json b/package.json index 46345560..369b034d 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@vue/babel-helper-vue-jsx-merge-props": "1.4.0", "@vue/babel-plugin-jsx": "1.1.1", "@vue/compiler-sfc": "3.2.41", - "@vue/test-utils": "2.2.1", + "@vue/test-utils": "2.2.6", "autoprefixer": "10.4.12", "babel-loader": "8.2.5", "babel-plugin-lodash": "3.3.4", @@ -71,7 +71,7 @@ "css-loader": "6.7.1", "css-minimizer-webpack-plugin": "4.2.2", "custom-event-polyfill": "1.0.7", - "eslint": "8.26.0", + "eslint": "8.29.0", "eslint-config-standard": "17.0.0", "eslint-formatter-friendly": "7.0.0", "eslint-plugin-import": "2.26.0", @@ -109,7 +109,7 @@ "semver": "7.3.8", "serviceworker-webpack5-plugin": "2.0.0", "shelljs": "0.8.5", - "sinon": "14.0.1", + "sinon": "14.0.2", "sinon-chai": "3.7.0", "stylelint": "13.13.1", "stylelint-config-standard": "20.0.0", diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 36e0eec8..7886bdb2 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -376,6 +376,7 @@ const afterStoreSetup = async ({ store, i18n }) => { // Start fetching things that don't need to block the UI store.dispatch('fetchMutes') + store.dispatch('startFetchingAnnouncements') getTOS({ store }) getStickers({ store }) diff --git a/src/boot/routes.js b/src/boot/routes.js index 63dd1297..2dc900e7 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -24,6 +24,7 @@ import Lists from 'components/lists/lists.vue' import ListsTimeline from 'components/lists_timeline/lists_timeline.vue' import ListsEdit from 'components/lists_edit/lists_edit.vue' import NavPanel from 'src/components/nav_panel/nav_panel.vue' +import AnnouncementsPage from 'components/announcements_page/announcements_page.vue' export default (store) => { const validateAuthenticatedRoute = (to, from, next) => { @@ -76,6 +77,7 @@ export default (store) => { { name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) }, { name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute }, { name: 'about', path: '/about', component: About }, + { name: 'announcements', path: '/announcements', component: AnnouncementsPage }, { name: 'user-profile', path: '/users/:name', component: UserProfile }, { name: 'legacy-user-profile', path: '/:name', component: UserProfile }, { name: 'lists', path: '/lists', component: Lists }, diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js new file mode 100644 index 00000000..c10c7d90 --- /dev/null +++ b/src/components/announcement/announcement.js @@ -0,0 +1,105 @@ +import { mapState } from 'vuex' +import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' +import RichContent from '../rich_content/rich_content.jsx' +import localeService from '../../services/locale/locale.service.js' + +const Announcement = { + components: { + AnnouncementEditor, + RichContent + }, + data () { + return { + editing: false, + editedAnnouncement: { + content: '', + startsAt: undefined, + endsAt: undefined, + allDay: undefined + }, + editError: '' + } + }, + props: { + announcement: Object + }, + computed: { + ...mapState({ + currentUser: state => state.users.currentUser + }), + content () { + return this.announcement.content + }, + isRead () { + return this.announcement.read + }, + publishedAt () { + const time = this.announcement.published_at + if (!time) { + return + } + + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) + }, + startsAt () { + const time = this.announcement.starts_at + if (!time) { + return + } + + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) + }, + endsAt () { + const time = this.announcement.ends_at + if (!time) { + return + } + + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) + }, + inactive () { + return this.announcement.inactive + } + }, + methods: { + markAsRead () { + if (!this.isRead) { + return this.$store.dispatch('markAnnouncementAsRead', this.announcement.id) + } + }, + deleteAnnouncement () { + return this.$store.dispatch('deleteAnnouncement', this.announcement.id) + }, + formatTimeOrDate (time, locale) { + const d = new Date(time) + return this.announcement.all_day ? d.toLocaleDateString(locale) : d.toLocaleString(locale) + }, + enterEditMode () { + this.editedAnnouncement.content = this.announcement.pleroma.raw_content + this.editedAnnouncement.startsAt = this.announcement.starts_at + this.editedAnnouncement.endsAt = this.announcement.ends_at + this.editedAnnouncement.allDay = this.announcement.all_day + this.editing = true + }, + submitEdit () { + this.$store.dispatch('editAnnouncement', { + id: this.announcement.id, + ...this.editedAnnouncement + }) + .then(() => { + this.editing = false + }) + .catch(error => { + this.editError = error.error + }) + }, + cancelEdit () { + this.editing = false + }, + clearError () { + this.editError = undefined + } + } +} + +export default Announcement diff --git a/src/components/announcement/announcement.vue b/src/components/announcement/announcement.vue new file mode 100644 index 00000000..5f64232a --- /dev/null +++ b/src/components/announcement/announcement.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/src/components/announcement_editor/announcement_editor.js b/src/components/announcement_editor/announcement_editor.js new file mode 100644 index 00000000..79a03afe --- /dev/null +++ b/src/components/announcement_editor/announcement_editor.js @@ -0,0 +1,13 @@ +import Checkbox from '../checkbox/checkbox.vue' + +const AnnouncementEditor = { + components: { + Checkbox + }, + props: { + announcement: Object, + disabled: Boolean + } +} + +export default AnnouncementEditor diff --git a/src/components/announcement_editor/announcement_editor.vue b/src/components/announcement_editor/announcement_editor.vue new file mode 100644 index 00000000..0f29f9f7 --- /dev/null +++ b/src/components/announcement_editor/announcement_editor.vue @@ -0,0 +1,60 @@ +