mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-25 18:49:11 +03:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
a7bdd39d12
@ -47,7 +47,8 @@
|
||||
"nanoid": "^4.0.1",
|
||||
"posthog-js": "^1.46.1",
|
||||
"svelte-french-toast": "^1.0.3",
|
||||
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log"
|
||||
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log",
|
||||
"tinykeys": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "next",
|
||||
|
@ -55,6 +55,7 @@ specifiers:
|
||||
svelte-french-toast: ^1.0.3
|
||||
tailwindcss: ^3.1.5
|
||||
tauri-plugin-log-api: github:tauri-apps/tauri-plugin-log
|
||||
tinykeys: ^1.4.0
|
||||
tslib: ^2.4.1
|
||||
typescript: ^4.8.4
|
||||
vite: ^4.0.0
|
||||
@ -95,6 +96,7 @@ dependencies:
|
||||
posthog-js: 1.46.1
|
||||
svelte-french-toast: 1.0.3_svelte@3.55.1
|
||||
tauri-plugin-log-api: github.com/tauri-apps/tauri-plugin-log/05a9bfd9edb9b5f4ab95412bb607691708b65a25
|
||||
tinykeys: 1.4.0
|
||||
|
||||
devDependencies:
|
||||
'@sveltejs/adapter-static': 1.0.0-next.50_l5ueyfihz3gpzzvvyo2ean5u3e
|
||||
@ -2526,6 +2528,10 @@ packages:
|
||||
globrex: 0.1.2
|
||||
dev: true
|
||||
|
||||
/tinykeys/1.4.0:
|
||||
resolution: {integrity: sha512-ysnVd2E4nWbNXIbHaUidcKGLTmNimqP0hdpsD0Ph5hPJ84ntCF6PHj+Jg3im9nZt9/hNsBg/E6m1psHc2KaPnQ==}
|
||||
dev: false
|
||||
|
||||
/to-regex-range/5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
@ -1,12 +1,52 @@
|
||||
<script>
|
||||
let history = window.history;
|
||||
<script lang="ts">
|
||||
import { afterNavigate, goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
let position = 0;
|
||||
const history = [$page.url.pathname];
|
||||
|
||||
$: canGoBack = history.length > 1 && position > 0;
|
||||
$: canGoForward = history.length > 1 && position < history.length - 1;
|
||||
|
||||
afterNavigate((nav) => {
|
||||
if (nav.to === null) return;
|
||||
const to = nav.to.url.pathname;
|
||||
if (to === history[position]) {
|
||||
return;
|
||||
} else if (to === history[position + 1]) {
|
||||
position++;
|
||||
} else if (to === history[position - 1]) {
|
||||
position--;
|
||||
} else {
|
||||
history.splice(position + 1);
|
||||
history.push(to);
|
||||
position++;
|
||||
}
|
||||
});
|
||||
|
||||
const onBackClicked = () => {
|
||||
if (canGoBack) {
|
||||
position--;
|
||||
goto(history[position]);
|
||||
}
|
||||
};
|
||||
|
||||
const onForwardClicked = () => {
|
||||
if (canGoForward) {
|
||||
position++;
|
||||
goto(history[position]);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center space-x-3 text-zinc-400">
|
||||
<button
|
||||
class="group rounded-md p-2 hover:bg-zinc-700 hover:text-zinc-200"
|
||||
class="group rounded-md p-2"
|
||||
class:hover:bg-zinc-700={canGoBack}
|
||||
class:cursor-pointer={canGoBack}
|
||||
on:click={onBackClicked}
|
||||
disabled={!canGoBack}
|
||||
title="Go back"
|
||||
on:click={() => history.back()}
|
||||
>
|
||||
<div class="flex h-4 w-4 items-center justify-center">
|
||||
<svg
|
||||
@ -21,15 +61,17 @@
|
||||
clip-rule="evenodd"
|
||||
d="M14.9998 5H3.41376L6.70676 1.707C7.09776 1.316 7.09776 0.684 6.70676 0.293C6.31576 -0.0979999 5.68376 -0.0979999 5.29276 0.293L0.292762 5.293C-0.0982383 5.684 -0.0982383 6.316 0.292762 6.707L5.29276 11.707C5.48776 11.902 5.74376 12 5.99976 12C6.25576 12 6.51176 11.902 6.70676 11.707C7.09776 11.316 7.09776 10.684 6.70676 10.293L3.41376 7H14.9998C15.5528 7 15.9998 6.552 15.9998 6C15.9998 5.448 15.5528 5 14.9998 5Z"
|
||||
fill="#5C5F62"
|
||||
class="group-hover:fill-zinc-50"
|
||||
class:fill-zinc-50={canGoBack}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
class="group rounded-md p-2 hover:bg-zinc-700 hover:text-zinc-200"
|
||||
class="group rounded-md p-2"
|
||||
title="Go forward"
|
||||
on:click={() => history.forward()}
|
||||
class:hover:bg-zinc-700={canGoForward}
|
||||
on:click={onForwardClicked}
|
||||
disabled={!canGoForward}
|
||||
>
|
||||
<div class="flex h-4 w-4 items-center justify-center">
|
||||
<svg
|
||||
@ -44,7 +86,7 @@
|
||||
clip-rule="evenodd"
|
||||
d="M15.707 5.293L10.707 0.293C10.316 -0.0979999 9.684 -0.0979999 9.293 0.293C8.902 0.684 8.902 1.316 9.293 1.707L12.586 5H1C0.447 5 0 5.448 0 6C0 6.552 0.447 7 1 7H12.586L9.293 10.293C8.902 10.684 8.902 11.316 9.293 11.707C9.488 11.902 9.744 12 10 12C10.256 12 10.512 11.902 10.707 11.707L15.707 6.707C16.098 6.316 16.098 5.684 15.707 5.293Z"
|
||||
fill="#5C5F62"
|
||||
class="group-hover:fill-zinc-50"
|
||||
class:fill-zinc-50={canGoForward}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
81
src/lib/components/CommandPalette/CommandPalette.svelte
Normal file
81
src/lib/components/CommandPalette/CommandPalette.svelte
Normal file
@ -0,0 +1,81 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount, afterUpdate } from 'svelte';
|
||||
import { currentProject } from '$lib/current_project';
|
||||
import { IconCircleCancel } from '$lib/components/icons';
|
||||
import tinykeys from 'tinykeys';
|
||||
|
||||
$: scopeToProject = $currentProject ? true : false;
|
||||
|
||||
let showingCommandPalette = false;
|
||||
let dialog: HTMLDialogElement;
|
||||
let userInput: string;
|
||||
|
||||
const toggleCommandPalette = () => {
|
||||
if (dialog && dialog.open) {
|
||||
dialog.close();
|
||||
showingCommandPalette = false;
|
||||
} else {
|
||||
dialog.showModal();
|
||||
showingCommandPalette = true;
|
||||
}
|
||||
};
|
||||
|
||||
let unsubscribeKeyboardHandler: () => void;
|
||||
|
||||
onMount(() => {
|
||||
toggleCommandPalette();
|
||||
unsubscribeKeyboardHandler = tinykeys(window, {
|
||||
'Meta+k': () => {
|
||||
toggleCommandPalette();
|
||||
},
|
||||
Backspace: () => {
|
||||
if (!userInput) {
|
||||
scopeToProject = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
unsubscribeKeyboardHandler?.();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<dialog
|
||||
class="rounded-lg
|
||||
border border-zinc-400/40
|
||||
bg-zinc-900/70 p-0 backdrop-blur-xl
|
||||
"
|
||||
bind:this={dialog}
|
||||
on:click|self={() => toggleCommandPalette()}
|
||||
>
|
||||
<div class="min-h-[640px] w-[640px] rounded text-zinc-400" on:click|stopPropagation>
|
||||
<!-- Search input area -->
|
||||
<div class="flex h-14 items-center border-b border-zinc-400/20">
|
||||
<div class="ml-4 flex flex-grow items-center">
|
||||
<!-- Project scope -->
|
||||
{#if scopeToProject}
|
||||
<div class="flex items-center">
|
||||
<span class="font-semibold text-zinc-300">{$currentProject?.title}</span>
|
||||
<span class="ml-1 text-lg">/</span>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Search input -->
|
||||
<div class="mx-1 flex-grow">
|
||||
<input
|
||||
class="w-full bg-transparent text-zinc-300 focus:outline-none"
|
||||
bind:value={userInput}
|
||||
type="text"
|
||||
placeholder={scopeToProject
|
||||
? 'Search for commands, files and code changes...'
|
||||
: 'Search for projects'}
|
||||
/>
|
||||
</div>
|
||||
<div class="mr-4 text-red-50">
|
||||
<IconCircleCancel class="fill-zinc-400" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
3
src/lib/components/CommandPalette/index.ts
Normal file
3
src/lib/components/CommandPalette/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { default as CommandPaletteNext } from './CommandPalette.svelte';
|
||||
|
||||
export default CommandPaletteNext;
|
14
src/lib/components/icons/IconCircleCancel.svelte
Normal file
14
src/lib/components/icons/IconCircleCancel.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<svg
|
||||
{...$$restProps}
|
||||
width="15"
|
||||
height="15"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M0 10C0 4.486 4.486 0 10 0C15.514 0 20 4.486 20 10C20 15.514 15.514 20 10 20C4.486 20 0 15.514 0 10ZM7.70711 6.29289C7.31658 5.90237 6.68342 5.90237 6.29289 6.29289C5.90237 6.68342 5.90237 7.31658 6.29289 7.70711L8.58579 10L6.29289 12.2929C5.90237 12.6834 5.90237 13.3166 6.29289 13.7071C6.68342 14.0976 7.31658 14.0976 7.70711 13.7071L10 11.4142L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L11.4142 10L13.7071 7.70711C14.0976 7.31658 14.0976 6.68342 13.7071 6.29289C13.3166 5.90237 12.6834 5.90237 12.2929 6.29289L10 8.58579L7.70711 6.29289Z"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 806 B |
@ -13,3 +13,4 @@ export { default as IconCircleHalf } from './IconCircleHalf.svelte';
|
||||
export { default as IconSquareRoundedFilled } from './IconSquareRoundedFilled.svelte';
|
||||
export { default as IconMapPinFilled } from './IconMapPinFilled.svelte';
|
||||
export { default as IconCircleFilled } from './IconCircleFilled.svelte';
|
||||
export { default as IconCircleCancel } from './IconCircleCancel.svelte';
|
||||
|
@ -450,9 +450,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="middle" class="flex-auto overflow-auto ">
|
||||
<div class="flex h-full w-full flex-col gap-2">
|
||||
<div id="code" class="flex-auto overflow-auto px-2">
|
||||
<div
|
||||
id="middle"
|
||||
class="flex-auto overflow-auto border border-zinc-700 rounded m-2 bg-[#2F2F33] "
|
||||
>
|
||||
<div class="flex h-full w-full flex-col gap-2 relative ">
|
||||
<div id="code" class="flex-auto overflow-auto px-2 h-full w-full pb-[120px]">
|
||||
{#if currentEdit !== null}
|
||||
<CodeViewer
|
||||
doc={currentEdit.doc}
|
||||
@ -462,21 +465,26 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div id="info" class="mx-4 rounded-lg bg-zinc-800 p-2">
|
||||
<div id="info" class=" rounded-lg bg-zinc-800 p-2 absolute bottom-[64px] left-4">
|
||||
<div class="flex flex-row justify-between">
|
||||
<div>{currentPlaylist.chapters.length} sessions</div>
|
||||
<div>{currentPlaylist.editCount} edits</div>
|
||||
<div>{Math.round(currentPlaylist.totalDurationMs / 1000 / 60)} min</div>
|
||||
</div>
|
||||
{#if currentEdit !== null}
|
||||
<div class="flex flex-row justify-between">
|
||||
{#if currentEdit !== null}
|
||||
<div class="font-mono font-bold text-white">{currentEdit.filepath}</div>
|
||||
<div>{new Date(currentEdit.delta.timestampMs).toLocaleString('en-US')}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="controls" class="flex flex-col p-2">
|
||||
<div
|
||||
id="controls"
|
||||
class="flex flex-col p-2 absolute bottom-0 w-full border-t border-zinc-700 bg-[#2E2E32]/75"
|
||||
style="
|
||||
border-width: 0.5px;
|
||||
-webkit-backdrop-filter: blur(20px) saturate(190%) contrast(70%) brightness(80%);
|
||||
backdrop-filter: blur(20px) saturate(190%) contrast(70%) brightness(80%);
|
||||
background-color: rgba(24, 24, 27, 0.60);
|
||||
border: 0.5px solid rgba(63, 63, 70, 0.50);
|
||||
"
|
||||
>
|
||||
<div class="flex h-0 w-full justify-between">
|
||||
{#each currentPlaylist.chapters as chapter}
|
||||
<div
|
||||
|
Loading…
Reference in New Issue
Block a user