Added project avatar

This commit is contained in:
Pavel Laptev 2024-02-28 13:07:48 +01:00 committed by Mattias Granlund
parent ada64ac160
commit 40cc56db9b
3 changed files with 145 additions and 62 deletions

View File

@ -8,7 +8,7 @@
import { navCollapsed } from '$lib/config/config'; import { navCollapsed } from '$lib/config/config';
import { persisted } from '$lib/persisted/persisted'; import { persisted } from '$lib/persisted/persisted';
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/settings/userSettings'; import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/settings/userSettings';
import { platform } from '@tauri-apps/api/os'; import { type Platform, platform } from '@tauri-apps/api/os';
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import type { User } from '$lib/backend/cloud'; import type { User } from '$lib/backend/cloud';
import type { Project, ProjectService } from '$lib/backend/projects'; import type { Project, ProjectService } from '$lib/backend/projects';
@ -41,11 +41,12 @@
$: isNavCollapsedPersist = navCollapsed(); $: isNavCollapsedPersist = navCollapsed();
let isNavCollapsed = $isNavCollapsedPersist; let isNavCollapsed = $isNavCollapsedPersist;
// Detect is the platform is Mac // Detect is the platform
let isMacos = false; let platformName: Platform | undefined;
platform().then((name) => { platform().then((name) => {
isMacos = name === 'darwin'; platformName = name;
console.log('platformName:', platformName);
}); });
// check if resizing // check if resizing
@ -96,24 +97,29 @@
{#if isNavCollapsed} {#if isNavCollapsed}
<div class="collapsed-nav-wrapper"> <div class="collapsed-nav-wrapper">
<div class="card collapsed-nav"> {#if platformName}
<div class="collapsed-nav__info"> {#if platformName === 'darwin'}
<h3 class="collapsed-nav__label text-base-13 text-bold"> <div class="drag-region" data-tauri-drag-region />
{project?.title} {/if}
</h3> <div class="card collapsed-nav">
<DomainButton <div class="collapsed-nav__info">
href={`/${project.id}/board`} <h3 class="collapsed-nav__label text-base-13 text-bold">
domain="workspace" {project?.title}
{branchController} </h3>
{baseBranchService} <DomainButton
{isNavCollapsed} href={`/${project.id}/board`}
></DomainButton> domain="workspace"
<BaseBranchCard {project} {baseBranchService} {githubService} {isNavCollapsed} /> {branchController}
{baseBranchService}
{isNavCollapsed}
></DomainButton>
<BaseBranchCard {project} {baseBranchService} {githubService} {isNavCollapsed} />
</div>
<div class="collapsed-nav__footer">
<Footer {user} projectId={project.id} {isNavCollapsed} />
</div>
</div> </div>
<div class="collapsed-nav__footer"> {/if}
<Footer {user} projectId={project.id} {isNavCollapsed} />
</div>
</div>
</div> </div>
{:else} {:else}
<div <div
@ -123,24 +129,26 @@
role="menu" role="menu"
tabindex="0" tabindex="0"
> >
{#if isMacos} {#if platformName}
<div class="drag-region" data-tauri-drag-region /> {#if platformName === 'darwin'}
{/if} <div class="drag-region" data-tauri-drag-region />
<div class="navigation-top"> {/if}
<ProjectSelector {project} {projectService} /> <div class="navigation-top">
<div class="domains"> <ProjectSelector {project} {projectService} />
<BaseBranchCard {project} {baseBranchService} {githubService} {isNavCollapsed} /> <div class="domains">
<DomainButton <BaseBranchCard {project} {baseBranchService} {githubService} {isNavCollapsed} />
href={`/${project.id}/board`} <DomainButton
domain="workspace" href={`/${project.id}/board`}
{branchController} domain="workspace"
{baseBranchService} {branchController}
{isNavCollapsed} {baseBranchService}
></DomainButton> {isNavCollapsed}
></DomainButton>
</div>
</div> </div>
</div> <Branches projectId={project.id} {branchService} {githubService} />
<Branches projectId={project.id} {branchService} {githubService} /> <Footer {user} projectId={project.id} {isNavCollapsed} />
<Footer {user} projectId={project.id} {isNavCollapsed} /> {/if}
</div> </div>
{/if} {/if}
</aside> </aside>
@ -164,6 +172,7 @@
} }
} }
.navigation { .navigation {
width: 17.5rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative; position: relative;

View File

@ -0,0 +1,69 @@
<script lang="ts">
export let name: string | undefined;
const gradients = [
'#E78D8D',
'#62CDCD',
'#EC90D2',
'#7DC8D8',
'#F1BC55',
'#6B6B4C',
'#9785DE',
'#99CE63',
'#636ECE',
'#5FD2B0'
];
const stringToGradient = (string: string | undefined) => {
if (!string) {
return `linear-gradient(45deg, ${gradients[0][0]} 15%, ${gradients[0][1]} 90%)`;
}
// trim the string, remove all spaces
const trimmedString = string.trim().replace(/\s/g, '');
// this is how we take the first letter. It works with emojies.
const startHash = trimmedString.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
// Covert the hash number into the number we can
const gradient = startHash % gradients.length;
// and return the linear-gradient
return gradients[gradient];
};
const getFirstLetter = (name: string | undefined) => {
if (!name) return '';
return name[0].toUpperCase();
};
$: firstLetter = getFirstLetter(name);
</script>
<div class="project-avatar" style:background-color={stringToGradient(name)}>
<svg class="avatar-letter" viewBox="0 0 24 24">
<text x="50%" y="52%" text-anchor="middle" alignment-baseline="middle">
{firstLetter.toUpperCase()}
</text>
</svg>
</div>
<style>
.project-avatar {
flex-shrink: 0;
width: var(--space-24);
height: var(--space-24);
border-radius: var(--radius-m);
}
.avatar-letter {
width: 100%;
height: 100%;
}
.avatar-letter text {
font-family: 'Inter', sans-serif;
font-weight: 800;
font-size: 16px;
fill: var(--clr-core-ntrl-100);
}
</style>

View File

@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import ProjectAvatar from './ProjectAvatar.svelte';
import ProjectsPopup from './ProjectsPopup.svelte'; import ProjectsPopup from './ProjectsPopup.svelte';
import { clickOutside } from '$lib/clickOutside'; import { clickOutside } from '$lib/clickOutside';
import Icon from '$lib/components/Icon.svelte'; import Icon from '$lib/components/Icon.svelte';
@ -11,43 +12,44 @@
let visible: boolean = false; let visible: boolean = false;
</script> </script>
<div class="wrapper"> <div
<div class="wrapper"
class="relative" use:clickOutside={{
use:clickOutside={{ handler: () => {
handler: () => { popup.hide();
popup.hide(); visible = false;
visible = false; },
}, enabled: visible
enabled: visible }}
>
<button
class="button"
on:click={(e) => {
visible = popup.toggle();
e.preventDefault();
}} }}
> >
<button <ProjectAvatar name={project?.title} />
class="button" <span class="button__label text-base-14 text-bold">{project?.title}</span>
on:click={(e) => { <div class="button__icon">
visible = popup.toggle(); <Icon name="select-chevron" />
e.preventDefault(); </div>
}} </button>
> <ProjectsPopup bind:this={popup} {projectService} />
<span class="button__label text-base-14 text-bold">{project?.title}</span>
<div class="button__icon">
<Icon name="select-chevron" />
</div>
</button>
<ProjectsPopup bind:this={popup} {projectService} />
</div>
</div> </div>
<style lang="postcss"> <style lang="postcss">
.wrapper { .wrapper {
position: relative;
margin-top: var(--space-10); margin-top: var(--space-10);
margin-bottom: var(--space-16); margin-bottom: var(--space-16);
} }
.button { .button {
display: flex; display: flex;
gap: var(--space-10);
width: 100%; width: 100%;
padding: var(--space-12); padding: var(--space-10);
border-radius: var(--radius-m); border-radius: var(--radius-m);
background-color: var(--clr-theme-container-pale); background-color: var(--clr-theme-container-pale);
@ -75,6 +77,9 @@
flex-grow: 1; flex-grow: 1;
color: var(--clr-theme-scale-ntrl-0); color: var(--clr-theme-scale-ntrl-0);
text-align: left; text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
.button__icon { .button__icon {