diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/SidePanelNotebook.tsx b/frontend/src/layout/navigation-3000/sidepanel/panels/SidePanelNotebook.tsx
index 4e7ad8e0833da..f3a0b11c7bbc0 100644
--- a/frontend/src/layout/navigation-3000/sidepanel/panels/SidePanelNotebook.tsx
+++ b/frontend/src/layout/navigation-3000/sidepanel/panels/SidePanelNotebook.tsx
@@ -1,32 +1,8 @@
-import { useActions, useValues } from 'kea'
-import { NotebookPopoverCard } from 'scenes/notebooks/Notebook/NotebookPopover'
-import { notebookPopoverLogic } from 'scenes/notebooks/Notebook/notebookPopoverLogic'
-import { sidePanelLogic } from '../sidePanelLogic'
-import { useEffect } from 'react'
+import { NotebookPanel } from 'scenes/notebooks/NotebookPanel/NotebookPanel'
export const SidePanelNotebook = (): JSX.Element => {
- const { closeSidePanel } = useActions(sidePanelLogic)
- const { selectedTab } = useValues(sidePanelLogic)
+ // const { closeSidePanel } = useActions(sidePanelLogic)
+ // const { selectedTab } = useValues(sidePanelLogic)
- const { visibility } = useValues(notebookPopoverLogic)
- const { setVisibility } = useActions(notebookPopoverLogic)
-
- // useEffect(() => {
- // // When something sets the popover to hidden - close the side panel
- // return () => {
- // if (selectedTab === 'notebook') {
- // closeSidePanel()
- // }
- // }
- // }, [visibility === 'hidden'])
-
- useEffect(() => {
- setVisibility('visible')
- // On unmount - hide the popover
- return () => {
- setVisibility('hidden')
- }
- }, [])
-
- return
+ return
}
diff --git a/frontend/src/layout/navigation/SideBar/SideBar.tsx b/frontend/src/layout/navigation/SideBar/SideBar.tsx
index e7cd5d9c3846d..4c7be14ee0798 100644
--- a/frontend/src/layout/navigation/SideBar/SideBar.tsx
+++ b/frontend/src/layout/navigation/SideBar/SideBar.tsx
@@ -50,7 +50,7 @@ import { Tooltip } from 'lib/lemon-ui/Tooltip'
import { Spinner } from 'lib/lemon-ui/Spinner/Spinner'
import { DebugNotice } from 'lib/components/DebugNotice'
import ActivationSidebar from 'lib/components/ActivationSidebar/ActivationSidebar'
-import { NotebookPopover } from 'scenes/notebooks/Notebook/NotebookPopover'
+import { NotebookPopover } from 'scenes/notebooks/NotebookPanel/NotebookPopover'
import { FlaggedFeature } from 'lib/components/FlaggedFeature'
import { IconNotebook } from 'scenes/notebooks/IconNotebook'
diff --git a/frontend/src/layout/navigation/TopBar/NotebookButton.tsx b/frontend/src/layout/navigation/TopBar/NotebookButton.tsx
index 278644197c756..a2125be240ec8 100644
--- a/frontend/src/layout/navigation/TopBar/NotebookButton.tsx
+++ b/frontend/src/layout/navigation/TopBar/NotebookButton.tsx
@@ -1,5 +1,5 @@
import { useActions, useValues } from 'kea'
-import { notebookPopoverLogic } from 'scenes/notebooks/Notebook/notebookPopoverLogic'
+import { notebookPopoverLogic } from 'scenes/notebooks/NotebookPanel/notebookPopoverLogic'
import { LemonButton, LemonButtonWithSideActionProps } from '@posthog/lemon-ui'
import { useFeatureFlag } from 'lib/hooks/useFeatureFlag'
import { IconNotebook } from 'scenes/notebooks/IconNotebook'
diff --git a/frontend/src/models/notebooksModel.ts b/frontend/src/models/notebooksModel.ts
index 249b6055b6847..7f86b042dbee2 100644
--- a/frontend/src/models/notebooksModel.ts
+++ b/frontend/src/models/notebooksModel.ts
@@ -8,7 +8,7 @@ import posthog from 'posthog-js'
import { LOCAL_NOTEBOOK_TEMPLATES } from 'scenes/notebooks/NotebookTemplates/notebookTemplates'
import { deleteWithUndo } from 'lib/utils'
import { teamLogic } from 'scenes/teamLogic'
-import { notebookPopoverLogic } from 'scenes/notebooks/Notebook/notebookPopoverLogic'
+import { notebookPopoverLogic } from 'scenes/notebooks/NotebookPanel/notebookPopoverLogic'
import { defaultNotebookContent, EditorFocusPosition, JSONContent } from 'scenes/notebooks/Notebook/utils'
import type { notebooksModelType } from './notebooksModelType'
diff --git a/frontend/src/scenes/notebooks/AddToNotebook/DraggableToNotebook.tsx b/frontend/src/scenes/notebooks/AddToNotebook/DraggableToNotebook.tsx
index b4b6f619320df..c2e43371f8bde 100644
--- a/frontend/src/scenes/notebooks/AddToNotebook/DraggableToNotebook.tsx
+++ b/frontend/src/scenes/notebooks/AddToNotebook/DraggableToNotebook.tsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react'
import { NotebookNodeType } from '~/types'
import './DraggableToNotebook.scss'
import { useActions, useValues } from 'kea'
-import { notebookPopoverLogic } from '../Notebook/notebookPopoverLogic'
+import { notebookPopoverLogic } from '../NotebookPanel/notebookPopoverLogic'
import clsx from 'clsx'
import { FlaggedFeature } from 'lib/components/FlaggedFeature'
import { FEATURE_FLAGS } from 'lib/constants'
diff --git a/frontend/src/scenes/notebooks/NotebookPanel/NotebookPanel.scss b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPanel.scss
new file mode 100644
index 0000000000000..826edb17825e1
--- /dev/null
+++ b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPanel.scss
@@ -0,0 +1,67 @@
+@import '../../../styles/mixins';
+
+.NotebookPanel {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ border-radius: var(--radius);
+ background-color: var(--bg-3000);
+ border: 1px solid var(--border-3000);
+ box-shadow: 0px 16px 16px rgba(0, 0, 0, 0);
+ transition: box-shadow 150ms linear;
+ overflow: hidden;
+}
+
+.NotebookPanelDropzone {
+ box-shadow: 0px 16px 16px rgba(0, 0, 0, 0.15);
+ border: 2px dashed var(--border-3000);
+ border-radius: var(--radius);
+
+ transition: all 150ms;
+ height: 4rem;
+ margin-bottom: 1rem;
+ backdrop-filter: blur(5px);
+ display: flex;
+
+ .NotebookPanelDropzone__message {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ font-weight: 700;
+ font-size: 1rem;
+ color: var(--muted-alt);
+ text-align: center;
+ pointer-events: none;
+ background-color: var(--bg-light);
+ padding: 1rem;
+ opacity: 0.75;
+ transition: all 150ms;
+ }
+
+ .NotebookPanelDropzone__dropped {
+ overflow: hidden;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ &--active {
+ border-color: var(--primary);
+ height: 8rem;
+
+ .NotebookPanelDropzone__message {
+ opacity: 1;
+ }
+ }
+
+ &--dropped {
+ padding: 1rem;
+ border-color: var(--primary);
+ background-color: var(--bg-light);
+ height: 100%;
+ justify-content: flex-start;
+ align-items: initial;
+ }
+}
diff --git a/frontend/src/scenes/notebooks/NotebookPanel/NotebookPanel.tsx b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPanel.tsx
new file mode 100644
index 0000000000000..7337ad67943f9
--- /dev/null
+++ b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPanel.tsx
@@ -0,0 +1,83 @@
+import { useActions, useValues } from 'kea'
+import './NotebookPanel.scss'
+import { Notebook } from '../Notebook/Notebook'
+import { LemonButton } from '@posthog/lemon-ui'
+import { IconFullScreen, IconShare } from 'lib/lemon-ui/icons'
+import { useMemo } from 'react'
+import { NotebookListMini } from '../Notebook/NotebookListMini'
+import { notebooksModel } from '~/models/notebooksModel'
+import { NotebookExpandButton, NotebookSyncInfo } from '../Notebook/NotebookMeta'
+import { notebookLogic } from '../Notebook/notebookLogic'
+import { useResizeBreakpoints } from 'lib/hooks/useResizeObserver'
+import { openNotebookShareDialog } from '../Notebook/NotebookShare'
+import { notebookPanelLogic } from './notebookPanelLogic'
+
+export function NotebookPanel(): JSX.Element | null {
+ const { fullScreen, selectedNotebook, initialAutofocus, droppedResource, dropProperties } =
+ useValues(notebookPanelLogic)
+ const { setFullScreen, selectNotebook } = useActions(notebookPanelLogic)
+ const { createNotebook } = useActions(notebooksModel)
+ const { notebook } = useValues(notebookLogic({ shortId: selectedNotebook }))
+ // const { activeScene } = useValues(sceneLogic)
+
+ // const showEditor = activeScene === Scene.Notebook ? visibility !== 'hidden' : shownAtLeastOnce
+ const editable = !notebook?.is_template
+
+ const { ref, size } = useResizeBreakpoints({
+ 0: 'small',
+ 832: 'medium',
+ })
+
+ const contentWidthHasEffect = useMemo(() => fullScreen && size === 'medium', [fullScreen, size])
+
+ if (droppedResource) {
+ return null
+ }
+
+ return (
+
+
+
+ selectNotebook(notebook.short_id)}
+ onNewNotebook={() => createNotebook()}
+ />
+
+
+ {selectedNotebook && }
+
+ openNotebookShareDialog({ shortId: selectedNotebook })}
+ status="primary-alt"
+ icon={}
+ tooltip="Share notebook"
+ tooltipPlacement="left"
+ />
+
+ {contentWidthHasEffect && }
+
+ setFullScreen(!fullScreen)}
+ status="primary-alt"
+ active={fullScreen}
+ icon={}
+ tooltip="Toggle full screen"
+ tooltipPlacement="left"
+ />
+
+
+
+
+
+
+
+ )
+}
diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookPopover.scss b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPopover.scss
similarity index 100%
rename from frontend/src/scenes/notebooks/Notebook/NotebookPopover.scss
rename to frontend/src/scenes/notebooks/NotebookPanel/NotebookPopover.scss
diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookPopover.tsx b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPopover.tsx
similarity index 93%
rename from frontend/src/scenes/notebooks/Notebook/NotebookPopover.tsx
rename to frontend/src/scenes/notebooks/NotebookPanel/NotebookPopover.tsx
index f820f876cce36..5cc828d4e7535 100644
--- a/frontend/src/scenes/notebooks/Notebook/NotebookPopover.tsx
+++ b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPopover.tsx
@@ -1,20 +1,20 @@
import { useActions, useValues } from 'kea'
import clsx from 'clsx'
import './NotebookPopover.scss'
-import { Notebook } from './Notebook'
-import { notebookPopoverLogic } from 'scenes/notebooks/Notebook/notebookPopoverLogic'
+import { Notebook } from '../Notebook/Notebook'
+import { notebookPopoverLogic } from 'scenes/notebooks/NotebookPanel/notebookPopoverLogic'
import { LemonButton } from '@posthog/lemon-ui'
import { IconFullScreen, IconChevronRight, IconOpenInNew, IconShare } from 'lib/lemon-ui/icons'
import { useEffect, useMemo, useRef } from 'react'
import { useKeyboardHotkeys } from 'lib/hooks/useKeyboardHotkeys'
-import { NotebookListMini } from './NotebookListMini'
+import { NotebookListMini } from '../Notebook/NotebookListMini'
import { notebooksModel } from '~/models/notebooksModel'
-import { NotebookExpandButton, NotebookSyncInfo } from './NotebookMeta'
-import { notebookLogic } from './notebookLogic'
+import { NotebookExpandButton, NotebookSyncInfo } from '../Notebook/NotebookMeta'
+import { notebookLogic } from '../Notebook/notebookLogic'
import { urls } from 'scenes/urls'
import { NotebookPopoverDropzone } from './NotebookPopoverDropzone'
import { useResizeBreakpoints } from 'lib/hooks/useResizeObserver'
-import { openNotebookShareDialog } from './NotebookShare'
+import { openNotebookShareDialog } from '../Notebook/NotebookShare'
import { sceneLogic } from 'scenes/sceneLogic'
import { Scene } from 'scenes/sceneTypes'
diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookPopoverDropzone.tsx b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPopoverDropzone.tsx
similarity index 97%
rename from frontend/src/scenes/notebooks/Notebook/NotebookPopoverDropzone.tsx
rename to frontend/src/scenes/notebooks/NotebookPanel/NotebookPopoverDropzone.tsx
index 12adec1008664..e89f4f7d421c7 100644
--- a/frontend/src/scenes/notebooks/Notebook/NotebookPopoverDropzone.tsx
+++ b/frontend/src/scenes/notebooks/NotebookPanel/NotebookPopoverDropzone.tsx
@@ -4,7 +4,7 @@ import { notebookPopoverLogic } from './notebookPopoverLogic'
import { useActions, useValues } from 'kea'
import { NotebookNodeType } from '~/types'
import { NotebookSelectList } from '../NotebookSelectButton/NotebookSelectButton'
-import { notebookLogicType } from './notebookLogicType'
+import { notebookLogicType } from '../Notebook/notebookLogicType'
import { LemonButton } from '@posthog/lemon-ui'
export function NotebookPopoverDropzone(): JSX.Element | null {
diff --git a/frontend/src/scenes/notebooks/NotebookPanel/notebookPanelLogic.ts b/frontend/src/scenes/notebooks/NotebookPanel/notebookPanelLogic.ts
new file mode 100644
index 0000000000000..3045127b1d88b
--- /dev/null
+++ b/frontend/src/scenes/notebooks/NotebookPanel/notebookPanelLogic.ts
@@ -0,0 +1,139 @@
+import { actions, kea, reducers, path, listeners, selectors, connect } from 'kea'
+
+import { HTMLProps, RefObject } from 'react'
+import { EditorFocusPosition } from '../Notebook/utils'
+
+import type { notebookPanelLogicType } from './notebookPanelLogicType'
+import { NotebookNodeResource } from '~/types'
+import { SidePanelTab, sidePanelLogic } from '~/layout/navigation-3000/sidepanel/sidePanelLogic'
+
+export const MIN_NOTEBOOK_SIDEBAR_WIDTH = 600
+
+export const notebookPanelLogic = kea([
+ path(['scenes', 'notebooks', 'Notebook', 'notebookPanelLogic']),
+ connect({
+ values: [sidePanelLogic, ['sidePanelOpen']],
+ actions: [sidePanelLogic, ['openSidePanel']],
+ }),
+ actions({
+ setFullScreen: (full: boolean) => ({ full }),
+ selectNotebook: (id: string, autofocus: EditorFocusPosition | undefined = undefined) => ({ id, autofocus }),
+ startDropMode: true,
+ endDropMode: true,
+ setDropDistance: (distance: number) => ({ distance }),
+ setDroppedResource: (resource: NotebookNodeResource | string | null) => ({ resource }),
+ }),
+
+ reducers(() => ({
+ selectedNotebook: [
+ 'scratchpad',
+ { persist: true },
+ {
+ selectNotebook: (_, { id }) => id,
+ },
+ ],
+ fullScreen: [
+ false,
+ {
+ setFullScreen: (_, { full }) => full,
+ setVisibility: (state, { visibility }) => (visibility === 'hidden' ? false : state),
+ },
+ ],
+ initialAutofocus: [
+ 'start' as EditorFocusPosition,
+ {
+ selectNotebook: (_, { autofocus }) => autofocus ?? 'start',
+ },
+ ],
+ elementRef: [
+ null as RefObject | null,
+ {
+ setElementRef: (_, { element }) => element,
+ },
+ ],
+ shownAtLeastOnce: [
+ false,
+ {
+ setVisibility: (state, { visibility }) => visibility !== 'hidden' || state,
+ },
+ ],
+ dropMode: [
+ false,
+ {
+ startDropMode: () => true,
+ endDropMode: () => false,
+ },
+ ],
+ dropDistance: [
+ 0,
+ {
+ startDropMode: () => -1,
+ endDropMode: () => -1,
+ setDropDistance: (_, { distance }) => distance,
+ },
+ ],
+ droppedResource: [
+ null as NotebookNodeResource | string | null,
+ {
+ setVisibility: (state, { visibility }) => (visibility === 'hidden' ? null : state),
+ setDroppedResource: (_, { resource }) => resource,
+ },
+ ],
+ })),
+
+ selectors(({ cache, actions }) => ({
+ dropProperties: [
+ (s) => [s.dropMode, s.dropDistance, s.sidePanelOpen],
+ (
+ dropMode,
+ dropDistance,
+ sidePanelOpen
+ ): Pick, 'onDragEnter' | 'onDragLeave' | 'style'> => {
+ return dropMode
+ ? {
+ onDragEnter: () => {
+ cache.dragEntercount = (cache.dragEntercount || 0) + 1
+ if (cache.dragEntercount === 1) {
+ actions.openSidePanel(SidePanelTab.Notebooks)
+ }
+ },
+
+ onDragLeave: () => {
+ cache.dragEntercount = (cache.dragEntercount || 0) - 1
+
+ if (cache.dragEntercount <= 0) {
+ cache.dragEntercount = 0
+ actions.openSidePanel(SidePanelTab.Notebooks)
+ }
+ },
+ }
+ : {}
+ },
+ ],
+ })),
+
+ listeners(({ cache, actions }) => ({
+ startDropMode: () => {
+ cache.dragEntercount = 0
+ cache.dragStart = null
+ actions.openSidePanel(SidePanelTab.Notebooks)
+
+ cache.dragListener = (event: MouseEvent) => {
+ if (!cache.dragStart) {
+ cache.dragStart = event.pageX
+ }
+
+ // The drop distance is the percentage between where the drag started and where it now is
+ const dropDistance = (event.pageX - cache.dragStart) / window.innerWidth
+ actions.setDropDistance(dropDistance)
+ }
+ window.addEventListener('drag', cache.dragListener)
+ },
+ endDropMode: () => {
+ // if (values.visibility === 'peek') {
+ // actions.setVisibility('hidden')
+ // }
+ window.removeEventListener('drag', cache.dragListener)
+ },
+ })),
+])
diff --git a/frontend/src/scenes/notebooks/Notebook/notebookPopoverLogic.ts b/frontend/src/scenes/notebooks/NotebookPanel/notebookPopoverLogic.ts
similarity index 99%
rename from frontend/src/scenes/notebooks/Notebook/notebookPopoverLogic.ts
rename to frontend/src/scenes/notebooks/NotebookPanel/notebookPopoverLogic.ts
index 1a0f4865b5092..916697879891f 100644
--- a/frontend/src/scenes/notebooks/Notebook/notebookPopoverLogic.ts
+++ b/frontend/src/scenes/notebooks/NotebookPanel/notebookPopoverLogic.ts
@@ -4,7 +4,7 @@ import { urlToAction } from 'kea-router'
import { HTMLProps, RefObject } from 'react'
import posthog from 'posthog-js'
import { subscriptions } from 'kea-subscriptions'
-import { EditorFocusPosition } from './utils'
+import { EditorFocusPosition } from '../Notebook/utils'
import type { notebookPopoverLogicType } from './notebookPopoverLogicType'
import { NotebookNodeResource, NotebookPopoverVisibility } from '~/types'
diff --git a/frontend/src/scenes/notebooks/NotebookScene.tsx b/frontend/src/scenes/notebooks/NotebookScene.tsx
index 805a1186f9039..49d088f4375ac 100644
--- a/frontend/src/scenes/notebooks/NotebookScene.tsx
+++ b/frontend/src/scenes/notebooks/NotebookScene.tsx
@@ -5,7 +5,7 @@ import { Notebook } from './Notebook/Notebook'
import { NotFound } from 'lib/components/NotFound'
import { NotebookSceneLogicProps, notebookSceneLogic } from './notebookSceneLogic'
import { LemonButton, LemonTag } from '@posthog/lemon-ui'
-import { notebookPopoverLogic } from './Notebook/notebookPopoverLogic'
+import { notebookPopoverLogic } from './NotebookPanel/notebookPopoverLogic'
import { NotebookExpandButton, NotebookSyncInfo } from './Notebook/NotebookMeta'
import { UserActivityIndicator } from 'lib/components/UserActivityIndicator/UserActivityIndicator'
import {
diff --git a/frontend/src/scenes/notebooks/NotebooksTable/NotebooksTable.tsx b/frontend/src/scenes/notebooks/NotebooksTable/NotebooksTable.tsx
index 6f57e08427f01..fd94c94bd1535 100644
--- a/frontend/src/scenes/notebooks/NotebooksTable/NotebooksTable.tsx
+++ b/frontend/src/scenes/notebooks/NotebooksTable/NotebooksTable.tsx
@@ -10,7 +10,7 @@ import { useEffect } from 'react'
import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
import { LemonMenu } from 'lib/lemon-ui/LemonMenu'
import { IconDelete, IconEllipsis } from 'lib/lemon-ui/icons'
-import { notebookPopoverLogic } from '../Notebook/notebookPopoverLogic'
+import { notebookPopoverLogic } from '../NotebookPanel/notebookPopoverLogic'
import { membersLogic } from 'scenes/organization/Settings/membersLogic'
import { ContainsTypeFilters } from 'scenes/notebooks/NotebooksTable/ContainsTypeFilter'
import { DEFAULT_FILTERS, notebooksTableLogic } from 'scenes/notebooks/NotebooksTable/notebooksTableLogic'