From 53e78160100a5b95e1e31f27920bbc213f540977 Mon Sep 17 00:00:00 2001 From: Felix Kling Date: Thu, 6 Jul 2023 20:06:51 +0200 Subject: [PATCH] sveltekit-prototype: Add separator component and setup storybook (#54674) This commit adds a simple separator component to be used for resizing panels (e.g. sidebars) and is used on file tree pages. The way the separator works is quite simple atm: It computes its position in relation to the size of the parent element and saves that value in the provided store. The parent component can use this value however it sees fit. The current value is persisted in local storage. I assume that this functionality will be expanded or changed in the future but it's a start. I also setup storybook 7, following the default setup instructions. I left everybody as default except for deleting the example stories it came with. We can always change the structure later. Initially I wasn't able to run `pnpm run storybook`, it was throwing an error about not being able to import `ts-dedent`. Adding it to the root `package.json` file seems to resolve this issue. Repo page: https://github.com/sourcegraph/sourcegraph/assets/179026/fb6ba082-8959-47ed-b2ae-8e1aa351b64c Storybook: ![2023-07-06_14-34](https://github.com/sourcegraph/sourcegraph/assets/179026/558fdbfc-cbc6-45c3-973b-92d1931f1395) ## Test plan Open repo page and use separator. Run storybooks with `pnpm run storybooks` Run existing storybooks in the workspace roots. It's not impacted by adding a new version. --- client/web-sveltekit/.eslintrc.cjs | 10 +- client/web-sveltekit/.storybook/main.js | 13 + client/web-sveltekit/.storybook/preview.js | 14 + client/web-sveltekit/package.json | 99 +- client/web-sveltekit/src/lib/Separator.svelte | 102 + client/web-sveltekit/src/lib/stores.ts | 29 +- .../routes/[...repo]/(code)/+layout.svelte | 9 +- .../src/stories/Separator.stories.ts | 18 + .../src/stories/SeparatorExample.svelte | 38 + package.json | 1 + pnpm-lock.yaml | 1912 ++++++++++++++++- 11 files changed, 2091 insertions(+), 154 deletions(-) create mode 100644 client/web-sveltekit/.storybook/main.js create mode 100644 client/web-sveltekit/.storybook/preview.js create mode 100644 client/web-sveltekit/src/lib/Separator.svelte create mode 100644 client/web-sveltekit/src/stories/Separator.stories.ts create mode 100644 client/web-sveltekit/src/stories/SeparatorExample.svelte diff --git a/client/web-sveltekit/.eslintrc.cjs b/client/web-sveltekit/.eslintrc.cjs index 3c18eb107d2..1b33d9a5b4c 100644 --- a/client/web-sveltekit/.eslintrc.cjs +++ b/client/web-sveltekit/.eslintrc.cjs @@ -1,13 +1,19 @@ const baseConfig = require('../../.eslintrc') module.exports = { root: true, - extends: '../../.eslintrc.js', + extends: ['../../.eslintrc.js', 'plugin:storybook/recommended'], parserOptions: { ...baseConfig.parserOptions, project: [__dirname + '/tsconfig.json', __dirname + '/src/**/tsconfig.json'], }, plugins: [...baseConfig.plugins, 'svelte3'], - overrides: [...baseConfig.overrides, { files: ['*.svelte'], processor: 'svelte3/svelte3' }], + overrides: [ + ...baseConfig.overrides, + { + files: ['*.svelte'], + processor: 'svelte3/svelte3', + }, + ], settings: { ...baseConfig.settings, 'svelte3/typescript': () => require('typescript'), diff --git a/client/web-sveltekit/.storybook/main.js b/client/web-sveltekit/.storybook/main.js new file mode 100644 index 00000000000..04694945b5f --- /dev/null +++ b/client/web-sveltekit/.storybook/main.js @@ -0,0 +1,13 @@ +/** @type { import('@storybook/sveltekit').StorybookConfig } */ +const config = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'], + framework: { + name: '@storybook/sveltekit', + options: {}, + }, + docs: { + autodocs: 'tag', + }, +} +export default config diff --git a/client/web-sveltekit/.storybook/preview.js b/client/web-sveltekit/.storybook/preview.js new file mode 100644 index 00000000000..f7cb2d1449a --- /dev/null +++ b/client/web-sveltekit/.storybook/preview.js @@ -0,0 +1,14 @@ +/** @type { import('@storybook/svelte').Preview } */ +const preview = { + parameters: { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, + }, +} + +export default preview diff --git a/client/web-sveltekit/package.json b/client/web-sveltekit/package.json index c4ecfa8bab1..e70f5dcb86d 100644 --- a/client/web-sveltekit/package.json +++ b/client/web-sveltekit/package.json @@ -1,45 +1,58 @@ { - "name": "@sourcegraph/web-sveltekit", - "version": "0.0.1", - "scripts": { - "dev": "vite dev", - "dev:dotcom": "vite dev --mode=dotcom", - "dev:oss": "vite dev --mode=oss", - "build": "vite build", - "preview": "vite preview", - "test": "playwright test", - "sync": "svelte-kit sync", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "eslint .", - "format": "prettier --plugin-search-dir . --write .", - "generate": "pnpm -w generate" - }, - "devDependencies": { - "@playwright/test": "1.25.0", - "@sveltejs/adapter-auto": "^2.1.0", - "@sveltejs/adapter-static": "^2.0.2", - "@sveltejs/kit": "^1.20.4", - "@types/cookie": "^0.5.1", - "@types/prismjs": "^1.26.0", - "eslint-plugin-svelte3": "^4.0.0", - "prettier-plugin-svelte": "^2.10.1", - "svelte": "^4.0.0", - "svelte-check": "^3.4.3", - "tslib": "2.1.0", - "vite": "^4.3.9" - }, - "type": "module", - "dependencies": { - "@popperjs/core": "^2.11.8", - "@remix-run/router": "~1.3.2", - "@sourcegraph/branded": "workspace:*", - "@sourcegraph/common": "workspace:*", - "@sourcegraph/http-client": "workspace:*", - "@sourcegraph/shared": "workspace:*", - "@sourcegraph/web": "workspace:*", - "@sourcegraph/wildcard": "workspace:*", - "lodash-es": "^4.17.21", - "prismjs": "^1.29.0" - } + "name": "@sourcegraph/web-sveltekit", + "version": "0.0.1", + "scripts": { + "dev": "vite dev", + "dev:dotcom": "vite dev --mode=dotcom", + "dev:oss": "vite dev --mode=oss", + "build": "vite build", + "preview": "vite preview", + "test": "playwright test", + "sync": "svelte-kit sync", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "eslint .", + "format": "prettier --plugin-search-dir . --write .", + "generate": "pnpm -w generate", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, + "devDependencies": { + "@playwright/test": "1.25.0", + "@storybook/addon-essentials": "^7.0.26", + "@storybook/addon-interactions": "^7.0.26", + "@storybook/addon-links": "^7.0.26", + "@storybook/blocks": "^7.0.26", + "@storybook/svelte": "^7.0.26", + "@storybook/sveltekit": "^7.0.26", + "@storybook/testing-library": "^0.0.14-next.2", + "@sveltejs/adapter-auto": "^2.1.0", + "@sveltejs/adapter-static": "^2.0.2", + "@sveltejs/kit": "^1.20.4", + "@types/cookie": "^0.5.1", + "@types/prismjs": "^1.26.0", + "eslint-plugin-storybook": "^0.6.12", + "eslint-plugin-svelte3": "^4.0.0", + "prettier-plugin-svelte": "^2.10.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "storybook": "^7.0.26", + "svelte": "^4.0.0", + "svelte-check": "^3.4.3", + "tslib": "2.1.0", + "vite": "^4.3.9" + }, + "type": "module", + "dependencies": { + "@popperjs/core": "^2.11.8", + "@remix-run/router": "~1.3.2", + "@sourcegraph/branded": "workspace:*", + "@sourcegraph/common": "workspace:*", + "@sourcegraph/http-client": "workspace:*", + "@sourcegraph/shared": "workspace:*", + "@sourcegraph/web": "workspace:*", + "@sourcegraph/wildcard": "workspace:*", + "lodash-es": "^4.17.21", + "prismjs": "^1.29.0" + } } diff --git a/client/web-sveltekit/src/lib/Separator.svelte b/client/web-sveltekit/src/lib/Separator.svelte new file mode 100644 index 00000000000..26551b97b91 --- /dev/null +++ b/client/web-sveltekit/src/lib/Separator.svelte @@ -0,0 +1,102 @@ + + + + + +
+ +
+
+ + diff --git a/client/web-sveltekit/src/lib/stores.ts b/client/web-sveltekit/src/lib/stores.ts index 33492cf8942..98b8bbf0e7e 100644 --- a/client/web-sveltekit/src/lib/stores.ts +++ b/client/web-sveltekit/src/lib/stores.ts @@ -1,5 +1,5 @@ import { getContext } from 'svelte' -import { readable, type Readable } from 'svelte/store' +import { readable, writable, type Readable, type Writable } from 'svelte/store' import type { GraphQLClient } from '$lib/http-client' import type { SettingsCascade, AuthenticatedUser, TemporarySettingsStorage } from '$lib/shared' @@ -53,3 +53,30 @@ export const graphqlClient = readable(null, set => { // eslint-disable-next-line no-void void getWebGraphQLClient().then(client => set(client)) }) + +/** + * This store syncs the provided value with localStorage. Values must be JSON (de)seralizable. + */ +export function createLocalWritable(localStorageKey: string, defaultValue: T): Writable { + const { subscribe, set, update } = writable(defaultValue, set => { + const existingValue = localStorage.getItem(localStorageKey) + if (existingValue) { + set(JSON.parse(existingValue)) + } + }) + + return { + subscribe, + set: value => { + set(value) + localStorage.setItem(localStorageKey, JSON.stringify(value)) + }, + update: fn => { + update(value => { + const newValue = fn(value) + localStorage.setItem(localStorageKey, JSON.stringify(newValue)) + return newValue + }) + }, + } +} diff --git a/client/web-sveltekit/src/routes/[...repo]/(code)/+layout.svelte b/client/web-sveltekit/src/routes/[...repo]/(code)/+layout.svelte index cff254843cd..1a4e305b2fb 100644 --- a/client/web-sveltekit/src/routes/[...repo]/(code)/+layout.svelte +++ b/client/web-sveltekit/src/routes/[...repo]/(code)/+layout.svelte @@ -5,6 +5,7 @@ import Icon from '$lib/Icon.svelte' import FileTree from '$lib/repo/FileTree.svelte' import { asStore } from '$lib/utils' + import Separator, { getSeparatorPosition } from '$lib/Separator.svelte' import type { PageData } from './$types' @@ -15,11 +16,14 @@ } $: treeOrError = asStore(data.treeEntries.deferred) + let showSidebar = true + const sidebarSize = getSeparatorPosition('repo-sidebar', 0.2) + $: sidebarWidth = showSidebar ? `max(200px, ${$sidebarSize * 100}%)` : undefined
-