This commit is contained in:
Ian Donahue 2023-03-13 02:43:24 +01:00
commit afcc6da963
9 changed files with 244 additions and 67 deletions

View File

@ -4,9 +4,13 @@
import CommitIcon from './icons/CommitIcon.svelte';
import BookmarkIcon from './icons/BookmarkIcon.svelte';
import BranchIcon from './icons/BranchIcon.svelte';
import ContactIcon from './icons/ContactIcon.svelte';
import ProjectIcon from './icons/ProjectIcon.svelte';
import { invoke } from '@tauri-apps/api';
import { goto } from '$app/navigation';
import { shortPath } from '$lib/paths';
import { currentProject } from '$lib/current_project';
import type { Project } from '$lib/projects';
let showCommand = false;
let showCommit = false;
@ -14,8 +18,7 @@
let is_command_down = false;
let is_k_down = false;
let is_c_down = false;
export let projectId: string;
let is_e_down = false;
let palette: HTMLElement;
let commitPalette: HTMLElement;
@ -30,6 +33,8 @@
const matchFiles = (params: { projectId: string; matchPattern: string }) =>
invoke<Array<string>>('git_match_paths', params);
const listProjects = () => invoke<Project[]>('list_projects');
const commit = (params: {
projectId: string;
message: string;
@ -50,6 +55,9 @@
case 'c':
is_c_down = true;
break;
case 'e':
is_e_down = true;
break;
case 'Escape':
showCommand = false;
showCommit = false;
@ -83,6 +91,9 @@
showCommit = true;
executeCommand('commit');
}
if (is_command_down && is_e_down) {
executeCommand('contact');
}
}
function onKeyUp(event: KeyboardEvent) {
@ -99,6 +110,10 @@
is_c_down = false;
event.preventDefault();
break;
case 'e':
is_e_down = false;
event.preventDefault();
break;
}
}
@ -117,7 +132,7 @@
function upMenu() {
const menu = document.getElementById('commandMenu');
if (menu) {
const items = menu.querySelectorAll('li');
const items = menu.querySelectorAll('li.item');
const active = menu.querySelector('li.active');
if (active) {
const index = Array.from(items).indexOf(active);
@ -132,14 +147,10 @@
}
function downMenu() {
console.log('DOWN');
const menu = document.getElementById('commandMenu');
console.log('menu', menu);
if (menu) {
const items = menu.querySelectorAll('li');
console.log('items', items);
const items = menu.querySelectorAll('li.item');
const active = menu.querySelector('li.active');
console.log('active', active);
if (active) {
const index = Array.from(items).indexOf(active);
if (index < items.length - 1) {
@ -160,27 +171,39 @@
const active = menu.querySelector('li.active');
if (active) {
const command = active.getAttribute('data-command');
const context = active.getAttribute('data-context');
if (command) {
executeCommand(command);
executeCommand(command, context);
}
console.log('active', active);
} else {
goto('/projects/' + projectId + '/search?search=' + search);
if ($currentProject) {
goto('/projects/' + $currentProject.id + '/search?search=' + search);
}
}
}
}
function executeCommand(command: string) {
function executeCommand(command: string, context?: string | null) {
switch (command) {
case 'commit':
listFiles({ projectId: projectId }).then((files) => {
console.log('files', files);
changedFiles = files;
});
showCommit = true;
setTimeout(function () {
commitMessageInput.focus();
}, 100);
if ($currentProject) {
listFiles({ projectId: $currentProject.id }).then((files) => {
console.log('files', files);
changedFiles = files;
});
showCommit = true;
setTimeout(function () {
commitMessageInput.focus();
}, 100);
}
break;
case 'contact':
console.log('contact us');
goto('/contact');
break;
case 'switch':
console.log('switch', command, context);
goto('/projects/' + context);
break;
case 'bookmark':
break;
@ -195,13 +218,44 @@
searchChanged(search, showCommand);
}
let baseCommands = [
let projectCommands = [
{ text: 'Commit', key: 'C', icon: CommitIcon, command: 'commit' },
{ text: 'Bookmark', key: 'B', icon: BookmarkIcon, command: 'bookmark' },
{ text: 'Branch', key: 'H', icon: BranchIcon, command: 'branch' }
{ text: 'Branch', key: 'R', icon: BranchIcon, command: 'branch' }
];
$: menuItems = baseCommands;
let switchCommands = [];
$: if ($currentProject) {
listProjects().then((projects) => {
switchCommands = [];
projects.forEach((p) => {
if (p.id !== $currentProject?.id) {
switchCommands.push({
text: p.title,
icon: ProjectIcon,
command: 'switch',
context: p.id
});
}
});
});
}
let baseCommands = [{ text: 'Contact Us', key: 'E', icon: ContactIcon, command: 'contact' }];
function commandList() {
let commands = [];
let divider = [{ type: 'divider' }];
if ($currentProject) {
commands = projectCommands.concat(divider).concat(switchCommands);
} else {
commands = switchCommands;
}
commands = commands.concat(divider).concat(baseCommands);
return commands;
}
$: menuItems = commandList();
function searchChanged(searchValue: string, showCommand: boolean) {
if (!showCommand) {
@ -211,26 +265,27 @@
updateMenu([]);
return;
}
const searchPattern = '.*' + Array.from(searchValue).join('(.*)');
matchFiles({ projectId: projectId, matchPattern: searchPattern }).then((files) => {
let searchResults = [];
files.slice(0, 5).forEach((f) => {
searchResults.push({ text: f, icon: FileIcon });
if ($currentProject) {
const searchPattern = '.*' + Array.from(searchValue).join('(.*)');
matchFiles({ projectId: $currentProject.id, matchPattern: searchPattern }).then((files) => {
let searchResults = [];
files.slice(0, 5).forEach((f) => {
searchResults.push({ text: f, icon: FileIcon });
});
updateMenu(searchResults);
});
updateMenu(searchResults);
});
}
}
function updateMenu(searchResults: Array<{ text: string }>) {
if (searchResults.length == 0) {
menuItems = baseCommands;
menuItems = commandList();
} else {
menuItems = searchResults;
}
}
function doCommit() {
console.log('do commit', commitMessage);
// get checked files
let changedFiles: Array<string> = [];
let doc = document.getElementsByClassName('file-checkbox');
@ -239,17 +294,18 @@
changedFiles.push(c.dataset['file']);
}
});
console.log('files', changedFiles, commitMessage);
commit({
projectId: projectId,
message: commitMessage,
files: changedFiles,
push: false
}).then((result) => {
console.log('commit result', result);
commitMessage = '';
showCommit = false;
});
if ($currentProject) {
commit({
projectId: $currentProject.id,
message: commitMessage,
files: changedFiles,
push: false
}).then((result) => {
console.log('commit result', result);
commitMessage = '';
showCommit = false;
});
}
}
</script>
@ -309,25 +365,30 @@
<li class="p-1">
<ul id="commandMenu" class="text-sm text-zinc-400">
{#each menuItems as item}
<!-- Active: "bg-zinc-800 text-white" -->
<li
class="group flex cursor-default select-none items-center rounded-md px-3 py-2"
on:click={() => {
executeCommand(item.command);
}}
data-command={item.command}
>
<!-- Active: "text-white", Not Active: "text-zinc-500" -->
<svelte:component this={item.icon} />
<span class="ml-3 flex-auto truncate">{item.text}</span>
{#if item.key}
<span
class="ml-3 flex-none text-xs font-semibold text-zinc-400 px-1 py-1 bg-zinc-800 border-b border-black rounded"
>
<kbd class="font-sans"></kbd><kbd class="font-sans">{item.key}</kbd>
</span>
{/if}
</li>
{#if item.type == 'divider'}
<li class="border-t border-zinc-500 border-opacity-20 my-2" />
{:else}
<!-- Active: "bg-zinc-800 text-white" -->
<li
class="item group flex cursor-default select-none items-center rounded-md px-3 py-2"
on:click={() => {
executeCommand(item.command);
}}
data-command={item.command}
data-context={item.context}
>
<!-- Active: "text-white", Not Active: "text-zinc-500" -->
<svelte:component this={item.icon} />
<span class="ml-3 flex-auto truncate">{item.text}</span>
{#if item.key}
<span
class="ml-3 flex-none text-xs font-semibold text-zinc-400 px-1 py-1 bg-zinc-800 border-b border-black rounded"
>
<kbd class="font-sans"></kbd><kbd class="font-sans">{item.key}</kbd>
</span>
{/if}
</li>
{/if}
{/each}
</ul>
</li>

View File

@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
/>
</svg>

After

Width:  |  Height:  |  Size: 459 B

View File

@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z"
/>
</svg>

After

Width:  |  Height:  |  Size: 460 B

View File

@ -0,0 +1,4 @@
import { writable } from 'svelte/store';
import type { Project } from '$lib/projects';
export const currentProject = writable<Project|undefined>(undefined);

View File

@ -8,6 +8,7 @@
import { writable } from 'svelte/store';
import Breadcrumbs from '$lib/components/Breadcrumbs.svelte';
import CommandPalette from '$lib/components/CommandPalette.svelte';
import { currentProject } from '$lib/current_project';
export let data: LayoutData;
const { user, posthog, projects } = data;
@ -45,4 +46,5 @@
<slot />
</div>
<Toaster />
<CommandPalette />
</div>

View File

@ -2,11 +2,14 @@
import { open } from '@tauri-apps/api/dialog';
import type { LayoutData } from './$types';
import { toasts } from '$lib';
import { currentProject } from '$lib/current_project';
export let data: LayoutData;
const { projects } = data;
$: currentProject.set(undefined);
const onAddLocalRepositoryClick = async () => {
const selectedPath = await open({
directory: true,

View File

@ -0,0 +1,74 @@
<div class="isolate py-8 text-zinc-200">
<div class="mx-auto max-w-2xl sm:text-center">
<h2 class="text-xl font-bold tracking-tight">Contact Us</h2>
<p class="mt-2 text-lg leading-8 text-zinc-300">
Thanks for using GitButler! We would love to help with any questions, problems or requests.
Select your weapon of choice.
</p>
</div>
<div class="mx-auto mt-8 max-w-lg space-y-16">
<div class="flex gap-x-6">
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-blue-600">
<svg
class="h-6 w-6 text-white"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
/>
</svg>
</div>
<div>
<h3 class="text-base font-semibold leading-7 text-zinc-100">Email Us</h3>
<p class="mt-2 text-zinc-400">
We love our emails. For bugs, feature requests, general questions or anything else, just
fire off an emain from your favorite client.
</p>
<p class="mt-4">
<a class="text-blue-200" href="mailto:hello@gitbutler.com">hello@gitbutler.com</a>
</p>
</div>
</div>
<div class="flex gap-x-6">
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-blue-600">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-white"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155"
/>
</svg>
</div>
<div>
<h3 class="text-base font-semibold leading-7 text-zinc-100">Chat with Us</h3>
<p class="mt-2 text-zinc-400">
If you prefer chatting in public, join our Discord community for something a little more
real time.
</p>
<p class="mt-4">
<a
target="_blank"
rel="noopener noreferrer"
href="https://discord.com/channels/1060193121130000425/1060193121666863156"
class="text-sm font-semibold leading-6 text-blue-200"
>Join our Discord <span aria-hidden="true">&rarr;</span></a
>
</p>
</div>
</div>
</div>
</div>

View File

@ -5,11 +5,12 @@
import type { Project } from '$lib/projects';
import { onDestroy } from 'svelte';
import { page } from '$app/stores';
import CommandPalette from '$lib/components/CommandPalette.svelte';
import { currentProject } from '$lib/current_project';
export let data: LayoutData;
$: project = data.project;
$: currentProject.set($project);
function projectUrl(project: Project) {
const gitUrl = project.api?.git_url;
@ -126,7 +127,12 @@
<a target="_blank" rel="noreferrer" href={projectUrl($project)} class="flex">
<div class="leading-5">Open in GitButler Cloud</div>
<div class="icon h-5 w-5 ml-1">
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill="#52525B" d="M14 13v1a1 1 0 01-1 1H6c-.575 0-1-.484-1-1V7a1 1 0 011-1h1c1.037 0 1.04 1.5 0 1.5-.178.005-.353 0-.5 0v6h6V13c0-1 1.5-1 1.5 0zm-3.75-7.25A.75.75 0 0111 5h4v4a.75.75 0 01-1.5 0V7.56l-3.22 3.22a.75.75 0 11-1.06-1.06l3.22-3.22H11a.75.75 0 01-.75-.75z"/></svg>
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
><path
fill="#52525B"
d="M14 13v1a1 1 0 01-1 1H6c-.575 0-1-.484-1-1V7a1 1 0 011-1h1c1.037 0 1.04 1.5 0 1.5-.178.005-.353 0-.5 0v6h6V13c0-1 1.5-1 1.5 0zm-3.75-7.25A.75.75 0 0111 5h4v4a.75.75 0 01-1.5 0V7.56l-3.22 3.22a.75.75 0 11-1.06-1.06l3.22-3.22H11a.75.75 0 01-.75-.75z"
/></svg
>
</div>
</a>
{:else}
@ -141,4 +147,3 @@
</div>
</footer>
</div>
<CommandPalette projectId={$project?.id} />

View File

@ -119,7 +119,7 @@
<div class="recent-file-changes-container w-full h-full">
<h2 class="mb-4 px-8 text-lg font-bold text-zinc-300">Recent File Changes</h2>
{#if $dateSessions === undefined}
<span>Loading...</span>
<div class="p-8 text-zinc-400 text-center">Loading...</div>
{:else}
<div
class="flex flex-col space-y-4 overflow-y-auto px-8 pb-8"