浏览代码

Implement side-bar pinning

Especially useful to follow Claude conversation and see the desktop at the same time
Alessandro Pignotti 4 月之前
父节点
当前提交
c8cd5daab4
共有 3 个文件被更改,包括 41 次插入5 次删除
  1. 1 0
      postcss.config.js
  2. 23 1
      src/lib/SideBar.svelte
  3. 17 4
      src/lib/WebVM.svelte

+ 1 - 0
postcss.config.js

@@ -27,6 +27,7 @@ export default {
 				case '.fa-brain:before':
 				case '.fa-brain:before':
 				case '.fa-download:before':
 				case '.fa-download:before':
 				case '.fa-keyboard:before':
 				case '.fa-keyboard:before':
+				case '.fa-thumbtack:before':
 				case '.fa-brands:before':
 				case '.fa-brands:before':
 				case '.fa-solid:before':
 				case '.fa-solid:before':
 				case '.fa-regular:before':
 				case '.fa-regular:before':

+ 23 - 1
src/lib/SideBar.svelte

@@ -1,4 +1,5 @@
 <script>
 <script>
+	import { createEventDispatcher } from 'svelte';
 	import Icon from './Icon.svelte';
 	import Icon from './Icon.svelte';
 	import InformationTab from './InformationTab.svelte';
 	import InformationTab from './InformationTab.svelte';
 	import NetworkingTab from './NetworkingTab.svelte';
 	import NetworkingTab from './NetworkingTab.svelte';
@@ -8,6 +9,7 @@
 	import PostsTab from './PostsTab.svelte';
 	import PostsTab from './PostsTab.svelte';
 	import DiscordTab from './DiscordTab.svelte';
 	import DiscordTab from './DiscordTab.svelte';
 	import GitHubTab from './GitHubTab.svelte';
 	import GitHubTab from './GitHubTab.svelte';
+	import SmallButton from './SmallButton.svelte';
 	import { cpuActivity, diskActivity, aiActivity } from './activities.js';
 	import { cpuActivity, diskActivity, aiActivity } from './activities.js';
 	const icons = [
 	const icons = [
 		{ icon: 'fas fa-info-circle', info: 'Information', activity: null },
 		{ icon: 'fas fa-info-circle', info: 'Information', activity: null },
@@ -20,8 +22,10 @@
 		{ icon: 'fab fa-discord', info: 'Discord', activity: null },
 		{ icon: 'fab fa-discord', info: 'Discord', activity: null },
 		{ icon: 'fab fa-github', info: 'GitHub', activity: null },
 		{ icon: 'fab fa-github', info: 'GitHub', activity: null },
 	];
 	];
+	let dispatch = createEventDispatcher();
 	let activeInfo = null; // Tracks currently visible info.
 	let activeInfo = null; // Tracks currently visible info.
 	let hideTimeout = 0; // Timeout for hiding info panel.
 	let hideTimeout = 0; // Timeout for hiding info panel.
+	export let sideBarPinned;
 
 
 	function showInfo(info) {
 	function showInfo(info) {
 		clearTimeout(hideTimeout);
 		clearTimeout(hideTimeout);
@@ -29,6 +33,9 @@
 		activeInfo = info;
 		activeInfo = info;
 	}
 	}
 	function hideInfo() {
 	function hideInfo() {
+		// Never remove the sidebar if pinning is enabled
+		if(sideBarPinned)
+			return;
 		// Prevents multiple timers and hides the info panel after 400ms unless interrupted.
 		// Prevents multiple timers and hides the info panel after 400ms unless interrupted.
 		clearTimeout(hideTimeout);
 		clearTimeout(hideTimeout);
 		hideTimeout = setTimeout(() => {
 		hideTimeout = setTimeout(() => {
@@ -42,6 +49,8 @@
 	}
 	}
 	// Toggles the info panel for the clicked icon.
 	// Toggles the info panel for the clicked icon.
 	function handleClick(icon) {
 	function handleClick(icon) {
+		if(sideBarPinned)
+			return;
 		// Hides the panel if the icon is active. Otherwise, shows the panel with info.
 		// Hides the panel if the icon is active. Otherwise, shows the panel with info.
 		if (activeInfo === icon.info) {
 		if (activeInfo === icon.info) {
 			activeInfo = null;
 			activeInfo = null;
@@ -50,6 +59,11 @@
 		}
 		}
 	}
 	}
 
 
+	function toggleSidebarPin() {
+		sideBarPinned = !sideBarPinned;
+		dispatch('sidebarPinChange', sideBarPinned);
+	}
+
 	export let handleTool;
 	export let handleTool;
 </script>
 </script>
 
 
@@ -70,11 +84,19 @@
 		{/each}
 		{/each}
 	</div>
 	</div>
 	<div
 	<div
-		class="flex flex-col gap-5 shrink-0 w-80 h-full z-10 p-2 bg-neutral-600 text-gray-100 opacity-95"
+		class="relative flex flex-col gap-5 shrink-0 w-80 h-full z-10 p-2 bg-neutral-600 text-gray-100 opacity-95"
 		class:hidden={!activeInfo}
 		class:hidden={!activeInfo}
 		on:mouseenter={handleMouseEnterPanel}
 		on:mouseenter={handleMouseEnterPanel}
 		on:mouseleave={hideInfo}
 		on:mouseleave={hideInfo}
 	>
 	>
+		<div class="absolute right-2 top-2">
+			<SmallButton
+				buttonIcon="fa-solid fa-thumbtack"
+				clickHandler={toggleSidebarPin}
+				buttonTooltip={sideBarPinned ? "Unpin Sidebar" : "Pin Sidebar"}
+				bgColor={sideBarPinned ? "bg-neutral-500" : "bg-neutral-700"}
+			/>
+		</div>
 		{#if activeInfo === 'Information'}
 		{#if activeInfo === 'Information'}
 			<InformationTab>
 			<InformationTab>
 				<slot></slot>
 				<slot></slot>

+ 17 - 4
src/lib/WebVM.svelte

@@ -1,5 +1,5 @@
 <script>
 <script>
-	import { onMount } from 'svelte';
+	import { onMount, tick } from 'svelte';
 	import { get } from 'svelte/store';
 	import { get } from 'svelte/store';
 	import Nav from 'labs/packages/global-navbar/src/Nav.svelte';
 	import Nav from 'labs/packages/global-navbar/src/Nav.svelte';
 	import SideBar from '$lib/SideBar.svelte';
 	import SideBar from '$lib/SideBar.svelte';
@@ -28,6 +28,7 @@
 	var lastScreenshot = null;
 	var lastScreenshot = null;
 	var screenshotCanvas = null;
 	var screenshotCanvas = null;
 	var screenshotCtx = null;
 	var screenshotCtx = null;
+	var sideBarPinned = false;
 	function writeData(buf, vt)
 	function writeData(buf, vt)
 	{
 	{
 		if(vt != 1)
 		if(vt != 1)
@@ -175,6 +176,10 @@
 			return;
 			return;
 		curInnerWidth = window.innerWidth;
 		curInnerWidth = window.innerWidth;
 		curInnerHeight = window.innerHeight;
 		curInnerHeight = window.innerHeight;
+		triggerResize();
+	}
+	function triggerResize()
+	{
 		term.options.fontSize = computeXTermFontSize();
 		term.options.fontSize = computeXTermFontSize();
 		fitAddon.fit();
 		fitAddon.fit();
 		const display = document.getElementById("display");
 		const display = document.getElementById("display");
@@ -615,20 +620,28 @@
 			return new Error("Error: Invalid tool syntax");
 			return new Error("Error: Invalid tool syntax");
 		}
 		}
 	}
 	}
+	async function handleSidebarPinChange(event)
+	{
+		sideBarPinned = event.detail;
+		// Make sure the pinning state of reflected in the layout
+		await tick();
+		// Adjust the layout based on the new sidebar state
+		triggerResize();
+	}
 </script>
 </script>
 
 
 <main class="relative w-full h-full">
 <main class="relative w-full h-full">
 	<Nav />
 	<Nav />
 	<div class="absolute top-10 bottom-0 left-0 right-0">
 	<div class="absolute top-10 bottom-0 left-0 right-0">
-		<SideBar on:connect={handleConnect} on:reset={handleReset} handleTool={handleTool}>
+		<SideBar on:connect={handleConnect} on:reset={handleReset} handleTool={handleTool} on:sidebarPinChange={handleSidebarPinChange}>
 			<slot></slot>
 			<slot></slot>
 		</SideBar>
 		</SideBar>
 		{#if configObj.needsDisplay}
 		{#if configObj.needsDisplay}
-			<div class="absolute top-0 bottom-0 left-14 right-0">
+			<div class="absolute top-0 bottom-0 {sideBarPinned ? 'left-[23.5rem]' : 'left-14'} right-0">
 				<canvas class="w-full h-full cursor-none" id="display"></canvas>
 				<canvas class="w-full h-full cursor-none" id="display"></canvas>
 			</div>
 			</div>
 		{/if}
 		{/if}
-		<div class="absolute top-0 bottom-0 left-14 right-0 p-1 scrollbar" id="console">
+		<div class="absolute top-0 bottom-0 {sideBarPinned ? 'left-[23.5rem]' : 'left-14'} right-0 p-1 scrollbar" id="console">
 		</div>
 		</div>
 	</div>
 	</div>
 </main>
 </main>