From 63a14f7d06cb05c862f9fefdc221d1b6fe18e999 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 10 Jun 2026 15:34:10 +0530 Subject: [PATCH] feat: add wide article viewer --- app/javascript/sdk/IFrameHelper.js | 6 ++++++ app/javascript/sdk/bubbleHelpers.js | 10 ++++++++++ app/javascript/sdk/sdk.js | 12 ++++++++++-- app/javascript/widget/App.vue | 13 +++++++++++++ app/views/layouts/_portal_scripts.html.erb | 13 +++++++++++++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/app/javascript/sdk/IFrameHelper.js b/app/javascript/sdk/IFrameHelper.js index 3ab1ba1f5..ffe2e75b4 100644 --- a/app/javascript/sdk/IFrameHelper.js +++ b/app/javascript/sdk/IFrameHelper.js @@ -19,6 +19,8 @@ import { setBubbleText, addUnreadClass, removeUnreadClass, + addArticleViewClass, + removeArticleViewClass, } from './bubbleHelpers'; import { isWidgetColorLighter } from 'shared/helpers/colorHelper'; import { dispatchWindowEvent } from 'shared/helpers/CustomEventHelper'; @@ -268,6 +270,10 @@ export const IFrameHelper = { }, resetUnreadMode: () => removeUnreadClass(), + + expandWidget: () => addArticleViewClass(), + collapseWidget: () => removeArticleViewClass(), + handleNotificationDot: event => { if (window.$chatwoot.hideMessageBubble) { return; diff --git a/app/javascript/sdk/bubbleHelpers.js b/app/javascript/sdk/bubbleHelpers.js index c53323e27..e46dbee5a 100644 --- a/app/javascript/sdk/bubbleHelpers.js +++ b/app/javascript/sdk/bubbleHelpers.js @@ -110,3 +110,13 @@ export const removeUnreadClass = () => { const holderEl = document.querySelector('.woot-widget-holder'); removeClasses(holderEl, 'has-unread-view'); }; + +export const addArticleViewClass = () => { + const holderEl = document.querySelector('.woot-widget-holder'); + addClasses(holderEl, 'has-article-view'); +}; + +export const removeArticleViewClass = () => { + const holderEl = document.querySelector('.woot-widget-holder'); + removeClasses(holderEl, 'has-article-view'); +}; diff --git a/app/javascript/sdk/sdk.js b/app/javascript/sdk/sdk.js index 095fe80ca..44473c8c8 100644 --- a/app/javascript/sdk/sdk.js +++ b/app/javascript/sdk/sdk.js @@ -7,11 +7,13 @@ export const SDK_CSS = ` .woot-widget-holder { box-shadow: 0 5px 40px rgba(0, 0, 0, .16); opacity: 1; - will-change: transform, opacity; + will-change: transform, opacity, width, height; transform: translateY(0); overflow: hidden !important; position: fixed !important; - transition: opacity 0.2s linear, transform 0.25s linear; + transition: opacity 0.2s linear, transform 0.25s linear, + width 0.3s cubic-bezier(0.4, 0, 0.2, 1), + height 0.3s cubic-bezier(0.4, 0, 0.2, 1); z-index: 2147483000 !important; } @@ -287,6 +289,12 @@ export const SDK_CSS = ` min-height: 250px !important; width: 400px !important; } + + .woot-widget-holder.has-article-view { + width: min(640px, max(0px, -20px + 100dvw)) !important; + height: calc(100% - 125px) !important; + max-height: none !important; + } } .woot-hidden { diff --git a/app/javascript/widget/App.vue b/app/javascript/widget/App.vue index 0d456fa83..c5ed2f9cc 100755 --- a/app/javascript/widget/App.vue +++ b/app/javascript/widget/App.vue @@ -81,6 +81,15 @@ export default { document.documentElement.dir = value ? 'rtl' : 'ltr'; }, }, + '$route.name'(routeName, previousRouteName) { + // Expansion is driven by the rendered portal page (see the + // 'portalPageLoaded' handler) so the widget only widens for article pages. + // Here we just collapse when leaving the article view, since the iframe is + // torn down then and can no longer signal. + if (this.isIFrame && previousRouteName === 'article-viewer') { + IFrameHelper.sendMessage({ event: 'collapseWidget' }); + } + }, }, mounted() { const { websiteToken, locale, widgetColor } = window.chatwootWebChannel; @@ -342,6 +351,10 @@ export default { this.setColorScheme(message.darkMode); } else if (message.event === 'open-article') { this.openArticle(message.slug); + } else if (message.event === 'portalPageLoaded') { + IFrameHelper.sendMessage({ + event: message.isArticle ? 'expandWidget' : 'collapseWidget', + }); } else if (message.event === 'toggle-open') { this.$store.dispatch('appConfig/toggleWidgetOpen', message.isOpen); diff --git a/app/views/layouts/_portal_scripts.html.erb b/app/views/layouts/_portal_scripts.html.erb index b1479cace..ef04f5ec7 100644 --- a/app/views/layouts/_portal_scripts.html.erb +++ b/app/views/layouts/_portal_scripts.html.erb @@ -88,6 +88,19 @@ html.light { tocHeader: '<%= I18n.t('public_portal.toc_header') %>' }; +<% if @is_plain_layout_enabled %> + +<% end %> <% if @portal.channel_web_widget.present? && !@is_plain_layout_enabled %>