mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-09-19 16:17:37 +03:00
Merge origin/master into origin/always-await-promises
This commit is contained in:
commit
78a7d44b45
@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Button from './Button.svelte';
|
||||
import IconButton from './IconButton.svelte';
|
||||
import { UpdaterService } from '$lib/backend/updater';
|
||||
import { showToast } from '$lib/notifications/toasts';
|
||||
import { getContext } from '$lib/utils/context';
|
||||
@ -20,7 +19,7 @@
|
||||
{#if $update$?.version && $update$.status != 'UPTODATE' && !dismissed}
|
||||
<div class="update-banner" class:busy={$update$?.status == 'PENDING'}>
|
||||
<div class="floating-button">
|
||||
<IconButton icon="cross-small" on:click={() => (dismissed = true)} />
|
||||
<Button icon="cross-small" style="ghost" on:click={() => (dismissed = true)} />
|
||||
</div>
|
||||
<div class="img">
|
||||
<div class="circle-img">
|
||||
|
@ -31,6 +31,8 @@
|
||||
let branchName = branch?.upstreamName || normalizeBranchName($branchStore.name);
|
||||
|
||||
function handleBranchNameChange(title: string) {
|
||||
if (title == '') return;
|
||||
|
||||
branchName = normalizeBranchName(title);
|
||||
branchController.updateBranchName(branch.id, title);
|
||||
}
|
||||
@ -87,40 +89,44 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="header__wrapper">
|
||||
<div class="header card" class:isUnapplied>
|
||||
<div class="header__info">
|
||||
<div class="header__label">
|
||||
<div class="header card">
|
||||
<div class="header__info-wrapper">
|
||||
{#if !isUnapplied}
|
||||
<div class="draggable" data-drag-handle>
|
||||
<Icon name="draggable" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="header__info">
|
||||
<BranchLabel
|
||||
name={branch.name || 'hello'}
|
||||
name={branch.name}
|
||||
on:change={(e) => handleBranchNameChange(e.detail.name)}
|
||||
disabled={isUnapplied}
|
||||
/>
|
||||
</div>
|
||||
<div class="header__remote-branch">
|
||||
<ActiveBranchStatus
|
||||
branchName={branch.upstreamName ?? branchName}
|
||||
{isUnapplied}
|
||||
{hasIntegratedCommits}
|
||||
remoteExists={!!branch.upstreamName}
|
||||
isLaneCollapsed={$isLaneCollapsed}
|
||||
/>
|
||||
<div class="header__remote-branch">
|
||||
<ActiveBranchStatus
|
||||
branchName={branch.upstreamName ?? branchName}
|
||||
{isUnapplied}
|
||||
{hasIntegratedCommits}
|
||||
remoteExists={!!branch.upstreamName}
|
||||
isLaneCollapsed={$isLaneCollapsed}
|
||||
/>
|
||||
|
||||
{#await branch.isMergeable then isMergeable}
|
||||
{#if !isMergeable}
|
||||
<Tag
|
||||
icon="locked-small"
|
||||
style="warning"
|
||||
help="Applying this branch will add merge conflict markers that you will have to resolve"
|
||||
>
|
||||
Conflict
|
||||
</Tag>
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
<div class="draggable" data-drag-handle>
|
||||
<Icon name="draggable" />
|
||||
{#await branch.isMergeable then isMergeable}
|
||||
{#if !isMergeable}
|
||||
<Tag
|
||||
icon="locked-small"
|
||||
style="warning"
|
||||
help="Applying this branch will add merge conflict markers that you will have to resolve"
|
||||
>
|
||||
Conflict
|
||||
</Tag>
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header__actions">
|
||||
<div class="header__buttons">
|
||||
{#if branch.active}
|
||||
@ -229,7 +235,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="postcss">
|
||||
<style>
|
||||
.header__wrapper {
|
||||
z-index: var(--z-lifted);
|
||||
position: sticky;
|
||||
@ -240,15 +246,6 @@
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
gap: var(--size-2);
|
||||
|
||||
&:hover {
|
||||
& .draggable {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
&.isUnapplied {
|
||||
background: var(--clr-bg-alt);
|
||||
}
|
||||
}
|
||||
.header__top-overlay {
|
||||
z-index: var(--z-ground);
|
||||
@ -258,13 +255,17 @@
|
||||
width: 100%;
|
||||
height: var(--size-20);
|
||||
background: var(--target-branch-background);
|
||||
/* background-color: red; */
|
||||
}
|
||||
.header__info-wrapper {
|
||||
display: flex;
|
||||
gap: var(--size-2);
|
||||
padding: var(--size-10);
|
||||
}
|
||||
.header__info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: margin var(--transition-slow);
|
||||
padding: var(--size-12);
|
||||
overflow: hidden;
|
||||
gap: var(--size-10);
|
||||
}
|
||||
.header__actions {
|
||||
@ -276,31 +277,19 @@
|
||||
border-radius: 0 0 var(--radius-m) var(--radius-m);
|
||||
user-select: none;
|
||||
}
|
||||
.isUnapplied .header__actions {
|
||||
border-top: 1px solid var(--clr-border-main);
|
||||
}
|
||||
|
||||
.header__buttons {
|
||||
display: flex;
|
||||
position: relative;
|
||||
gap: var(--size-4);
|
||||
}
|
||||
.header__label {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
gap: var(--size-4);
|
||||
}
|
||||
.draggable {
|
||||
display: flex;
|
||||
height: fit-content;
|
||||
cursor: grab;
|
||||
position: absolute;
|
||||
right: var(--size-4);
|
||||
top: var(--size-6);
|
||||
opacity: 0;
|
||||
padding: var(--size-2) var(--size-2) 0 0;
|
||||
color: var(--clr-scale-ntrl-50);
|
||||
transition:
|
||||
opacity var(--transition-slow),
|
||||
color var(--transition-slow);
|
||||
transition: color var(--transition-slow);
|
||||
|
||||
&:hover {
|
||||
color: var(--clr-scale-ntrl-40);
|
||||
@ -326,7 +315,7 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* COLLAPSABLE LANE */
|
||||
/* COLLAPSIBLE LANE */
|
||||
|
||||
.collapsed-lane {
|
||||
cursor: default;
|
||||
|
@ -1,119 +1,97 @@
|
||||
<script lang="ts">
|
||||
import { useResize } from '$lib/utils/useResize';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
export let name: string;
|
||||
export let disabled = false;
|
||||
let inputActive = false;
|
||||
let label: HTMLDivElement;
|
||||
let input: HTMLInputElement;
|
||||
|
||||
function activateInput() {
|
||||
if (disabled) return;
|
||||
inputActive = true;
|
||||
setTimeout(() => input.select(), 0);
|
||||
}
|
||||
|
||||
let inputEl: HTMLInputElement;
|
||||
let initialName = name;
|
||||
|
||||
let mesureEl: HTMLSpanElement;
|
||||
let inputWidth = 0;
|
||||
let inputWidth: string | undefined;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: { name: string };
|
||||
}>();
|
||||
|
||||
$: {
|
||||
if (mesureEl) {
|
||||
inputWidth = mesureEl.getBoundingClientRect().width;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if inputActive}
|
||||
<span class="branch-name-mesure-el text-base-13 text-bold" bind:this={mesureEl}>{name}</span>
|
||||
<input
|
||||
type="text"
|
||||
{disabled}
|
||||
bind:this={input}
|
||||
bind:value={name}
|
||||
on:change={(e) => dispatch('change', { name: e.currentTarget.value })}
|
||||
on:input={() => {
|
||||
if (input.value.length > 0) {
|
||||
inputWidth = mesureEl.getBoundingClientRect().width;
|
||||
} else {
|
||||
inputWidth = 0;
|
||||
}
|
||||
}}
|
||||
title={name}
|
||||
class="branch-name-input text-base-13 text-bold"
|
||||
on:dblclick|stopPropagation
|
||||
on:blur={() => (inputActive = false)}
|
||||
on:keydown={(e) => {
|
||||
if (e.key == 'Enter') {
|
||||
// Unmount input field asynchronously to ensure on:change gets executed.
|
||||
setTimeout(() => (inputActive = false), 0);
|
||||
setTimeout(() => label.focus(), 0);
|
||||
}
|
||||
|
||||
if (e.key == 'Escape') {
|
||||
inputActive = false;
|
||||
name = initialName;
|
||||
setTimeout(() => label.focus(), 0);
|
||||
}
|
||||
}}
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
style={`width: calc(${inputWidth}px + var(--size-12))`}
|
||||
/>
|
||||
{:else}
|
||||
<div
|
||||
bind:this={label}
|
||||
role="textbox"
|
||||
tabindex="0"
|
||||
class="branch-name text-base-13 text-bold truncate"
|
||||
on:keydown={(e) => e.key == 'Enter' && activateInput()}
|
||||
on:mousedown={activateInput}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
{/if}
|
||||
<span
|
||||
use:useResize={(frame) => {
|
||||
inputWidth = `${Math.round(frame.width)}px`;
|
||||
}}
|
||||
class="branch-name-mesure-el text-base-14 text-bold"
|
||||
bind:this={mesureEl}>{name}</span
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
{disabled}
|
||||
bind:this={inputEl}
|
||||
bind:value={name}
|
||||
on:change={(e) => dispatch('change', { name: e.currentTarget.value.trim() })}
|
||||
title={name}
|
||||
class="branch-name-input text-base-14 text-bold"
|
||||
on:dblclick|stopPropagation
|
||||
on:click|stopPropagation={() => {
|
||||
inputEl.focus();
|
||||
}}
|
||||
on:blur={() => {
|
||||
if (name == '') name = initialName;
|
||||
}}
|
||||
on:focus={() => {
|
||||
initialName = name;
|
||||
}}
|
||||
on:keydown={(e) => {
|
||||
if (e.key == 'Enter' || e.key == 'Escape') {
|
||||
inputEl.blur();
|
||||
}
|
||||
}}
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
style:width={inputWidth}
|
||||
/>
|
||||
|
||||
<style lang="postcss">
|
||||
.branch-name,
|
||||
.branch-name-mesure-el,
|
||||
.branch-name-input {
|
||||
min-width: 2.8rem;
|
||||
height: var(--size-20);
|
||||
pointer-events: auto;
|
||||
color: var(--clr-scale-ntrl-0);
|
||||
padding: var(--size-2) var(--size-4);
|
||||
border-radius: var(--radius-s);
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.branch-name {
|
||||
cursor: text;
|
||||
display: inline-block;
|
||||
transition: background-color var(--transition-fast);
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--clr-bg-muted);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.branch-name-mesure-el {
|
||||
pointer-events: auto;
|
||||
visibility: hidden;
|
||||
border: 2px solid transparent;
|
||||
top: 30px;
|
||||
color: black;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
white-space: pre;
|
||||
}
|
||||
.branch-name-input {
|
||||
min-width: 1rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
border-radius: var(--radius-s);
|
||||
color: var(--clr-scale-ntrl-0);
|
||||
background-color: var(--clr-bg-main);
|
||||
outline: none;
|
||||
&:focus {
|
||||
|
||||
/* not readonly */
|
||||
&:not([disabled]):hover {
|
||||
background-color: var(--clr-bg-muted);
|
||||
}
|
||||
|
||||
&:not([disabled]):focus {
|
||||
outline: none;
|
||||
background-color: var(--clr-bg-muted);
|
||||
border-color: var(--clr-border-main);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -22,8 +22,6 @@
|
||||
const branchController = getContext(BranchController);
|
||||
const project = getContext(Project);
|
||||
|
||||
let meatballButton: HTMLDivElement;
|
||||
let container: HTMLDivElement;
|
||||
let isApplying = false;
|
||||
|
||||
function updateContextMenu(copyablePrUrl: string) {
|
||||
@ -44,11 +42,9 @@
|
||||
</script>
|
||||
|
||||
<div class="header__wrapper">
|
||||
<div class="header card" bind:this={container}>
|
||||
<div class="header card">
|
||||
<div class="header__info">
|
||||
<div class="header__label">
|
||||
<BranchLabel bind:name={branch.name} />
|
||||
</div>
|
||||
<BranchLabel disabled bind:name={branch.name} />
|
||||
<div class="header__remote-branch">
|
||||
<div
|
||||
class="status-tag text-base-11 text-semibold remote"
|
||||
@ -90,8 +86,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="header__actions">
|
||||
<div class="header__buttons"></div>
|
||||
<div class="relative" bind:this={meatballButton}>
|
||||
<div class="header__buttons">
|
||||
<Button
|
||||
style="ghost"
|
||||
kind="solid"
|
||||
@ -145,15 +140,16 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: margin var(--transition-slow);
|
||||
padding: var(--size-12);
|
||||
padding: var(--size-10);
|
||||
gap: var(--size-10);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header__actions {
|
||||
display: flex;
|
||||
gap: var(--size-4);
|
||||
background: var(--clr-bg-alt);
|
||||
padding: var(--size-14);
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
border-radius: 0 0 var(--radius-m) var(--radius-m);
|
||||
user-select: none;
|
||||
}
|
||||
@ -162,12 +158,6 @@
|
||||
position: relative;
|
||||
gap: var(--size-4);
|
||||
}
|
||||
.header__label {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
gap: var(--size-4);
|
||||
}
|
||||
|
||||
.header__remote-branch {
|
||||
color: var(--clr-scale-ntrl-50);
|
||||
|
@ -2,7 +2,6 @@
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
import { pxToRem } from '$lib/utils/pxToRem';
|
||||
import { tooltip } from '$lib/utils/tooltip';
|
||||
import { onMount } from 'svelte';
|
||||
import type iconsJson from '$lib/icons/icons.json';
|
||||
import type { ComponentColor, ComponentStyleKind } from '$lib/vbranches/types';
|
||||
|
||||
@ -15,9 +14,9 @@
|
||||
export let tabindex = 0;
|
||||
export let type: 'submit' | 'reset' | undefined = undefined;
|
||||
// Layout props
|
||||
export let width: number | undefined = undefined;
|
||||
export let size: 'medium' | 'large' = 'medium';
|
||||
export let reversedDirection: boolean = false;
|
||||
export let width: number | undefined = undefined;
|
||||
export let size: 'tag' | 'button' | 'cta' = 'button';
|
||||
export let wide = false;
|
||||
export let grow = false;
|
||||
export let align: 'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline' | 'auto' = 'auto';
|
||||
@ -32,11 +31,6 @@
|
||||
export let badgeIcon: keyof typeof iconsJson | undefined = undefined;
|
||||
|
||||
const SLOTS = $$props.$$slots;
|
||||
|
||||
onMount(() => {
|
||||
if (!element) return;
|
||||
element.ariaLabel = element.innerText?.trim();
|
||||
});
|
||||
</script>
|
||||
|
||||
<button
|
||||
@ -45,6 +39,7 @@
|
||||
class:wide
|
||||
class:grow
|
||||
class:not-button={clickable}
|
||||
class:fixed-width={!SLOTS}
|
||||
class:is-dropdown={isDropdownChild}
|
||||
style:align-self={align}
|
||||
style:width={width ? pxToRem(width) : undefined}
|
||||
@ -153,9 +148,9 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-flex;
|
||||
padding: 0 var(--size-2);
|
||||
}
|
||||
|
||||
/* BADGE */
|
||||
@ -221,7 +216,7 @@
|
||||
|
||||
&:not(.not-button, &:disabled):hover {
|
||||
--btn-clr: var(--clr-scale-ntrl-20);
|
||||
--btn-bg: oklch(from var(--clr-core-ntrl-60) l c h / 0.15);
|
||||
--btn-bg: var(--clr-bg-muted);
|
||||
}
|
||||
|
||||
& .badge {
|
||||
@ -355,18 +350,43 @@
|
||||
|
||||
/* SIZE MODIFIERS */
|
||||
|
||||
.btn.medium {
|
||||
height: var(--size-control-button);
|
||||
min-width: var(--size-control-button);
|
||||
padding: var(--size-4) var(--size-6);
|
||||
.btn.tag {
|
||||
height: var(--size-control-tag);
|
||||
min-width: var(--size-control-tag);
|
||||
padding: var(--size-2) var(--size-4);
|
||||
}
|
||||
|
||||
.btn.large {
|
||||
.btn.button {
|
||||
height: var(--size-control-button);
|
||||
min-width: var(--size-control-button);
|
||||
padding: var(--size-4) var(--size-8);
|
||||
}
|
||||
|
||||
.btn.cta {
|
||||
height: var(--size-control-cta);
|
||||
min-width: var(--size-control-cta);
|
||||
padding: var(--size-6) var(--size-8);
|
||||
}
|
||||
|
||||
/* FIXED WIDTH */
|
||||
|
||||
.btn.fixed-width {
|
||||
&.tag {
|
||||
width: var(--size-control-tag);
|
||||
padding: var(--size-2);
|
||||
}
|
||||
|
||||
&.button {
|
||||
width: var(--size-control-button);
|
||||
padding: var(--size-4);
|
||||
}
|
||||
|
||||
&.cta {
|
||||
width: var(--size-control-cta);
|
||||
padding: var(--size-6);
|
||||
}
|
||||
}
|
||||
|
||||
/* DROPDOWN */
|
||||
.is-dropdown {
|
||||
&:first-of-type {
|
||||
|
@ -19,7 +19,7 @@
|
||||
import { splitMessage } from '$lib/utils/commitMessage';
|
||||
import { getContext, getContextStore } from '$lib/utils/context';
|
||||
import { tooltip } from '$lib/utils/tooltip';
|
||||
import { setAutoHeight } from '$lib/utils/useAutoHeight';
|
||||
import { useAutoHeight } from '$lib/utils/useAutoHeight';
|
||||
import { useResize } from '$lib/utils/useResize';
|
||||
import { BranchController } from '$lib/vbranches/branchController';
|
||||
import { Ownership } from '$lib/vbranches/ownership';
|
||||
@ -69,8 +69,8 @@
|
||||
}
|
||||
|
||||
function updateHeights() {
|
||||
setAutoHeight(titleTextArea);
|
||||
setAutoHeight(descriptionTextArea);
|
||||
useAutoHeight(titleTextArea);
|
||||
useAutoHeight(descriptionTextArea);
|
||||
}
|
||||
|
||||
async function commit() {
|
||||
@ -148,9 +148,9 @@
|
||||
bind:this={titleTextArea}
|
||||
use:focusTextareaOnMount
|
||||
use:useResize={() => {
|
||||
setAutoHeight(titleTextArea);
|
||||
useAutoHeight(titleTextArea);
|
||||
}}
|
||||
on:focus={(e) => setAutoHeight(e.currentTarget)}
|
||||
on:focus={(e) => useAutoHeight(e.currentTarget)}
|
||||
on:input={(e) => {
|
||||
$commitMessage = concatMessage(e.currentTarget.value, description);
|
||||
}}
|
||||
@ -172,8 +172,8 @@
|
||||
spellcheck="false"
|
||||
rows="1"
|
||||
bind:this={descriptionTextArea}
|
||||
use:useResize={() => setAutoHeight(descriptionTextArea)}
|
||||
on:focus={(e) => setAutoHeight(e.currentTarget)}
|
||||
use:useResize={() => useAutoHeight(descriptionTextArea)}
|
||||
on:focus={(e) => useAutoHeight(e.currentTarget)}
|
||||
on:input={(e) => {
|
||||
$commitMessage = concatMessage(title, e.currentTarget.value);
|
||||
}}
|
||||
@ -182,7 +182,7 @@
|
||||
if (e.key == 'Backspace' && value.length == 0) {
|
||||
e.preventDefault();
|
||||
titleTextArea.focus();
|
||||
setAutoHeight(e.currentTarget);
|
||||
useAutoHeight(e.currentTarget);
|
||||
} else if (e.key == 'a' && (e.metaKey || e.ctrlKey) && value.length == 0) {
|
||||
// select previous textarea on cmd+a if this textarea is empty
|
||||
e.preventDefault();
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import FileStatusTag from './FileStatusTag.svelte';
|
||||
import Tag from './Tag.svelte';
|
||||
import IconButton from '$lib/components/IconButton.svelte';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import { getVSIFileIcon } from '$lib/ext-icons';
|
||||
import { computeFileStatus } from '$lib/utils/fileStatus';
|
||||
import { computeAddedRemovedByFiles } from '$lib/utils/metrics';
|
||||
@ -66,7 +66,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<IconButton icon="cross" size="m" on:click={() => dispatch('close')} />
|
||||
<Button icon="cross" style="ghost" on:click={() => dispatch('close')} />
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Button from './Button.svelte';
|
||||
import AccountLink from '$lib/components/AccountLink.svelte';
|
||||
import IconButton from '$lib/components/IconButton.svelte';
|
||||
import * as events from '$lib/utils/events';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
@ -10,19 +10,19 @@
|
||||
|
||||
<div class="footer" class:collapsed={isNavCollapsed}>
|
||||
<div class="left-btns">
|
||||
<IconButton
|
||||
<Button
|
||||
icon="mail"
|
||||
help="Send feedback"
|
||||
size="l"
|
||||
width={isNavCollapsed ? '100%' : undefined}
|
||||
style="ghost"
|
||||
size="cta"
|
||||
on:mousedown={() => events.emit('openSendIssueModal')}
|
||||
wide={isNavCollapsed}
|
||||
/>
|
||||
<IconButton
|
||||
<Button
|
||||
icon="settings"
|
||||
help="Project settings"
|
||||
size="l"
|
||||
width={isNavCollapsed ? '100%' : undefined}
|
||||
style="ghost"
|
||||
size="cta"
|
||||
on:mousedown={async () => goto(`/${projectId}/settings`)}
|
||||
wide={isNavCollapsed}
|
||||
/>
|
||||
</div>
|
||||
<AccountLink {isNavCollapsed} />
|
||||
|
@ -44,7 +44,7 @@
|
||||
toasts.success('GitHub authenticated');
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
toasts.success('GitHub authentication failed');
|
||||
toasts.error('GitHub authentication failed');
|
||||
} finally {
|
||||
loading = false;
|
||||
gitHubOauthModal.close();
|
||||
|
@ -1,65 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
import { tooltip } from '$lib/utils/tooltip';
|
||||
import type iconsJson from '$lib/icons/icons.json';
|
||||
|
||||
export let icon: keyof typeof iconsJson;
|
||||
export let size: 's' | 'm' | 'l' = 'l';
|
||||
export let loading = false;
|
||||
export let help = '';
|
||||
export let width: string | undefined = undefined;
|
||||
|
||||
let className = '';
|
||||
let selected = false;
|
||||
export { className as class };
|
||||
export let title = '';
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="icon-btn {className} size-{size}"
|
||||
class:selected
|
||||
use:tooltip={help}
|
||||
{title}
|
||||
on:click
|
||||
on:mousedown
|
||||
style:width
|
||||
>
|
||||
<Icon name={loading ? 'spinner' : icon} />
|
||||
</button>
|
||||
|
||||
<style lang="postcss">
|
||||
.icon-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-m);
|
||||
color: var(--clr-scale-ntrl-50);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color var(--transition-fast),
|
||||
color var(--transition-fast);
|
||||
&:not(.selected):hover {
|
||||
background-color: var(--clr-bg-muted);
|
||||
color: var(--clr-scale-ntrl-40);
|
||||
}
|
||||
}
|
||||
.selected {
|
||||
background-color: var(--clr-bg-muted);
|
||||
cursor: default;
|
||||
}
|
||||
.size-l {
|
||||
height: var(--size-control-cta);
|
||||
width: var(--size-control-cta);
|
||||
padding: var(--size-8);
|
||||
}
|
||||
.size-m {
|
||||
height: var(--size-control-button);
|
||||
width: var(--size-control-button);
|
||||
padding: var(--size-4);
|
||||
}
|
||||
.size-s {
|
||||
height: var(--size-control-tag);
|
||||
width: var(--size-control-tag);
|
||||
padding: var(--size-2);
|
||||
}
|
||||
</style>
|
@ -52,7 +52,7 @@
|
||||
tabindex="0"
|
||||
use:recordDimensions
|
||||
use:clickOutside={{ handler: () => onDismiss() }}
|
||||
style="position: absolute; top:{pos.y}px; left:{pos.x}px"
|
||||
style="z-index: var(--z-floating); position: absolute; top:{pos.y}px; left:{pos.x}px"
|
||||
>
|
||||
<slot {item} dismiss={onDismiss} />
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import IconButton from './IconButton.svelte';
|
||||
import Button from './Button.svelte';
|
||||
import InfoMessage from './InfoMessage.svelte';
|
||||
import MergeButton from './MergeButton.svelte';
|
||||
import Tag from './Tag.svelte';
|
||||
@ -245,9 +245,11 @@
|
||||
{@const pr = $pr$}
|
||||
<div class="card pr-card">
|
||||
<div class="floating-button">
|
||||
<IconButton
|
||||
<Button
|
||||
icon="update-small"
|
||||
size="m"
|
||||
size="tag"
|
||||
style="ghost"
|
||||
kind="soft"
|
||||
loading={isFetchingDetails || isFetchingChecks}
|
||||
help={$lastDetailsFetch ? 'Updated ' + $lastDetailsFetch : ''}
|
||||
on:click={async () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import SupportersBanner from './SupportersBanner.svelte';
|
||||
import IconButton from '../IconButton.svelte';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
import { UserService } from '$lib/stores/user';
|
||||
import { getContext } from '$lib/utils/context';
|
||||
@ -31,9 +31,10 @@
|
||||
<div class="profile-sidebar__menu-wrapper">
|
||||
<div class="profile-sidebar__header">
|
||||
<div class="back-btn__icon">
|
||||
<IconButton
|
||||
<Button
|
||||
icon="chevron-left"
|
||||
size="m"
|
||||
style="ghost"
|
||||
kind="soft"
|
||||
on:mousedown={() => {
|
||||
if (history.length > 0) {
|
||||
history.back();
|
||||
|
@ -13,6 +13,7 @@ export function computeFileStatus(file: AnyFile): FileStatus {
|
||||
}
|
||||
return 'M';
|
||||
}
|
||||
|
||||
if (file.hunks.length == 1) {
|
||||
const changeType = file.hunks[0].changeType;
|
||||
if (changeType == 'added') {
|
||||
|
@ -39,7 +39,7 @@ export function tooltip(node: HTMLElement, optsOrString: ToolTipOptions | string
|
||||
|
||||
function onMouseLeave() {
|
||||
// If tooltip shown when mouse out then we hide after delay
|
||||
if (tooltip) hideAfterDelay();
|
||||
if (tooltip) hide();
|
||||
// But if we mouse out before tooltip is shown, we cancel the show timer
|
||||
else if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
@ -63,13 +63,6 @@ export function tooltip(node: HTMLElement, optsOrString: ToolTipOptions | string
|
||||
timeoutId = undefined;
|
||||
}
|
||||
|
||||
function hideAfterDelay() {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
timeoutId = setTimeout(() => hide(), 250);
|
||||
}
|
||||
|
||||
function adjustPosition() {
|
||||
if (!tooltip) return;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
export function setAutoHeight(element: HTMLTextAreaElement) {
|
||||
export function useAutoHeight(element: HTMLTextAreaElement) {
|
||||
if (!element) return;
|
||||
element.style.height = 'auto';
|
||||
element.style.height = `${element.scrollHeight + 2}px`;
|
||||
element.style.height = `${element.scrollHeight}px`;
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
export function useResize(element: HTMLElement, callback: (width: number, height: number) => void) {
|
||||
export function useResize(
|
||||
element: HTMLElement,
|
||||
callback: (frame: { width: number; height: number }) => void
|
||||
) {
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const { width, height } = entry.contentRect;
|
||||
const { inlineSize, blockSize } = entry.borderBoxSize[0];
|
||||
|
||||
callback(width, height);
|
||||
callback({
|
||||
width: Math.round(inlineSize),
|
||||
height: Math.round(blockSize)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
import { onMount, setContext } from 'svelte';
|
||||
import { Toaster } from 'svelte-french-toast';
|
||||
import type { LayoutData } from './$types';
|
||||
import { dev } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export let data: LayoutData;
|
||||
@ -71,7 +72,12 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<div data-tauri-drag-region class="app-root">
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
class="app-root"
|
||||
role="application"
|
||||
on:contextmenu={(e) => !dev && e.preventDefault()}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
<Toaster />
|
||||
|
@ -28,6 +28,7 @@
|
||||
--z-ground: 1;
|
||||
--z-lifted: 2;
|
||||
--z-floating: 3;
|
||||
--z-tooltip: 4;
|
||||
--z-blocker: 10;
|
||||
|
||||
/* TODO: add focus color */
|
||||
|
@ -6,10 +6,24 @@
|
||||
color: var(--clr-core-ntrl-60);
|
||||
display: inline-block;
|
||||
padding: var(--size-6);
|
||||
z-index: var(--z-floating);
|
||||
z-index: var(--z-tooltip);
|
||||
|
||||
max-width: 11.25rem;
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
top: -9999px;
|
||||
|
||||
opacity: 0;
|
||||
animation: showup-tooltip-animation 0.1s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes showup-tooltip-animation {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-0.2rem) scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user