mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-29 20:43:37 +03:00
Merge branch 'master' of https://github.com/gitbutlerapp/gitbutler-client
This commit is contained in:
commit
afcc6da963
@ -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,20 +171,23 @@
|
||||
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) => {
|
||||
if ($currentProject) {
|
||||
listFiles({ projectId: $currentProject.id }).then((files) => {
|
||||
console.log('files', files);
|
||||
changedFiles = files;
|
||||
});
|
||||
@ -181,6 +195,15 @@
|
||||
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,8 +265,9 @@
|
||||
updateMenu([]);
|
||||
return;
|
||||
}
|
||||
if ($currentProject) {
|
||||
const searchPattern = '.*' + Array.from(searchValue).join('(.*)');
|
||||
matchFiles({ projectId: projectId, matchPattern: searchPattern }).then((files) => {
|
||||
matchFiles({ projectId: $currentProject.id, matchPattern: searchPattern }).then((files) => {
|
||||
let searchResults = [];
|
||||
files.slice(0, 5).forEach((f) => {
|
||||
searchResults.push({ text: f, icon: FileIcon });
|
||||
@ -220,17 +275,17 @@
|
||||
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,9 +294,9 @@
|
||||
changedFiles.push(c.dataset['file']);
|
||||
}
|
||||
});
|
||||
console.log('files', changedFiles, commitMessage);
|
||||
if ($currentProject) {
|
||||
commit({
|
||||
projectId: projectId,
|
||||
projectId: $currentProject.id,
|
||||
message: commitMessage,
|
||||
files: changedFiles,
|
||||
push: false
|
||||
@ -251,6 +306,7 @@
|
||||
showCommit = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} on:keyup={onKeyUp} on:click={checkCommandModal} />
|
||||
@ -309,13 +365,17 @@
|
||||
<li class="p-1">
|
||||
<ul id="commandMenu" class="text-sm text-zinc-400">
|
||||
{#each menuItems as item}
|
||||
{#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="group flex cursor-default select-none items-center rounded-md px-3 py-2"
|
||||
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} />
|
||||
@ -328,6 +388,7 @@
|
||||
</span>
|
||||
{/if}
|
||||
</li>
|
||||
{/if}
|
||||
{/each}
|
||||
</ul>
|
||||
</li>
|
||||
|
14
src/lib/components/icons/ContactIcon.svelte
Normal file
14
src/lib/components/icons/ContactIcon.svelte
Normal 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 |
14
src/lib/components/icons/ProjectIcon.svelte
Normal file
14
src/lib/components/icons/ProjectIcon.svelte
Normal 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 |
4
src/lib/current_project.ts
Normal file
4
src/lib/current_project.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type { Project } from '$lib/projects';
|
||||
|
||||
export const currentProject = writable<Project|undefined>(undefined);
|
@ -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>
|
||||
|
@ -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,
|
||||
|
74
src/routes/contact/+page.svelte
Normal file
74
src/routes/contact/+page.svelte
Normal 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">→</span></a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -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} />
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user