Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/improsocial/impro
An extensible Bluesky client for web impro.social
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242import { html, render } from "/js/lib/lit-html.js";import { effect } from "/js/signals.js";import { linkToLogin } from "/js/navigation.js";import { sidebarTemplate } from "/js/templates/sidebar.template.js";import { footerTemplate } from "/js/templates/footer.template.js";import { PLUGIN_PREVIEW_QUERY_PARAM } from "/js/plugins/pluginService.js";import { Layout } from "/js/router.js";import "/js/components/animated-sidebar.js";import "/js/components/trending-pane.js";import "/js/components/sidebar-search.js";import "/js/components/pinned-feeds-pane.js";import "/js/components/app-icon.js";
function exitPluginPreview() { const url = new URL(window.location.href); url.searchParams.delete(PLUGIN_PREVIEW_QUERY_PARAM); window.location.assign(url.toString());}
function pluginPreviewBannerTemplate({ plugins }) { if (plugins.length === 0) return null; const links = []; plugins.forEach((plugin, index) => { if (index > 0) links.push(", "); links.push( html`<a class="plugin-preview-banner-link" href="/plugins/community/${encodeURIComponent(plugin.id)}" >${plugin.name}</a >`, ); }); return html` <div class="plugin-preview-banner" data-testid="plugin-preview-banner"> <div class="plugin-preview-banner-icon"> <app-icon icon="eye-line"></app-icon> </div> <div class="plugin-preview-banner-body"> <div class="plugin-preview-banner-title">Preview mode</div> <div class="plugin-preview-banner-subtitle"> You are currently previewing community ${links.length === 1 ? "plugin" : "plugins"}: ${links}. <a class="plugin-preview-banner-link" href=${linkToLogin()} >Sign in</a > to install. </div> </div> <!-- <button class="plugin-preview-banner-exit" data-testid="plugin-preview-banner-exit" @click=${exitPluginPreview} > Exit preview </button> --> </div> `;}
export function mainLayoutTemplate({ isAuthenticated = true, currentUser, activeNavItem, isNavItemPage = false, numNotifications = 0, numChatNotifications = 0, onClickActiveNavItem, children, onClickComposeButton, pluginService, previewingPlugins = [], onLongPressProfile = null, groupChatLinkService, liveStatusService, dataLayer,}) { return html` <div class="main-layout-wrapper" @chat-join-link:click=${(e) => groupChatLinkService.handleAction( e.detail.actionType, e.detail.preview, )} @live-avatar:click=${(e) => liveStatusService.handleAvatarClick(e.detail.did)} > <div class="view-columns"> <div class="view-column-left"> ${sidebarTemplate({ isAuthenticated, currentUser, activeNavItem, isNavItemPage, numNotifications, numChatNotifications, onClickActiveItem: onClickActiveNavItem, onClickComposeButton, pluginSidebarItems: pluginService.getSidebarItems(), onLongPressProfile, })} </div> <div class="view-column-center" data-testid="view-column-center"> ${children} </div> <div class="view-column-right"> ${activeNavItem === "search" ? html`<div class="sidebar-search-placeholder"></div>` : html`<sidebar-search .dataLayer=${dataLayer} .isAuthenticated=${isAuthenticated} ></sidebar-search>`} ${isAuthenticated ? html`<pinned-feeds-pane .dataLayer=${dataLayer} ?show-selected=${activeNavItem === "home"} ?more-feeds-active=${activeNavItem === "feeds"} ></pinned-feeds-pane>` : ""} <trending-pane .dataLayer=${dataLayer}></trending-pane> </div> </div> ${pluginPreviewBannerTemplate({ plugins: previewingPlugins })} ${footerTemplate({ isAuthenticated, currentUser, activeNavItem, isNavItemPage, numNotifications, numChatNotifications, onClickActiveItem: onClickActiveNavItem, onLongPressProfile, })} </div> `;}
export class MainLayout extends Layout { #container = null; #disposeEffect = null;
constructor(context, router) { super(); this.context = context; this.router = router; const pagesEl = document.createElement("div"); pagesEl.id = "pages"; this.slot = pagesEl; }
mount(container) { if (this.#container) { throw new Error("MainLayout is already mounted"); } const { isAuthenticated, dataLayer, notificationService, chatNotificationService, postComposerService, accountSwitcherService, pluginService, groupChatLinkService, liveStatusService, profileHoverCardService, auth, } = this.context; const { router, slot } = this;
container.id = "main-layout"; this.#container = container;
profileHoverCardService?.install(container);
const onLongPressProfile = accountSwitcherService && auth.supportsMultipleAccounts() ? () => accountSwitcherService.openAccountSwitcherDialog() : null;
// The active page may claim the click by cancelling the event const onClickActiveNavItem = () => { const event = new CustomEvent("active-nav-click", { cancelable: true }); this.dispatchEvent(event); if (!event.defaultPrevented) { window.scrollTo({ top: -1, behavior: "smooth" }); } };
this.#disposeEffect = effect(() => { const currentRoute = router.$currentRoute.get(); const layoutOptions = currentRoute?.options?.layoutOptions ?? {}; const currentUser = dataLayer.derived.$currentUser.get(); const activeNavItem = typeof layoutOptions.activeNavItem === "function" ? layoutOptions.activeNavItem(currentRoute.params) : (layoutOptions.activeNavItem ?? null); // True when this route is the nav item's own page, rather than somewhere // deeper in its section const isNavItemPage = typeof layoutOptions.isNavItemPage === "function" ? layoutOptions.isNavItemPage(currentRoute.params) : (layoutOptions.isNavItemPage ?? false); const previewingPlugins = pluginService.getPreviewPlugins(); render( mainLayoutTemplate({ isAuthenticated, currentUser, activeNavItem, isNavItemPage, numNotifications: notificationService?.$numNotifications.get() ?? null, numChatNotifications: chatNotificationService?.$numNotifications.get() ?? null, onClickActiveNavItem, children: slot, onClickComposeButton: () => postComposerService.composePost({ currentUser }), pluginService, previewingPlugins, onLongPressProfile, groupChatLinkService, liveStatusService, dataLayer, }), container, ); }); }
openSidebar() { this.#container?.querySelector("animated-sidebar")?.open(); }
dispose() { this.context.profileHoverCardService?.dispose(); this.#disposeEffect?.(); this.#disposeEffect = null; this.#container?.replaceChildren(); this.#container = null; }}