Skip to content

Commit

Permalink
Add Rich-Content Feature to Landing Page (#175)
Browse files Browse the repository at this point in the history
* Add Rich-Content Feature to Landing Page

---------

Co-authored-by: odkhang <[email protected]>
  • Loading branch information
it-tma-tri and odkhang authored Aug 1, 2024
1 parent 7b67eec commit 2fa2037
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 100 deletions.
108 changes: 54 additions & 54 deletions webapp/src/components/ChatContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,55 +40,16 @@ export async function contentToPlainText (content) {
}
const generateHTML = (input) => {
if (!input) return
return markdownIt.renderInline(input)
if (!input) return
return markdownIt.renderInline(input)
}
export default {
functional: true,
props: {
content: String
},
data() {
return {
selectedUser: null
}
},
methods: {
showUserModal(user) {
this.selectedUser = user
this.$modal.show('user-modal')
},
closeUserModal() {
this.$modal.hide('user-modal')
}
},
render(createElement, ctx) {
const parts = ctx.props.content.split(mentionRegex)
const content = parts.map(string => {
if (string.match(mentionRegex)) {
const user = ctx.parent.$store.state.chat.usersLookup[string.slice(1)]
if (user) {
return { user }
}
}
return { html: generateHTML(string) }
})
return content.map(part => {
if (part.user) {
return createElement('span', {
class: 'mention',
on: {
click: () => ctx.parent.showUserModal(part.user)
}
}, getUserName(part.user))
}
return createElement('span', { domProps: { innerHTML: part.html } })
})
},
components: {
'user-modal': {
template: `
functional: true,
components: {
props: ['selectedUser'],
'user-modal': {
template: `
<modal name="user-modal" height="auto" @before-close="closeUserModal">
<div class="modal-content">
<h3>User Information</h3>
Expand All @@ -99,13 +60,52 @@ export default {
</div>
</modal>
`,
props: ['selectedUser'],
methods: {
closeUserModal() {
this.$emit('close')
}
}
}
}
methods: {
closeUserModal () {
this.$emit('close')
}
}
}
},
props: {
content: String
},
data () {
return {
selectedUser: null
}
},
methods: {
showUserModal (user) {
this.selectedUser = user
this.$modal.show('user-modal')
},
closeUserModal () {
this.$modal.hide('user-modal')
}
},
render (createElement, ctx) {
const parts = ctx.props.content.split(mentionRegex)
const content = parts.map(string => {
if (string.match(mentionRegex)) {
const user = ctx.parent.$store.state.chat.usersLookup[string.slice(1)]
if (user) {
return { user }
}
}
return { html: generateHTML(string) }
})
return content.map(part => {
if (part.user) {
return createElement('span', {
class: 'mention',
on: {
click: () => ctx.parent.showUserModal(part.user)
}
}, getUserName(part.user))
}
return createElement('span', { domProps: { innerHTML: part.html } })
})
}
}
</script>
30 changes: 15 additions & 15 deletions webapp/src/components/ChatInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ export default {
}
}
},
watch: {
async 'autocomplete.search' (search) {
// TODO debounce?
if (!this.autocomplete) return
if (this.autocomplete.type === 'mention') {
const { results } = await api.call('user.list.search', {search_term: search, page: 1, include_banned: false})
this.autocomplete.options = results
// if (results.length === 1) {
// this.autocomplete.selected = 0
// this.handleMention()
// }
}
}
},
mounted () {
this.quill = new Quill(this.$refs.editor, {
debug: ENV_DEVELOPMENT ? 'info' : 'warn',
Expand Down Expand Up @@ -111,20 +125,6 @@ export default {
}
}
},
watch: {
async 'autocomplete.search' (search) {
// TODO debounce?
if (!this.autocomplete) return
if (this.autocomplete.type === 'mention') {
const { results } = await api.call('user.list.search', {search_term: search, page: 1, include_banned: false})
this.autocomplete.options = results
// if (results.length === 1) {
// this.autocomplete.selected = 0
// this.handleMention()
// }
}
}
},
methods: {
onTextChange (delta, oldDelta, source) {
if (source !== 'user') return
Expand Down Expand Up @@ -384,4 +384,4 @@ export default {
padding: 1px
.name
ellipsis()
</style>
</style>
2 changes: 1 addition & 1 deletion webapp/src/components/ChatMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -466,4 +466,4 @@ export default {
.display-name
color: $clr-disabled-text-light
text-decoration: line-through
</style>
</style>
33 changes: 19 additions & 14 deletions webapp/src/components/LandingPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
ul.splide__list
li.splide__slide(v-for="sponsor of sponsors")
img.sponsor(:src="sponsor.logo", :alt="sponsor.name", @load="onSponsorImageLoad(sponsor.id)")
.content
.schedule
.content-container
.content
rich-text-content(v-if="hasMainContent", :content="module.config.main_content")
template(v-if="featuredSessions && featuredSessions.length")
.header
h3 {{ $t('LandingPage:sessions:featured:header') }}
Expand Down Expand Up @@ -53,9 +54,10 @@ import moment from 'lib/timetravelMoment'
import Identicon from 'components/Identicon'
import MarkdownContent from 'components/MarkdownContent'
import scheduleProvidesMixin from 'components/mixins/schedule-provides'
import RichTextContent from 'components/RichTextContent'
export default {
components: { Identicon, MarkdownContent, Session },
components: { Identicon, MarkdownContent, Session, RichTextContent },
mixins: [scheduleProvidesMixin],
props: {
module: Object
Expand Down Expand Up @@ -88,7 +90,10 @@ export default {
},
speakers () {
return this.schedule?.speakers.slice().sort((a, b) => a.name.split(' ').at(-1).localeCompare(b.name.split(' ').at(-1)))
}
},
hasMainContent () {
return this.module.config.main_content?.ops?.some(op => op.insert.trim() !== '')
},
},
async mounted () {
// TODO make this configurable?
Expand Down Expand Up @@ -147,7 +152,7 @@ export default {
height: 100%
max-width: 100%
object-fit: contain
.content
.content-container
display: flex
justify-content: center
gap: 32px
Expand All @@ -157,10 +162,14 @@ export default {
min-width: 0
display: flex
flex-direction: column
.markdown-content
padding: 0 16px
width: 100%
max-width: 560px
.content
display: flex
flex-direction: column
max-width: 960px
.header
padding: 0 8px
.rich-text-content
padding: 0 8px
.header
display: flex
justify-content: space-between
Expand All @@ -171,10 +180,6 @@ export default {
line-height: 56px
.bunt-link-button
themed-button-primary()
.schedule
max-width: 960px
.header
padding: 0 8px
.speakers
max-width: calc(124px * 3 + 2px)
.speakers-list
Expand Down Expand Up @@ -237,7 +242,7 @@ export default {
justify-content: center
+below('m')
.content
.content-container
flex-direction: column
align-items: center
padding: 0 8px
Expand Down
30 changes: 15 additions & 15 deletions webapp/src/components/MediaSource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default {
this.initializeIframe(false)
}
},
youtubeTransUrl(youtubeTransUrl) {
youtubeTransUrl (youtubeTransUrl) {
if (!this.room) {
return
}
Expand All @@ -84,14 +84,14 @@ export default {
return
}
this.initializeIframe(false)
this.$root.$on('languageChanged', this.handleLanguageChange);
this.$root.$on('languageChanged', this.handleLanguageChange)
},
beforeDestroy () {
this.iframe?.remove()
if (api.socketState !== 'open') return
// TODO move to store?
if (this.room) api.call('room.leave', {room: this.room.id})
this.$root.$off('languageChanged', this.handleLanguageChange);
this.$root.$off('languageChanged', this.handleLanguageChange)
},
methods: {
async initializeIframe (mute) {
Expand Down Expand Up @@ -160,27 +160,27 @@ export default {
}
return true
},
handleLanguageChange(languageUrl) {
this.languageAudioUrl = languageUrl; // Set the audio source to the selected language URL
const mute = !!languageUrl; // Mute if language URL is present, otherwise unmute
this.destroyIframe();
this.initializeIframe(mute); // Initialize iframe with the appropriate mute state
handleLanguageChange (languageUrl) {
this.languageAudioUrl = languageUrl // Set the audio source to the selected language URL
const mute = !!languageUrl // Mute if language URL is present, otherwise unmute
this.destroyIframe()
this.initializeIframe(mute) // Initialize iframe with the appropriate mute state
// Set the language iframe URL when language changes
this.languageIframeUrl = this.getLanguageIframeUrl(languageUrl);
this.languageIframeUrl = this.getLanguageIframeUrl(languageUrl)
},
getYoutubeUrl(ytid, autoplay, mute) {
getYoutubeUrl (ytid, autoplay, mute) {
// Construct the autoplay parameter based on the input
const autoplayParam = autoplay ? 'autoplay=1&' : '';
const autoplayParam = autoplay ? 'autoplay=1&' : ''
// Construct the mute parameter based on the input
const muteParam = mute ? 'mute=1' : 'mute=0';
const muteParam = mute ? 'mute=1' : 'mute=0'
// Return the complete YouTube URL with the provided video ID, autoplay, and mute parameters
return `https://www.youtube-nocookie.com/embed/${ytid}?${autoplayParam}?enablejsapi=1&modestbranding=1&loop=1&controls=0&disablekb=1&rel=0&showinfo=0&playlist=${ytid}&${muteParam}`;
return `https://www.youtube-nocookie.com/embed/${ytid}?${autoplayParam}?enablejsapi=1&modestbranding=1&loop=1&controls=0&disablekb=1&rel=0&showinfo=0&playlist=${ytid}&${muteParam}`
},
// Added method to get the language iframe URL
getLanguageIframeUrl(languageUrl) {
getLanguageIframeUrl (languageUrl) {
// Checks if the languageUrl is not provided the retun null
if (!languageUrl) return null;

Check failure on line 182 in webapp/src/components/MediaSource.vue

View workflow job for this annotation

GitHub Actions / build

Extra semicolon

Check failure on line 182 in webapp/src/components/MediaSource.vue

View workflow job for this annotation

GitHub Actions / build

Extra semicolon
return `https://www.youtube-nocookie.com/embed/${languageUrl}?enablejsapi=1&autoplay=1&modestbranding=1&loop=1&controls=0&disablekb=1&rel=0&showinfo=0&playlist=${languageUrl}`;
return `https://www.youtube-nocookie.com/embed/${languageUrl}?enablejsapi=1&autoplay=1&modestbranding=1&loop=1&controls=0&disablekb=1&rel=0&showinfo=0&playlist=${languageUrl}`
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion webapp/src/views/admin/rooms/types-edit/page-landing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
upload-url-input(v-model="modules['page.landing'].config.header_background_image", label="Header background image", name="header-background-image")
bunt-input(v-model="modules['page.landing'].config.header_background_color", label="Header background color", name="headerbackgroundcolor")
bunt-select(v-model="modules['page.landing'].config.sponsor_room_id", label="Sponsor Source Room", name="sponsor-room", :options="sponsorRooms", option-label="name")
rich-text-editor(label="Main content", v-model="modules['page.landing'].config.main_content")
</template>
<script>
import UploadUrlInput from 'components/UploadUrlInput'
import RichTextEditor from 'components/RichTextEditor'
import mixin from './mixin'
export default {
components: { UploadUrlInput },
components: { RichTextEditor, UploadUrlInput },
mixins: [mixin],
computed: {
sponsorRooms () {
Expand All @@ -20,4 +22,7 @@ export default {
}
</script>
<style lang="stylus">
.c-page-landing-settings
.editor
margin: 8px
</style>

0 comments on commit 2fa2037

Please sign in to comment.