[Feature] Add empty page for editor.
diff --git a/studio/components/files/index.tsx b/studio/components/files/index.tsx
index c038cd9..034889c 100644
--- a/studio/components/files/index.tsx
+++ b/studio/components/files/index.tsx
@@ -105,7 +105,7 @@
     }
     const onDoubleClick = (ev: MouseEvent) => {
       id = (ev.target as HTMLElement)?.dataset.id
-      if (id) emit('doubleClick', id)
+      if (id) emit('doubleClick', Number(id))
     }
 
     const bindEvents = () => {
diff --git a/studio/components/studio-content/index.module.scss b/studio/components/studio-content/index.module.scss
index a620cdb..76b1c74 100644
--- a/studio/components/studio-content/index.module.scss
+++ b/studio/components/studio-content/index.module.scss
@@ -20,16 +20,5 @@
 }
 
 .editor {
-  display: flex;
-  flex-direction: column;
   height: 100%;
 }
-
-.tab {
-  flex: 1;
-  :global {
-    .n-tabs {
-      height: 100%;
-    }
-  }
-}
diff --git a/studio/components/studio-content/index.tsx b/studio/components/studio-content/index.tsx
index 419e31f..1ad7a90 100644
--- a/studio/components/studio-content/index.tsx
+++ b/studio/components/studio-content/index.tsx
@@ -32,9 +32,7 @@
     return () => (
       <NLayoutContent class={styles['studio-content']}>
         <div class={styles['editor']} ref={editorRef}>
-          <div class={styles['tab']}>
-            <Tabs />
-          </div>
+          <Tabs />
         </div>
       </NLayoutContent>
     )
diff --git a/studio/components/studio-header/index.tsx b/studio/components/studio-header/index.tsx
index 2fcedb9..6c6ce84 100644
--- a/studio/components/studio-header/index.tsx
+++ b/studio/components/studio-header/index.tsx
@@ -29,7 +29,7 @@
   name: 'studio-header',
   setup() {
     const { toggleSider } = useSiderWidth()
-    const { toggleLog, getIsLogFloating } = useLogHeight()
+    const { toggleLog } = useLogHeight()
     const onSelect = (key: string) => {
       if (key === '1') {
         toggleSider()
@@ -56,7 +56,6 @@
               },
               {
                 key: '2',
-                disabled: getIsLogFloating(),
                 label: () =>
                   h('div', {
                     class: styles['label-icon-horizontal']
diff --git a/studio/components/tab/empty.tsx b/studio/components/tab/empty.tsx
new file mode 100644
index 0000000..f0c81a3
--- /dev/null
+++ b/studio/components/tab/empty.tsx
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent } from 'vue'
+import { NEmpty } from 'naive-ui'
+import { useLocale } from '@/hooks'
+import styles from './index.module.scss'
+
+const Empty = defineComponent({
+  name: 'tab-empty',
+  setup() {
+    const { t } = useLocale()
+    return () => (
+      <NEmpty class={styles['empty']} description={t('empty_tab_tips')} />
+    )
+  }
+})
+
+export default Empty
diff --git a/studio/components/tab/index.module.scss b/studio/components/tab/index.module.scss
new file mode 100644
index 0000000..51a3bea
--- /dev/null
+++ b/studio/components/tab/index.module.scss
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.empty {
+  height: 100%;
+  justify-content: center;
+}
diff --git a/studio/components/tab/index.tsx b/studio/components/tab/index.tsx
index e0d664e..3863f84 100644
--- a/studio/components/tab/index.tsx
+++ b/studio/components/tab/index.tsx
@@ -27,6 +27,7 @@
 import { useLocale, useLogHeight } from '@/hooks'
 import Fullscreen from './fullscreen'
 import { useFullscreen } from './use-fullscreen'
+import Empty from './empty'
 
 export const Tabs = defineComponent({
   name: 'tabs',
@@ -34,8 +35,12 @@
     const { t } = useLocale()
     const dialog = useDialog()
     const fileStore = useFileStore()
-    const { setCurrentLogHeight, getEditorHeight, getLogHeight } =
-      useLogHeight()
+    const {
+      setCurrentLogHeight,
+      getEditorHeight,
+      getLogHeight,
+      setFileLogHeight
+    } = useLogHeight()
     const webSocketStore = useWebSocketStore()
     const { isFullscreen, toggleFullscreen } = useFullscreen()
 
@@ -47,6 +52,7 @@
     const onClose = (fileId: number) => {
       fileStore.closeFile(fileId)
       webSocketStore.close(fileId)
+      setFileLogHeight(fileId, 0)
     }
 
     const handleClose = (fileId: number) => {
@@ -93,52 +99,55 @@
       toggleFullscreen('file-editor-' + id)
     }
 
-    return () => (
-      <NTabs
-        value={fileStore.getCurrentFile.id}
-        type='card'
-        closable
-        tabStyle={{ minWidth: '80px', height: '100%' }}
-        size='small'
-        onClose={handleClose}
-        on-update:value={handleChange}
-      >
-        {fileStore.getOpenFiles.map((file) => {
-          const language = utils.getLanguageByName(file.name)
-          return (
-            <NTabPane
-              name={file.id}
-              key={file.name}
-              tab={() => (
-                <div>
-                  {file.name}{' '}
-                  {file.oldContent !== file.content && (
-                    <NBadge dot type='warning' />
-                  )}
-                </div>
-              )}
-            >
-              <Toolbar onFullscreen={() => void handleFullscreen(file.id)} />
-              <Fullscreen
-                id={'file-editor-' + file.id}
-                isFullscreen={isFullscreen.value}
-                onClose={() => void handleFullscreen(file.id)}
+    return () =>
+      !!fileStore.getOpenFiles.length ? (
+        <NTabs
+          value={fileStore.getCurrentFile.id}
+          type='card'
+          closable
+          tabStyle={{ minWidth: '80px', height: '100%' }}
+          size='small'
+          onClose={handleClose}
+          on-update:value={handleChange}
+        >
+          {fileStore.getOpenFiles.map((file) => {
+            const language = utils.getLanguageByName(file.name)
+            return (
+              <NTabPane
+                name={file.id}
+                key={file.name}
+                tab={() => (
+                  <div>
+                    {file.name}{' '}
+                    {file.oldContent !== file.content && (
+                      <NBadge dot type='warning' />
+                    )}
+                  </div>
+                )}
               >
-                <MonacoEditor
-                  v-model:value={file.content}
-                  options={{ language }}
-                  height={
-                    !isFullscreen.value
-                      ? `${getEditorHeight() - getLogHeight() - 40 - 45}px`
-                      : 'calc(100vh - 70px)'
-                  }
-                />
-              </Fullscreen>
-              <Log v-model:value={file.log} />
-            </NTabPane>
-          )
-        })}
-      </NTabs>
-    )
+                <Toolbar onFullscreen={() => void handleFullscreen(file.id)} />
+                <Fullscreen
+                  id={'file-editor-' + file.id}
+                  isFullscreen={isFullscreen.value}
+                  onClose={() => void handleFullscreen(file.id)}
+                >
+                  <MonacoEditor
+                    v-model:value={file.content}
+                    options={{ language }}
+                    height={
+                      !isFullscreen.value
+                        ? `${getEditorHeight() - getLogHeight() - 40 - 45}px`
+                        : 'calc(100vh - 70px)'
+                    }
+                  />
+                </Fullscreen>
+                <Log v-model:value={file.log} />
+              </NTabPane>
+            )
+          })}
+        </NTabs>
+      ) : (
+        <Empty />
+      )
   }
 })
diff --git a/studio/hooks/use-log-height.ts b/studio/hooks/use-log-height.ts
index a94589c..a768a72 100644
--- a/studio/hooks/use-log-height.ts
+++ b/studio/hooks/use-log-height.ts
@@ -14,26 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+import { ref } from 'vue'
 import { useFileStore } from '@/store/file'
 import { useLayoutStore } from '@/store/layout'
 
 export function useLogHeight() {
   const fileStore = useFileStore()
   const layoutStore = useLayoutStore()
+  const isLogFloatingRef = ref(false)
 
   const setLogHeight = (height: number) => {
     layoutStore.setFileLogHeight(fileStore.getCurrentFileId, height)
   }
+  const setFileLogHeight = (id: number, height: number) =>
+    layoutStore.setFileLogHeight(id, height)
   const setCurrentLogHeight = () => {
-    if (layoutStore.getIsLogFloating) return
+    if (isLogFloatingRef.value) return
     layoutStore.setLogHeightByFileId(fileStore.getCurrentFileId)
   }
   const getLogMaxHeight = () => layoutStore.getLogMaxHeight
   const getLogMinHeight = () => layoutStore.getLogMinHeight
   const getLogHeight = () => layoutStore.getLogHeight
   const getEditorHeight = () => layoutStore.getEditorHeight
-  const getIsLogFloating = () => layoutStore.getIsLogFloating
   const setEditorHeight = (height: number) => {
     layoutStore.setEditorHeight(height)
   }
@@ -45,7 +47,7 @@
     setLogHeight(logHeight)
   }
   const toggleLog = () => {
-    if (layoutStore.getIsLogFloating) return
+    if (isLogFloatingRef.value) return
     if (layoutStore.logHeight) {
       layoutStore.setPrevLogHeight(layoutStore.logHeight)
     }
@@ -53,7 +55,7 @@
     setLogHeight(logHeight)
   }
   const toggleFloatingLogHeight = (logFloating: boolean) => {
-    layoutStore.setIsLogFloating(logFloating)
+    isLogFloatingRef.value = logFloating
     if (logFloating) {
       layoutStore.setLogHeight(0)
     } else {
@@ -63,11 +65,12 @@
 
   return {
     setLogHeight,
+    setFileLogHeight,
     getLogHeight,
     getLogMaxHeight,
     getLogMinHeight,
     getEditorHeight,
-    getIsLogFloating,
+    isLogFloatingRef,
     setCurrentLogHeight,
     toggleLogUpAndDown,
     toggleLog,
diff --git a/studio/locales/en_US.ts b/studio/locales/en_US.ts
index 80970ea..5b1144e 100644
--- a/studio/locales/en_US.ts
+++ b/studio/locales/en_US.ts
@@ -33,7 +33,9 @@
   cannel: 'Cannel',
   confirm: 'Confirm',
   run_log: 'Run Log',
-  close: 'Close'
+  close: 'Close',
+  empty_tab_tips:
+    'Please open a file by double clicking on the file name in the file list on the left.'
 }
 
 export type Locale = typeof enUS
diff --git a/studio/locales/zh_CN.ts b/studio/locales/zh_CN.ts
index f4de580..872586a 100644
--- a/studio/locales/zh_CN.ts
+++ b/studio/locales/zh_CN.ts
@@ -33,5 +33,6 @@
   cannel: '取消',
   confirm: '确认',
   run_log: '运行日志',
-  close: '关闭'
+  close: '关闭',
+  empty_tab_tips: '请双击左侧文件列表中的文件名打开一个文件'
 }
diff --git a/studio/pages/log.tsx b/studio/pages/log.tsx
index 4febe79..252f109 100644
--- a/studio/pages/log.tsx
+++ b/studio/pages/log.tsx
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import { defineComponent, onMounted, ref } from 'vue'
+import { defineComponent, onMounted, Ref, ref } from 'vue'
 import { NTabs, NTabPane, NCard, NIcon, NSpace, NButton } from 'naive-ui'
 import { LogComponent } from '@/components/log'
 import { useLocale } from '@/hooks'
@@ -44,7 +44,7 @@
   name: 'log-page',
   setup() {
     const height = window.innerHeight - 85
-    const logValueRef = ref()
+    const logValueRef = ref(window.sessionStorage.getItem('log')) as Ref<string>
     const { t } = useLocale()
 
     const onClose = () => {
@@ -60,10 +60,12 @@
           logValueRef.value = data
         }
       })
-      window.addEventListener('beforeunload', () => {
+      window.addEventListener('beforeunload', (ev) => {
         beginTime = Date.now()
+        window.sessionStorage.setItem('log', logValueRef.value)
       })
-      window.addEventListener('unload', () => {
+      window.addEventListener('unload', (event) => {
+        console.log('event')
         const diffTime = Date.now() - beginTime
         if (diffTime < 10) {
           onClose()
diff --git a/studio/store/layout/index.ts b/studio/store/layout/index.ts
index 814dd6c..e3fd218 100644
--- a/studio/store/layout/index.ts
+++ b/studio/store/layout/index.ts
@@ -26,8 +26,7 @@
     logHeight: 400,
     prevLogHeight: 400,
     editorHeight: 0,
-    filesLogHeight: {},
-    isLogFloating: false
+    filesLogHeight: {}
   }),
   persist: true,
   getters: {
@@ -48,9 +47,6 @@
     },
     getPrevLogHeight(): number {
       return this.prevLogHeight
-    },
-    getIsLogFloating(): boolean {
-      return this.isLogFloating
     }
   },
   actions: {
@@ -80,9 +76,6 @@
     },
     setPrevLogHeight(logHeight: number) {
       this.prevLogHeight = logHeight
-    },
-    setIsLogFloating(logFloating: boolean) {
-      this.isLogFloating = logFloating
     }
   }
 })
diff --git a/studio/store/layout/types.ts b/studio/store/layout/types.ts
index c2f2b03..74c72fa 100644
--- a/studio/store/layout/types.ts
+++ b/studio/store/layout/types.ts
@@ -22,7 +22,6 @@
   prevLogHeight: number
   editorHeight: number
   filesLogHeight: { [key: number]: number }
-  isLogFloating: boolean
 }
 
 export type { ILayoutState }