sort out lint/format setup

This commit is contained in:
Nikita Galaiko 2023-02-24 10:46:41 +01:00
parent 894e31881d
commit d80c96ce80
No known key found for this signature in database
GPG Key ID: EBAB54E845BA519D
49 changed files with 2299 additions and 2747 deletions

18
.eslintignore Normal file
View File

@ -0,0 +1,18 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
# Ignore not svelte dirs
/.github
/.vscode
/src-tauri

20
.eslintrc.cjs Normal file
View File

@ -0,0 +1,20 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
}
};

View File

@ -1,21 +0,0 @@
{
"env": {
"es2022": true
},
"extends": [
"plugin:unicorn/recommended",
"plugin:prettier/recommended",
"plugin:svelte/recommended",
],
"plugins": [
"unicorn",
"prettier",
],
"overrides": [
{
"files": ["*.svelte"],
"processor": "svelte3/svelte3"
}
],
"root": true
}

18
.prettierignore Normal file
View File

@ -0,0 +1,18 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
# Ignore not svelte dirs
/.github
/.vscode
/src-tauri

9
.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

View File

@ -1,8 +0,0 @@
{
"tabWidth": 4,
"plugins": [
"prettier-plugin-svelte",
"prettier-plugin-tailwindcss"
],
"pluginSearchDirs": false
}

View File

@ -6,9 +6,10 @@
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write .",
"tauri": "tauri"
},
"dependencies": {
@ -35,19 +36,17 @@
"@tauri-apps/cli": "^1.2.2",
"@types/diff": "^5.0.2",
"autoprefixer": "^10.4.7",
"eslint": "^8.34.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-svelte": "^2.18.0",
"eslint-plugin-unicorn": "^45.0.2",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte3": "^4.0.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.8.1",
"postcss": "^8.4.14",
"postcss-load-config": "^4.0.1",
"prettier": "^2.8.4",
"prettier-plugin-svelte": "^2.9.0",
"prettier-plugin-tailwindcss": "^0.2.2",
"svelte": "^3.55.1",
"svelte-check": "^3.0.0",
"svelte-preprocess": "^4.10.7",
"svelte-check": "^3.0.1",
"tailwindcss": "^3.1.5",
"tslib": "^2.4.1",
"typescript": "^4.8.4",

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
const tailwindcss = require("tailwindcss");
const autoprefixer = require("autoprefixer");
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer,
],
autoprefixer
]
};
module.exports = config;

View File

@ -1,4 +1,4 @@
@import "inter-ui/inter.css";
@import 'inter-ui/inter.css';
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -1,8 +1,8 @@
import { PUBLIC_API_BASE_URL } from "$env/static/public";
import * as log from "$lib/log";
import { nanoid } from "nanoid";
import { PUBLIC_API_BASE_URL } from '$env/static/public';
import * as log from '$lib/log';
import { nanoid } from 'nanoid';
const apiUrl = new URL("/api/", new URL(PUBLIC_API_BASE_URL));
const apiUrl = new URL('/api/', new URL(PUBLIC_API_BASE_URL));
const getUrl = (path: string) => new URL(path, apiUrl).toString();
@ -36,9 +36,7 @@ const parseResponseJSON = async (response: Response) => {
if (response.status === 204 || response.status === 205) {
return null;
} else if (response.status >= 400) {
throw new Error(
`HTTP Error ${response.statusText}: ${await response.text()}`
);
throw new Error(`HTTP Error ${response.statusText}: ${await response.text()}`);
} else {
return await response.json();
}
@ -46,36 +44,34 @@ const parseResponseJSON = async (response: Response) => {
type FetchMiddleware = (f: typeof fetch) => typeof fetch;
const fetchWith = (
fetch: typeof window.fetch,
...middlewares: FetchMiddleware[]
) => middlewares.reduce((f, middleware) => middleware(f), fetch);
const fetchWith = (fetch: typeof window.fetch, ...middlewares: FetchMiddleware[]) =>
middlewares.reduce((f, middleware) => middleware(f), fetch);
const withRequestId: FetchMiddleware = (fetch) => async (url, options) => {
const requestId = nanoid();
if (!options) options = {};
options.headers = {
...options?.headers,
"X-Request-Id": requestId,
'X-Request-Id': requestId
};
return fetch(url, options);
};
const withLog: FetchMiddleware = (fetch) => async (url, options) => {
log.info("fetch", url, options);
log.info('fetch', url, options);
try {
const resp = await fetch(url, options);
log.info(resp);
return resp;
} catch (e: any) {
log.error("fetch", e);
log.error('fetch', e);
throw e;
}
};
export default (
{ fetch: realFetch }: { fetch: typeof window.fetch } = {
fetch: window.fetch,
fetch: window.fetch
}
) => {
const fetch = fetchWith(realFetch, withRequestId, withLog);
@ -83,12 +79,12 @@ export default (
login: {
token: {
create: (params: {} = {}): Promise<LoginToken> =>
fetch(getUrl("login/token.json"), {
method: "POST",
fetch(getUrl('login/token.json'), {
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json'
},
body: JSON.stringify(params),
body: JSON.stringify(params)
})
.then(parseResponseJSON)
.then((token) => {
@ -96,79 +92,73 @@ export default (
url.host = apiUrl.host;
return {
...token,
url: url.toString(),
url: url.toString()
};
}),
})
},
user: {
get: (token: string): Promise<User> =>
fetch(getUrl(`login/user/${token}.json`), {
method: "GET",
}).then(parseResponseJSON),
},
method: 'GET'
}).then(parseResponseJSON)
}
},
user: {
get: async (token: string): Promise<User> =>
fetch(getUrl(`user.json`), {
method: "GET",
method: 'GET',
headers: {
"X-Auth-Token": token,
},
'X-Auth-Token': token
}
}).then(parseResponseJSON),
update: async (
token: string,
params: { name?: string; picture?: File }
) => {
update: async (token: string, params: { name?: string; picture?: File }) => {
const formData = new FormData();
if (params.name) {
formData.append("name", params.name);
formData.append('name', params.name);
}
if (params.picture) {
formData.append("avatar", params.picture);
formData.append('avatar', params.picture);
}
return fetch(getUrl(`user.json`), {
method: "PUT",
method: 'PUT',
headers: {
"X-Auth-Token": token,
'X-Auth-Token': token
},
body: formData,
body: formData
}).then(parseResponseJSON);
},
}
},
projects: {
create: (
token: string,
params: { name: string; uid?: string }
): Promise<Project> =>
fetch(getUrl("projects.json"), {
method: "POST",
create: (token: string, params: { name: string; uid?: string }): Promise<Project> =>
fetch(getUrl('projects.json'), {
method: 'POST',
headers: {
"Content-Type": "application/json",
"X-Auth-Token": token,
'Content-Type': 'application/json',
'X-Auth-Token': token
},
body: JSON.stringify(params),
body: JSON.stringify(params)
}).then(parseResponseJSON),
list: (token: string): Promise<Project[]> =>
fetch(getUrl("projects.json"), {
method: "GET",
fetch(getUrl('projects.json'), {
method: 'GET',
headers: {
"X-Auth-Token": token,
},
'X-Auth-Token': token
}
}).then(parseResponseJSON),
get: (token: string, repositoryId: string): Promise<Project> =>
fetch(getUrl(`projects/${repositoryId}.json`), {
method: "GET",
method: 'GET',
headers: {
"X-Auth-Token": token,
},
'X-Auth-Token': token
}
}).then(parseResponseJSON),
delete: (token: string, repositoryId: string): Promise<void> =>
fetch(getUrl(`projects/${repositoryId}.json`), {
method: "DELETE",
method: 'DELETE',
headers: {
"X-Auth-Token": token,
},
}).then(parseResponseJSON),
},
'X-Auth-Token': token
}
}).then(parseResponseJSON)
}
};
};

View File

@ -1,3 +1,3 @@
export const toHumanBranchName = (branch: string) => {
return branch.replace("refs/heads/", "");
return branch.replace('refs/heads/', '');
};

View File

@ -1,18 +1,14 @@
<script>
import FaArrowLeft from "svelte-icons/fa/FaArrowLeft.svelte";
import FaArrowRight from "svelte-icons/fa/FaArrowRight.svelte";
import FaArrowLeft from 'svelte-icons/fa/FaArrowLeft.svelte';
import FaArrowRight from 'svelte-icons/fa/FaArrowRight.svelte';
let history = window.history;
</script>
<div class="flex items-center justify-center space-x-3 text-zinc-400">
<button
class="w-4 h-4 hover:text-zinc-200"
title="Go back"
on:click={() => history.back()}><FaArrowLeft /></button
<button class="w-4 h-4 hover:text-zinc-200" title="Go back" on:click={() => history.back()}
><FaArrowLeft /></button
>
<button
class="w-4 h-4 hover:text-zinc-200"
title="Go forward"
on:click={() => history.forward()}><FaArrowRight /></button
<button class="w-4 h-4 hover:text-zinc-200" title="Go forward" on:click={() => history.forward()}
><FaArrowRight /></button
>
</div>

View File

@ -1,19 +1,17 @@
<script lang="ts">
import type { Project } from "$lib/projects";
import type { Session } from "$lib/sessions";
import { toHumanReadableTime } from "$lib/time";
import { getContext } from "svelte";
import type { Writable } from "svelte/store";
import IoIosBowtie from "svelte-icons/io/IoIosBowtie.svelte";
import MdKeyboardArrowRight from "svelte-icons/md/MdKeyboardArrowRight.svelte";
import type { Project } from '$lib/projects';
import type { Session } from '$lib/sessions';
import { toHumanReadableTime } from '$lib/time';
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import IoIosBowtie from 'svelte-icons/io/IoIosBowtie.svelte';
import MdKeyboardArrowRight from 'svelte-icons/md/MdKeyboardArrowRight.svelte';
let project: Writable<Project | null | undefined> = getContext("project");
let session: Writable<Session | null | undefined> = getContext("session");
let project: Writable<Project | null | undefined> = getContext('project');
let session: Writable<Session | null | undefined> = getContext('session');
</script>
<div
class="flex flex-row items-center space-x-1 bg-zinc-900 text-zinc-400 h-8"
>
<div class="flex flex-row items-center space-x-1 bg-zinc-900 text-zinc-400 h-8">
<a class="hover:text-zinc-200" href="/">
<div class="w-6 h-6">
<IoIosBowtie />
@ -23,18 +21,13 @@
<div class="w-8 h-8 text-zinc-700">
<MdKeyboardArrowRight />
</div>
<a class="hover:text-zinc-200" href="/projects/{$project.id}"
>{$project.title}</a
>
<a class="hover:text-zinc-200" href="/projects/{$project.id}">{$project.title}</a>
{/if}
{#if $project && $session}
<div class="w-8 h-8 text-zinc-700">
<MdKeyboardArrowRight />
</div>
<a
class="hover:text-zinc-200"
href="/projects/{$project.id}/sessions/{$session.id}"
>
<a class="hover:text-zinc-200" href="/projects/{$project.id}/sessions/{$session.id}">
{toHumanReadableTime($session.meta.startTimestampMs)}
{toHumanReadableTime($session.meta.lastTimestampMs)}
</a>

View File

@ -1,34 +1,34 @@
<script lang="ts">
import { onMount, onDestroy } from "svelte";
import { EditorState } from "@codemirror/state";
import { EditorView, lineNumbers } from "@codemirror/view";
import { onMount, onDestroy } from 'svelte';
import { EditorState } from '@codemirror/state';
import { EditorView, lineNumbers } from '@codemirror/view';
let editorTheme = EditorView.theme(
{
"&": {
color: "#d4d4d8",
backgroundColor: "#18181b",
'&': {
color: '#d4d4d8',
backgroundColor: '#18181b'
},
".cm-content": {
caretColor: "#0e9",
'.cm-content': {
caretColor: '#0e9'
},
"&.cm-focused .cm-cursor": {
borderLeftColor: "#0e9",
'&.cm-focused .cm-cursor': {
borderLeftColor: '#0e9'
},
"&.cm-focused .cm-selectionBackground, ::selection": {
backgroundColor: "#0284c7",
},
".cm-gutters": {
backgroundColor: "#18181b",
color: "#3f3f46",
border: "none",
'&.cm-focused .cm-selectionBackground, ::selection': {
backgroundColor: '#0284c7'
},
'.cm-gutters': {
backgroundColor: '#18181b',
color: '#3f3f46',
border: 'none'
}
},
{ dark: true }
);
const fixedHeightEditor = EditorView.theme({
"&": { height: "600px" },
".cm-scroller": { overflow: "auto" },
'&': { height: '600px' },
'.cm-scroller': { overflow: 'auto' }
});
export let value: string;
@ -47,19 +47,17 @@
editorView = create_editor_view(value);
}
function create_editor_state(
value: string | null | undefined
): EditorState {
function create_editor_state(value: string | null | undefined): EditorState {
return EditorState.create({
doc: value ?? undefined,
extensions: state_extensions,
extensions: state_extensions
});
}
function create_editor_view(value: string): EditorView {
return new EditorView({
state: create_editor_state(value),
parent: element,
parent: element
});
}
@ -68,7 +66,7 @@
EditorView.lineWrapping,
lineNumbers(),
editorTheme,
fixedHeightEditor,
fixedHeightEditor
];
</script>

View File

@ -1,9 +1,9 @@
<script lang="ts">
import type Users from "$lib/users";
import type Api from "$lib/api";
import type { LoginToken } from "$lib/api";
import { derived, writable } from "svelte/store";
import { open } from "@tauri-apps/api/shell";
import type Users from '$lib/users';
import type Api from '$lib/api';
import type { LoginToken } from '$lib/api';
import { derived, writable } from 'svelte/store';
import { open } from '@tauri-apps/api/shell';
export let user: Awaited<ReturnType<typeof Users>>;
export let api: Awaited<ReturnType<typeof Api>>;
@ -27,25 +27,19 @@
<div>
{#if $user}
<button
class="text-zinc-400 hover:underline"
on:click={() => user.delete()}>Log out</button
>
<button class="text-zinc-400 hover:underline" on:click={() => user.delete()}>Log out</button>
{:else if $token !== null}
{#await Promise.all([open($token.url), pollForUser($token.token)])}
<div>Log in in your system browser</div>
{/await}
<p>
<button class="underline" on:click={() => open($authUrl)}
>Click here</button
>
<button class="underline" on:click={() => open($authUrl)}>Click here</button>
if you are not redirected automatically, you can
</p>
{:else}
<button
class="py-1 px-3 rounded text-white bg-blue-400"
on:click={() => api.login.token.create().then(token.set)}
>Sign up or Log in</button
on:click={() => api.login.token.create().then(token.set)}>Sign up or Log in</button
>
{/if}
</div>

View File

@ -1,4 +1,4 @@
export { default as CodeViewer } from "./CodeViewer.svelte";
export { default as BackForwardButtons } from "./BackForwardButtons.svelte";
export { default as Login } from "./Login.svelte";
export { default as Breadcrumbs } from "./Breadcrumbs.svelte";
export { default as CodeViewer } from './CodeViewer.svelte';
export { default as BackForwardButtons } from './BackForwardButtons.svelte';
export { default as Login } from './Login.svelte';
export { default as Breadcrumbs } from './Breadcrumbs.svelte';

View File

@ -1,29 +1,29 @@
<script lang="ts">
import { themeIcons } from "seti-icons";
import type { Session } from "$lib/sessions";
import { toHumanReadableTime, toHumanReadableDate } from "$lib/time";
import { toHumanBranchName } from "$lib/branch";
import TimelineDaySessionActivities from "./TimelineDaySessionActivities.svelte";
import { list } from "$lib/deltas";
import { themeIcons } from 'seti-icons';
import type { Session } from '$lib/sessions';
import { toHumanReadableTime, toHumanReadableDate } from '$lib/time';
import { toHumanBranchName } from '$lib/branch';
import TimelineDaySessionActivities from './TimelineDaySessionActivities.svelte';
import { list } from '$lib/deltas';
export let session: Session;
export let projectId: string;
const getIcon = themeIcons({
blue: "#268bd2",
grey: "#657b83",
"grey-light": "#839496",
green: "#859900",
orange: "#cb4b16",
pink: "#d33682",
purple: "#6c71c4",
red: "#dc322f",
white: "#fdf6e3",
yellow: "#b58900",
ignore: "#586e75",
blue: '#268bd2',
grey: '#657b83',
'grey-light': '#839496',
green: '#859900',
orange: '#cb4b16',
pink: '#d33682',
purple: '#6c71c4',
red: '#dc322f',
white: '#fdf6e3',
yellow: '#b58900',
ignore: '#586e75'
});
function pathToName(path: string) {
return path.split("/").slice(-1)[0];
return path.split('/').slice(-1)[0];
}
function pathToIconSvg(path: string) {
let name: string = pathToName(path);
@ -32,16 +32,16 @@
}
const colorFromBranchName = (branchName: string) => {
const colors = [
"bg-red-500 border-red-700",
"bg-green-500 border-green-700",
"bg-blue-500 border-blue-700",
"bg-yellow-500 border-yellow-700",
"bg-purple-500 border-purple-700",
"bg-pink-500 border-pink-700",
"bg-indigo-500 border-indigo-700",
"bg-orange-500 border-orange-700",
'bg-red-500 border-red-700',
'bg-green-500 border-green-700',
'bg-blue-500 border-blue-700',
'bg-yellow-500 border-yellow-700',
'bg-purple-500 border-purple-700',
'bg-pink-500 border-pink-700',
'bg-indigo-500 border-indigo-700',
'bg-orange-500 border-orange-700'
];
const hash = branchName.split("").reduce((acc, char) => {
const hash = branchName.split('').reduce((acc, char) => {
return acc + char.charCodeAt(0);
}, 0);
return colors[hash % colors.length];
@ -61,10 +61,7 @@
{toHumanBranchName(session.meta.branch)}
</a>
{#if !session.hash}
<span
class="flex absolute h-3 w-3 top-0 right-0 -mt-1 -mr-1"
title="Current session"
>
<span class="flex absolute h-3 w-3 top-0 right-0 -mt-1 -mr-1" title="Current session">
<span
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-orange-200 opacity-75"
/>
@ -87,15 +84,11 @@
{toHumanReadableDate(session.meta.startTimestampMs)},
{toHumanReadableTime(session.meta.startTimestampMs)}
<div class=" text-zinc-600">
{Math.round(
(session.meta.lastTimestampMs - session.meta.startTimestampMs) /
60 /
1000
)} min
{Math.round((session.meta.lastTimestampMs - session.meta.startTimestampMs) / 60 / 1000)} min
</div>
</div>
<div id="files">
{#await list( { projectId: projectId, sessionId: session.id } ) then deltas}
{#await list({ projectId: projectId, sessionId: session.id }) then deltas}
{#each Object.keys(deltas) as delta}
<div class="flex flex-row w-32 items-center">
<div class="w-6 h-6 text-white fill-blue-400">

View File

@ -1,9 +1,9 @@
<script lang="ts">
import type { Activity } from "$lib/sessions";
import FaSquare from "svelte-icons/fa/FaSquare.svelte";
import FaCircle from "svelte-icons/fa/FaCircle.svelte";
import FaAdjust from "svelte-icons/fa/FaAdjust.svelte";
import FaMapMarker from "svelte-icons/fa/FaMapMarker.svelte";
import type { Activity } from '$lib/sessions';
import FaSquare from 'svelte-icons/fa/FaSquare.svelte';
import FaCircle from 'svelte-icons/fa/FaCircle.svelte';
import FaAdjust from 'svelte-icons/fa/FaAdjust.svelte';
import FaMapMarker from 'svelte-icons/fa/FaMapMarker.svelte';
export let activities: Activity[];
export let sessionStart: number;
@ -15,9 +15,9 @@
return ((time - sessionStart) / sessionDuration) * 100;
};
const toHumanReadableTime = (timestamp: number) => {
return new Date(timestamp).toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
return new Date(timestamp).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: 'numeric'
});
};
</script>
@ -28,30 +28,26 @@
{#each activities as activity}
<div
class="flex -mx-1.5"
style="position:relative; left: {proportionOfTime(
activity.timestampMs
)}%;"
style="position:relative; left: {proportionOfTime(activity.timestampMs)}%;"
>
<div
class="w-3 h-3 text-slate-700 z-50 absolute inset-0"
style=""
title="{activity.type}: {activity.message} at {toHumanReadableTime(
activity.timestampMs
)}"
title="{activity.type}: {activity.message} at {toHumanReadableTime(activity.timestampMs)}"
>
{#if activity.type === "commit"}
{#if activity.type === 'commit'}
<div class="text-sky-500 hover:text-sky-600">
<FaSquare />
</div>
{:else if activity.type === "merge"}
{:else if activity.type === 'merge'}
<div class="text-green-500 hover:text-green-600">
<FaMapMarker />
</div>
{:else if activity.type === "rebase"}
{:else if activity.type === 'rebase'}
<div class="text-orange-500 hover:text-orange-600">
<FaAdjust />
</div>
{:else if activity.type === "push"}
{:else if activity.type === 'push'}
<div class="text-purple-500 hover:text-purple-600">
<FaCircle />
</div>

View File

@ -1 +1 @@
export { default as TimelineDaySession } from "./TimelineDaySession.svelte";
export { default as TimelineDaySession } from './TimelineDaySession.svelte';

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { toHumanBranchName } from "$lib/branch";
import { toHumanBranchName } from '$lib/branch';
export let startTime: Date;
export let endTime: Date;
@ -33,10 +33,7 @@
<li
class="relative mt-px flex col-start-{dateToGridCol(startTime)}"
style="grid-row: {timeToGridRow(startTime)} / span {timeToSpan(
startTime,
endTime
)};"
style="grid-row: {timeToGridRow(startTime)} / span {timeToSpan(startTime, endTime)};"
>
<a
{href}

View File

@ -1 +1 @@
export { default as WeekBlockEntry } from "./WeekBlockEntry.svelte";
export { default as WeekBlockEntry } from './WeekBlockEntry.svelte';

View File

@ -1,7 +1,7 @@
import { log } from "$lib";
import { invoke } from "@tauri-apps/api";
import { appWindow } from "@tauri-apps/api/window";
import { writable, type Readable } from "svelte/store";
import { log } from '$lib';
import { invoke } from '@tauri-apps/api';
import { appWindow } from '@tauri-apps/api/window';
import { writable, type Readable } from 'svelte/store';
export type OperationDelete = { delete: [number, number] };
export type OperationInsert = { insert: [number, string] };
@ -9,13 +9,11 @@ export type OperationInsert = { insert: [number, string] };
export type Operation = OperationDelete | OperationInsert;
export namespace Operation {
export const isDelete = (
operation: Operation
): operation is OperationDelete => "delete" in operation;
export const isDelete = (operation: Operation): operation is OperationDelete =>
'delete' in operation;
export const isInsert = (
operation: Operation
): operation is OperationInsert => "insert" in operation;
export const isInsert = (operation: Operation): operation is OperationInsert =>
'insert' in operation;
}
export type Delta = { timestampMs: number; operations: Operation[] };
@ -26,7 +24,7 @@ type DeltasEvent = {
};
export const list = (params: { projectId: string; sessionId: string }) =>
invoke<Record<string, Delta[]>>("list_deltas", params);
invoke<Record<string, Delta[]>>('list_deltas', params);
export default async (params: { projectId: string; sessionId: string }) => {
const init = await list(params);
@ -37,7 +35,7 @@ export default async (params: { projectId: string; sessionId: string }) => {
log.info(`Received deltas event ${eventName}`);
store.update((deltas) => ({
...deltas,
[event.payload.filePath]: event.payload.deltas,
[event.payload.filePath]: event.payload.deltas
}));
});

View File

@ -1,6 +1,6 @@
export * as deltas from "./deltas";
export * as projects from "./projects";
export * as log from "./log";
export * as toasts from "./toasts";
export * as sessions from "./sessions";
export * as week from "./week";
export * as deltas from './deltas';
export * as projects from './projects';
export * as log from './log';
export * as toasts from './toasts';
export * as sessions from './sessions';
export * as week from './week';

View File

@ -1,39 +1,36 @@
import { building } from "$app/environment";
import { building } from '$app/environment';
export const setup = async () => {
if (!building) {
await (await import("tauri-plugin-log-api")).attachConsole();
await (await import('tauri-plugin-log-api')).attachConsole();
}
};
const logger = async () =>
building
? {
debug: (..._: any[]) => { },
info: (..._: any[]) => { },
error: (..._: any[]) => { },
debug: (..._: any[]) => {},
info: (..._: any[]) => {},
error: (..._: any[]) => {}
}
: import("tauri-plugin-log-api").then((tauri) => ({
: import('tauri-plugin-log-api').then((tauri) => ({
debug: tauri.debug,
info: tauri.info,
error: tauri.error,
error: tauri.error
}));
const toString = (value: any) => {
if (value instanceof Error) {
return value.message;
} else if (typeof value === "object") {
} else if (typeof value === 'object') {
return JSON.stringify(value);
} else {
return value.toString();
}
};
export const debug = async (...args: any[]) =>
(await logger()).debug(args.map(toString).join(" "));
export const debug = async (...args: any[]) => (await logger()).debug(args.map(toString).join(' '));
export const info = async (...args: any[]) =>
(await logger()).info(args.map(toString).join(" "));
export const info = async (...args: any[]) => (await logger()).info(args.map(toString).join(' '));
export const error = async (...args: any[]) =>
(await logger()).error(args.map(toString).join(" "));
export const error = async (...args: any[]) => (await logger()).error(args.map(toString).join(' '));

View File

@ -1,31 +1,31 @@
import posthog from "posthog-js";
import { PUBLIC_POSTHOG_API_KEY } from "$env/static/public";
import type { User } from "$lib/api";
import * as log from "$lib/log";
import posthog from 'posthog-js';
import { PUBLIC_POSTHOG_API_KEY } from '$env/static/public';
import type { User } from '$lib/api';
import * as log from '$lib/log';
export default () => {
const instance = posthog.init(PUBLIC_POSTHOG_API_KEY, {
api_host: "https://eu.posthog.com",
capture_performance: false,
api_host: 'https://eu.posthog.com',
capture_performance: false
});
log.info("posthog initialized");
log.info('posthog initialized');
return {
identify: (user: User | undefined) => {
if (user) {
log.info("posthog identify", {
log.info('posthog identify', {
id: user.id,
name: user.name,
email: user.email,
email: user.email
});
instance?.identify(`user_${user.id}`, {
email: user.email,
name: user.name,
name: user.name
});
} else {
log.info("posthog reset");
instance?.capture("log-out");
log.info('posthog reset');
instance?.capture('log-out');
instance?.reset();
}
},
}
};
};

View File

@ -1,6 +1,6 @@
import { invoke } from "@tauri-apps/api";
import { derived, writable } from "svelte/store";
import type { Project as ApiProject } from "$lib/api";
import { invoke } from '@tauri-apps/api';
import { derived, writable } from 'svelte/store';
import type { Project as ApiProject } from '$lib/api';
export type Project = {
id: string;
@ -9,7 +9,7 @@ export type Project = {
api: ApiProject & { sync: boolean };
};
const list = () => invoke<Project[]>("list_projects");
const list = () => invoke<Project[]>('list_projects');
const update = (params: {
project: {
@ -17,12 +17,11 @@ const update = (params: {
title?: string;
api?: ApiProject & { sync: boolean };
};
}) => invoke<Project>("update_project", params);
}) => invoke<Project>('update_project', params);
const add = (params: { path: string }) =>
invoke<Project>("add_project", params);
const add = (params: { path: string }) => invoke<Project>('add_project', params);
const del = (params: { id: string }) => invoke("delete_project", params);
const del = (params: { id: string }) => invoke('delete_project', params);
export default async () => {
const init = await list();
@ -31,25 +30,19 @@ export default async () => {
return {
subscribe: store.subscribe,
get: (id: string) => {
const project = derived(store, (store) =>
store.find((p) => p.id === id)
);
const project = derived(store, (store) => store.find((p) => p.id === id));
return {
subscribe: project.subscribe,
update: (params: { title?: string; api?: Project["api"] }) =>
update: (params: { title?: string; api?: Project['api'] }) =>
update({
project: {
id,
...params,
},
...params
}
}).then((project) => {
store.update((projects) =>
projects.map((p) =>
p.id === project.id ? project : p
)
);
store.update((projects) => projects.map((p) => (p.id === project.id ? project : p)));
return project;
}),
})
};
},
add: (params: { path: string }) =>
@ -59,9 +52,7 @@ export default async () => {
}),
delete: (params: { id: string }) =>
del(params).then(() => {
store.update((projects) =>
projects.filter((p) => p.id !== params.id)
);
}),
store.update((projects) => projects.filter((p) => p.id !== params.id));
})
};
};

View File

@ -1,7 +1,7 @@
import { invoke } from "@tauri-apps/api";
import { appWindow } from "@tauri-apps/api/window";
import { writable } from "svelte/store";
import { log } from "$lib";
import { invoke } from '@tauri-apps/api';
import { appWindow } from '@tauri-apps/api/window';
import { writable } from 'svelte/store';
import { log } from '$lib';
export type Activity = {
type: string;
@ -22,10 +22,9 @@ export type Session = {
};
export const listFiles = (params: { projectId: string; sessionId: string }) =>
invoke<Record<string, string>>("list_session_files", params);
invoke<Record<string, string>>('list_session_files', params);
const list = (params: { projectId: string }) =>
invoke<Session[]>("list_sessions", params);
const list = (params: { projectId: string }) => invoke<Session[]>('list_sessions', params);
export default async (params: { projectId: string }) => {
const init = await list(params);
@ -35,22 +34,16 @@ export default async (params: { projectId: string }) => {
await appWindow.listen<Session>(eventName, (event) => {
log.info(`Received sessions event ${eventName}`);
store.update((sessions) => {
const index = sessions.findIndex(
(session) => session.id === event.payload.id
);
const index = sessions.findIndex((session) => session.id === event.payload.id);
if (index === -1) {
return [...sessions, event.payload];
} else {
return [
...sessions.slice(0, index),
event.payload,
...sessions.slice(index + 1),
];
return [...sessions.slice(0, index), event.payload, ...sessions.slice(index + 1)];
}
});
});
return {
subscribe: store.subscribe,
subscribe: store.subscribe
};
};

View File

@ -1,12 +1,12 @@
export const toHumanReadableTime = (timestamp: number) => {
return new Date(timestamp).toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
return new Date(timestamp).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: 'numeric'
});
};
export const toHumanReadableDate = (timestamp: number) => {
return new Date(timestamp).toLocaleDateString("en-US", {
dateStyle: "short",
return new Date(timestamp).toLocaleDateString('en-US', {
dateStyle: 'short'
});
};

View File

@ -1,11 +1,8 @@
import toast, {
type ToastOptions,
type ToastPosition,
} from "svelte-french-toast";
import toast, { type ToastOptions, type ToastPosition } from 'svelte-french-toast';
const defaultOptions = {
position: "bottom-center" as ToastPosition,
style: "border-radius: 200px; background: #333; color: #fff;",
position: 'bottom-center' as ToastPosition,
style: 'border-radius: 200px; background: #333; color: #fff;'
};
export const error = (msg: string, options: ToastOptions = {}) =>

View File

@ -1,12 +1,12 @@
import type { User } from "$lib/api";
import { writable } from "svelte/store";
import { invoke } from "@tauri-apps/api";
import type { User } from '$lib/api';
import { writable } from 'svelte/store';
import { invoke } from '@tauri-apps/api';
const get = () => invoke<User | undefined>("get_user");
const get = () => invoke<User | undefined>('get_user');
const set = (params: { user: User }) => invoke<void>("set_user", params);
const set = (params: { user: User }) => invoke<void>('set_user', params);
const del = () => invoke<void>("delete_user");
const del = () => invoke<void>('delete_user');
export default async () => {
const store = writable<User | undefined>(undefined);
@ -22,6 +22,6 @@ export default async () => {
delete: async () => {
await del();
store.set(undefined);
},
}
};
};

View File

@ -1,4 +1,4 @@
import { startOfWeek, endOfWeek, addWeeks, subWeeks, addDays } from "date-fns";
import { startOfWeek, endOfWeek, addWeeks, subWeeks, addDays } from 'date-fns';
export type Week = {
start: Date;
@ -8,7 +8,7 @@ export namespace Week {
export const from = (date: Date): Week => {
return {
start: startOfWeek(date, { weekStartsOn: 1 }),
end: endOfWeek(date),
end: endOfWeek(date)
};
};
export const next = (week: Week): Week => {

View File

@ -1,18 +1,18 @@
<script lang="ts">
import "../app.postcss";
import '../app.postcss';
import { Toaster } from "svelte-french-toast";
import type { LayoutData } from "./$types";
import { BackForwardButtons } from "$lib/components";
import { setContext } from "svelte";
import { writable } from "svelte/store";
import Breadcrumbs from "$lib/components/Breadcrumbs.svelte";
import { Toaster } from 'svelte-french-toast';
import type { LayoutData } from './$types';
import { BackForwardButtons } from '$lib/components';
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
import Breadcrumbs from '$lib/components/Breadcrumbs.svelte';
export let data: LayoutData;
const { user, posthog } = data;
setContext("project", writable(null));
setContext("session", writable(null));
setContext('project', writable(null));
setContext('session', writable(null));
user.subscribe(posthog.identify);
</script>
@ -26,17 +26,10 @@
</div>
<div class="ml-6"><Breadcrumbs /></div>
<div class="flex-grow" />
<a
href="/users/"
class="flex items-center gap-2 mr-4 font-medium hover:text-zinc-200"
>
<a href="/users/" class="flex items-center gap-2 mr-4 font-medium hover:text-zinc-200">
{#if $user}
{#if $user.picture}
<img
class="inline-block w-6 h-6 rounded-full"
src={$user.picture}
alt="Avatar"
/>
<img class="inline-block w-6 h-6 rounded-full" src={$user.picture} alt="Avatar" />
{/if}
<span>{$user.name}</span>
{:else}

View File

@ -1,10 +1,10 @@
import { readable } from "svelte/store";
import type { LayoutLoad } from "./$types";
import { building } from "$app/environment";
import type { Project } from "$lib/projects";
import Api from "$lib/api";
import Posthog from "$lib/posthog";
import * as log from "$lib/log";
import { readable } from 'svelte/store';
import type { LayoutLoad } from './$types';
import { building } from '$app/environment';
import type { Project } from '$lib/projects';
import Api from '$lib/api';
import Posthog from '$lib/posthog';
import * as log from '$lib/log';
export const ssr = false;
export const prerender = true;
@ -15,29 +15,29 @@ export const load: LayoutLoad = async ({ fetch }) => {
? {
...readable<Project[]>([]),
add: () => {
throw new Error("not implemented");
throw new Error('not implemented');
},
get: () => {
throw new Error("not implemented");
},
throw new Error('not implemented');
}
: await (await import("$lib/projects")).default();
}
: await (await import('$lib/projects')).default();
const user = building
? {
...readable<undefined>(undefined),
set: () => {
throw new Error("not implemented");
throw new Error('not implemented');
},
delete: () => {
throw new Error("not implemented");
},
throw new Error('not implemented');
}
: await (await import("$lib/users")).default();
}
: await (await import('$lib/users')).default();
await log.setup();
return {
projects,
user,
api: Api({ fetch }),
posthog: Posthog(),
posthog: Posthog()
};
};

View File

@ -1,7 +1,7 @@
<script lang="ts">
import FaFolderOpen from "svelte-icons/fa/FaFolderOpen.svelte";
import { open } from "@tauri-apps/api/dialog";
import type { LayoutData } from "./$types";
import FaFolderOpen from 'svelte-icons/fa/FaFolderOpen.svelte';
import { open } from '@tauri-apps/api/dialog';
import type { LayoutData } from './$types';
export let data: LayoutData;
const { projects } = data;
@ -9,13 +9,11 @@
const onAddLocalRepositoryClick = async () => {
const selectedPath = await open({
directory: true,
recursive: true,
recursive: true
});
if (selectedPath === null) return;
if (Array.isArray(selectedPath) && selectedPath.length !== 1) return;
const projectPath = Array.isArray(selectedPath)
? selectedPath[0]
: selectedPath;
const projectPath = Array.isArray(selectedPath) ? selectedPath[0] : selectedPath;
const projectExists = $projects.some((p) => p.path === projectPath);
if (projectExists) return;
@ -35,9 +33,8 @@
<div class="text-xl text-zinc-200 mb-1">Start</div>
<div class="flex items-center space-x-2">
<div class="w-4 h-4"><FaFolderOpen /></div>
<button
on:click={onAddLocalRepositoryClick}
class="hover:text-zinc-200">Add a local repository...</button
<button on:click={onAddLocalRepositoryClick} class="hover:text-zinc-200"
>Add a local repository...</button
>
</div>
</div>
@ -46,10 +43,7 @@
<div class="flex flex-col space-y-1">
{#each $projects as project}
<div class="space-x-2">
<a
class="hover:text-zinc-200"
href="/projects/{project.id}/">{project.title}</a
>
<a class="hover:text-zinc-200" href="/projects/{project.id}/">{project.title}</a>
<span class="text-zinc-500">{project.path}</span>
</div>
{/each}

View File

@ -1,10 +1,10 @@
<script lang="ts">
import type { LayoutData } from "./$types";
import { getContext } from "svelte";
import type { Writable } from "svelte/store";
import type { Project } from "$lib/projects";
import { onDestroy } from "svelte";
import { page } from "$app/stores";
import type { LayoutData } from './$types';
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import type { Project } from '$lib/projects';
import { onDestroy } from 'svelte';
import { page } from '$app/stores';
export let data: LayoutData;
@ -17,19 +17,18 @@
// get host from git url
const url = new URL(gitUrl);
const host = url.origin;
const projectId = gitUrl.split("/").pop();
const projectId = gitUrl.split('/').pop();
return `${host}/projects/${projectId}`;
}
const contextProjectStore: Writable<Project | null | undefined> =
getContext("project");
const contextProjectStore: Writable<Project | null | undefined> = getContext('project');
$: contextProjectStore.set($project);
onDestroy(() => {
contextProjectStore.set(null);
});
$: selection = $page?.route?.id?.split("/")?.[3];
$: selection = $page?.route?.id?.split('/')?.[3];
</script>
<nav
@ -48,8 +47,7 @@
href="/projects/{$project?.id}/day"
class="
{selection === 'day' ? 'bg-zinc-600/70 text-zinc-100' : ''}
rounded-lg h-7 flex items-center justify-center p-3 text-center hover:text-zinc-100"
>Day</a
rounded-lg h-7 flex items-center justify-center p-3 text-center hover:text-zinc-100">Day</a
>
<a
href="/projects/{$project?.id}/sessions/{lastSessionId}"
@ -62,10 +60,7 @@
<ul>
<li>
<a
href="/projects/{$project?.id}/settings"
class="text-zinc-400 hover:text-zinc-300"
>
<a href="/projects/{$project?.id}/settings" class="text-zinc-400 hover:text-zinc-300">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -96,27 +91,17 @@
<div
class="flex items-center flex-shrink-0 h-6 border-t select-none border-zinc-700 bg-zinc-900 "
>
<div
class="flex flex-row mx-4 items-center space-x-2 justify-between w-full"
>
<div class="flex flex-row mx-4 items-center space-x-2 justify-between w-full">
{#if $project?.api?.sync}
<a
href="/projects/{$project?.id}/settings"
class="text-zinc-400 hover:text-zinc-300"
>
<a href="/projects/{$project?.id}/settings" class="text-zinc-400 hover:text-zinc-300">
<div class="flex flex-row items-center space-x-2 ">
<div class="w-2 h-2 bg-green-700 rounded-full" />
<div class="text-zinc-200">Syncing</div>
</div>
</a>
<a target="_blank" rel="noreferrer" href={projectUrl($project)}
>Open in GitButler Cloud</a
>
<a target="_blank" rel="noreferrer" href={projectUrl($project)}>Open in GitButler Cloud</a>
{:else}
<a
href="/projects/{$project?.id}/settings"
class="text-zinc-400 hover:text-zinc-300"
>
<a href="/projects/{$project?.id}/settings" class="text-zinc-400 hover:text-zinc-300">
<div class="flex flex-row items-center space-x-2 ">
<div class="w-2 h-2 bg-red-700 rounded-full" />
<div class="text-zinc-200">Offline</div>

View File

@ -1,7 +1,7 @@
import { readable, derived } from "svelte/store";
import type { LayoutLoad } from "./$types";
import { building } from "$app/environment";
import type { Session } from "$lib/sessions";
import { readable, derived } from 'svelte/store';
import type { LayoutLoad } from './$types';
import { building } from '$app/environment';
import type { Session } from '$lib/sessions';
export const prerender = false;
@ -9,16 +9,12 @@ export const load: LayoutLoad = async ({ parent, params }) => {
const { projects } = await parent();
const sessions = building
? readable<Session[]>([])
: await (
await import("$lib/sessions")
).default({ projectId: params.projectId });
: await (await import('$lib/sessions')).default({ projectId: params.projectId });
const orderedSessions = derived(sessions, (sessions) => {
return sessions
.slice()
.sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs);
return sessions.slice().sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs);
});
return {
project: projects.get(params.projectId),
sessions: orderedSessions,
sessions: orderedSessions
};
};

View File

@ -1,5 +1,5 @@
<script lang="ts">
import type { PageData } from "./$types";
import type { PageData } from './$types';
export let data: PageData;
const { project } = data;
@ -10,11 +10,7 @@
Overview of {$project?.title}
</h1>
<div class="flex justify-center space-x-2">
<a class="hover:text-zinc-200" href="/projects/{$project?.id}/week"
>Week</a
>
<a href="/projects/{$project?.id}/day" class="hover:text-zinc-200"
>Day</a
>
<a class="hover:text-zinc-200" href="/projects/{$project?.id}/week">Week</a>
<a href="/projects/{$project?.id}/day" class="hover:text-zinc-200">Day</a>
</div>
</div>

View File

@ -1,22 +1,21 @@
<script lang="ts">
import MdKeyboardArrowLeft from "svelte-icons/md/MdKeyboardArrowLeft.svelte";
import MdKeyboardArrowRight from "svelte-icons/md/MdKeyboardArrowRight.svelte";
import { TimelineDaySession } from "$lib/components/timeline";
import type { PageData } from "./$types";
import type { Session } from "$lib/sessions";
import { derived } from "svelte/store";
import MdKeyboardArrowLeft from 'svelte-icons/md/MdKeyboardArrowLeft.svelte';
import MdKeyboardArrowRight from 'svelte-icons/md/MdKeyboardArrowRight.svelte';
import { TimelineDaySession } from '$lib/components/timeline';
import type { PageData } from './$types';
import type { Session } from '$lib/sessions';
import { derived } from 'svelte/store';
export let data: PageData;
const { project, sessions } = data;
let date = new Date();
$: canNavigateForwad =
new Date(date.getTime() + 24 * 60 * 60 * 1000) < new Date();
$: canNavigateForwad = new Date(date.getTime() + 24 * 60 * 60 * 1000) < new Date();
const formatDate = (date: Date) => {
return new Intl.DateTimeFormat("default", {
weekday: "short",
day: "numeric",
month: "short",
return new Intl.DateTimeFormat('default', {
weekday: 'short',
day: 'numeric',
month: 'short'
}).format(date);
};
@ -24,18 +23,14 @@
let sessionDurationMinutes =
(session.meta.lastTimestampMs - session.meta.startTimestampMs) / 60;
if (sessionDurationMinutes <= 10) {
return "w-40 min-w-40";
return 'w-40 min-w-40';
} else {
return "w-60 min-w-60";
return 'w-60 min-w-60';
}
};
$: sessionsInDay = derived([sessions], ([sessions]) => {
const start = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate()
);
const start = new Date(date.getFullYear(), date.getMonth(), date.getDate());
const end = new Date(start.getTime() + 24 * 60 * 60 * 1000);
return sessions.filter((session) => {
return (
@ -47,14 +42,11 @@
</script>
<div class="flex flex-col h-full select-none text-zinc-400">
<header
class="flex items-center justify-between flex-none px-8 py-1.5 border-b border-zinc-700"
>
<header class="flex items-center justify-between flex-none px-8 py-1.5 border-b border-zinc-700">
<div class="flex items-center justify-start w-64">
<button
class="-ml-2 w-8 h-8 hover:text-zinc-100"
on:click={() =>
(date = new Date(date.getTime() - 24 * 60 * 60 * 1000))}
on:click={() => (date = new Date(date.getTime() - 24 * 60 * 60 * 1000))}
>
<MdKeyboardArrowLeft />
</button>
@ -81,10 +73,7 @@
<div class="justify-center flex flex-row space-x-2 pt-2">
{#each $sessionsInDay as session}
<div class={sessionDisplayWidth(session)}>
<TimelineDaySession
projectId={$project.id}
{session}
/>
<TimelineDaySession projectId={$project.id} {session} />
</div>
{/each}
</div>

View File

@ -1,15 +1,15 @@
<script lang="ts">
import MdKeyboardArrowLeft from "svelte-icons/md/MdKeyboardArrowLeft.svelte";
import MdKeyboardArrowRight from "svelte-icons/md/MdKeyboardArrowRight.svelte";
import type { PageData } from "./$types";
import { add, format, differenceInSeconds, addSeconds } from "date-fns";
import { page } from "$app/stores";
import { onMount } from "svelte";
import { derived } from "svelte/store";
import { Operation } from "$lib/deltas";
import { Slider } from "fluent-svelte";
import { CodeViewer } from "$lib/components";
import "fluent-svelte/theme.css";
import MdKeyboardArrowLeft from 'svelte-icons/md/MdKeyboardArrowLeft.svelte';
import MdKeyboardArrowRight from 'svelte-icons/md/MdKeyboardArrowRight.svelte';
import type { PageData } from './$types';
import { add, format, differenceInSeconds, addSeconds } from 'date-fns';
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { derived } from 'svelte/store';
import { Operation } from '$lib/deltas';
import { Slider } from 'fluent-svelte';
import { CodeViewer } from '$lib/components';
import 'fluent-svelte/theme.css';
export let data: PageData;
$: session = data.session;
@ -19,9 +19,7 @@
let time = new Date();
$: start = new Date($session.meta.startTimestampMs);
$: end = $session.hash
? addSeconds(new Date($session.meta.lastTimestampMs), 10)
: time; // For some reason, some deltas are stamped a few seconds after the session end.
$: end = $session.hash ? addSeconds(new Date($session.meta.lastTimestampMs), 10) : time; // For some reason, some deltas are stamped a few seconds after the session end.
// Also, if the session is current, the end time moves.
onMount(() => {
@ -34,13 +32,13 @@
};
});
$: midpoint = add(start, {
seconds: differenceInSeconds(end, start) * 0.5,
seconds: differenceInSeconds(end, start) * 0.5
});
$: quarter = add(start, {
seconds: differenceInSeconds(end, start) * 0.25,
seconds: differenceInSeconds(end, start) * 0.25
});
$: threequarters = add(start, {
seconds: differenceInSeconds(end, start) * 0.75,
seconds: differenceInSeconds(end, start) * 0.75
});
const timeStampToCol = (deltaTimestamp: Date) => {
if (deltaTimestamp < start || deltaTimestamp > end) {
@ -74,17 +72,15 @@
const filePath = Object.keys(allDeltas)[selectedFileIdx];
const deltas = allDeltas[filePath];
let text = data.files[filePath] || "";
let text = data.files[filePath] || '';
if (!deltas) return text;
const sliderValueTimestampMs =
colToTimestamp(value).getTime() + tickSizeMs; // Include the tick size so that the slider value is always in the future
const sliderValueTimestampMs = colToTimestamp(value).getTime() + tickSizeMs; // Include the tick size so that the slider value is always in the future
// Filter operations based on the current slider value
const operations = deltas
.filter(
(delta) =>
delta.timestampMs >= start.getTime() &&
delta.timestampMs <= sliderValueTimestampMs
delta.timestampMs >= start.getTime() && delta.timestampMs <= sliderValueTimestampMs
)
.sort((a, b) => a.timestampMs - b.timestampMs)
.flatMap((delta) => delta.operations);
@ -106,23 +102,20 @@
});
const formatDate = (date: Date) => {
return new Intl.DateTimeFormat("default", {
weekday: "short",
day: "numeric",
hour: "numeric",
minute: "numeric",
return new Intl.DateTimeFormat('default', {
weekday: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}).format(date);
};
</script>
<div class="flex flex-col h-full text-zinc-400 overflow-hidden">
<header
class="flex items-center justify-between flex-none px-8 py-1.5 border-b border-zinc-700"
>
<header class="flex items-center justify-between flex-none px-8 py-1.5 border-b border-zinc-700">
<div class="flex items-center justify-start w-64">
<a
href="/projects/{$page.params
.projectId}/sessions/{$previousSesssion?.id}"
href="/projects/{$page.params.projectId}/sessions/{$previousSesssion?.id}"
class="-ml-2 w-8 h-8 hover:text-zinc-100 {$previousSesssion
? ''
: 'opacity-50 pointer-events-none cursor-not-allowed'}"
@ -135,8 +128,7 @@
<span class="col-span-3">{formatDate(end)}</span>
</div>
<a
href="/projects/{$page.params
.projectId}/sessions/{$nextSession?.id}"
href="/projects/{$page.params.projectId}/sessions/{$nextSession?.id}"
class="-mr-2 w-8 h-8 hover:text-zinc-100 {$nextSession
? ''
: 'text-zinc-700 pointer-events-none cursor-not-allowed'}"
@ -157,41 +149,29 @@
>
<div class="grid-cols-11 -mr-px border-zinc-700 grid">
<div />
<div
class="col-span-2 flex items-center justify-center py-2"
>
<span>{format(start, "hh:mm")}</span>
<div class="col-span-2 flex items-center justify-center py-2">
<span>{format(start, 'hh:mm')}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-2"
>
<span>{format(quarter, "hh:mm")}</span>
<div class="col-span-2 flex items-center justify-center py-2">
<span>{format(quarter, 'hh:mm')}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-2"
>
<span>{format(midpoint, "hh:mm")}</span>
<div class="col-span-2 flex items-center justify-center py-2">
<span>{format(midpoint, 'hh:mm')}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-2"
>
<span>{format(threequarters, "hh:mm")}</span>
<div class="col-span-2 flex items-center justify-center py-2">
<span>{format(threequarters, 'hh:mm')}</span>
</div>
<div
class="col-span-2 flex items-center justify-center py-2"
>
<span>{format(end, "hh:mm")}</span>
<div class="col-span-2 flex items-center justify-center py-2">
<span>{format(end, 'hh:mm')}</span>
</div>
</div>
<!-- needle -->
<div class="grid grid-cols-11">
<div class="col-span-2 flex items-center justify-center" />
<div
class="-mx-1 col-span-8 flex items-center justify-center"
>
<div class="-mx-1 col-span-8 flex items-center justify-center">
<Slider min={17} max={80} step={1} bind:value>
<svelte:fragment slot="tooltip" let:value>
{format(colToTimestamp(value), "hh:mm")}
{format(colToTimestamp(value), 'hh:mm')}
</svelte:fragment>
</Slider>
</div>
@ -203,17 +183,12 @@
<!-- file names list -->
<div
class="bg-col-start-1 col-end-2 row-start-1 grid divide-y divide-zinc-700/20"
style="grid-template-rows: repeat({Object.keys($deltas)
.length}, minmax(2rem, 1fr));"
style="grid-template-rows: repeat({Object.keys($deltas).length}, minmax(2rem, 1fr));"
>
<!-- <div class="row-end-1 h-7" /> -->
{#each Object.keys($deltas) as filePath, i}
<div
class="flex {i == selectedFileIdx
? 'bg-zinc-500/70'
: ''}"
>
<div class="flex {i == selectedFileIdx ? 'bg-zinc-500/70' : ''}">
<button
class="z-20 flex justify-end items-center overflow-hidden sticky left-0 w-1/6 leading-5
{selectedFileIdx == i
@ -222,7 +197,7 @@
on:click={() => (selectedFileIdx = i)}
title={filePath}
>
{filePath.split("/").pop()}
{filePath.split('/').pop()}
</button>
</div>
{/each}
@ -233,10 +208,7 @@
class="col-start-1 col-end-2 row-start-1 grid"
style="grid-template-columns: repeat(88, minmax(0, 1fr));"
>
<div
class="bg-sky-400/60 "
style=" grid-column: {value};"
/>
<div class="bg-sky-400/60 " style=" grid-column: {value};" />
</div>
<!-- time vertical lines -->
<div
@ -271,9 +243,7 @@
<button
class="z-20 h-full flex flex-col w-full items-center justify-center"
on:click={() => {
value = timeStampToCol(
new Date(delta.timestampMs)
);
value = timeStampToCol(new Date(delta.timestampMs));
selectedFileIdx = idx;
}}
/>

View File

@ -1,34 +1,30 @@
import type { PageLoad } from "./$types";
import { derived, readable } from "svelte/store";
import { building } from "$app/environment";
import type { Delta } from "$lib/deltas";
import type { PageLoad } from './$types';
import { derived, readable } from 'svelte/store';
import { building } from '$app/environment';
import type { Delta } from '$lib/deltas';
export const prerender = false;
export const load: PageLoad = async ({ parent, params }) => {
const { sessions } = await parent();
const deltas = building
? readable({} as Record<string, Delta[]>)
: (await import("$lib/deltas")).default({
: (await import('$lib/deltas')).default({
projectId: params.projectId,
sessionId: params.sessionId,
sessionId: params.sessionId
});
const files = building
? ({} as Record<string, string>)
: (await import("$lib/sessions")).listFiles({
: (await import('$lib/sessions')).listFiles({
projectId: params.projectId,
sessionId: params.sessionId,
sessionId: params.sessionId
});
return {
session: derived(sessions, (sessions) => {
const result = sessions.find(
(session) => session.id === params.sessionId
);
const result = sessions.find((session) => session.id === params.sessionId);
return result ? result : sessions[0];
}),
previousSesssion: derived(sessions, (sessions) => {
const currentSessionIndex = sessions.findIndex(
(session) => session.id === params.sessionId
);
const currentSessionIndex = sessions.findIndex((session) => session.id === params.sessionId);
if (currentSessionIndex - 1 < sessions.length) {
return sessions[currentSessionIndex - 1];
} else {
@ -36,9 +32,7 @@ export const load: PageLoad = async ({ parent, params }) => {
}
}),
nextSession: derived(sessions, (sessions) => {
const currentSessionIndex = sessions.findIndex(
(session) => session.id === params.sessionId
);
const currentSessionIndex = sessions.findIndex((session) => session.id === params.sessionId);
if (currentSessionIndex + 1 < sessions.length) {
return sessions[currentSessionIndex + 1];
} else {
@ -46,6 +40,6 @@ export const load: PageLoad = async ({ parent, params }) => {
}
}),
files: files,
deltas: deltas,
}
}
deltas: deltas
};
};

View File

@ -1,14 +1,14 @@
<script lang="ts">
import { derived } from "svelte/store";
import { Login } from "$lib/components";
import type { PageData } from "./$types";
import { derived } from 'svelte/store';
import { Login } from '$lib/components';
import type { PageData } from './$types';
export let data: PageData;
const { project, user, api } = data;
function repo_id(url: string) {
const hurl = new URL(url);
const path = hurl.pathname.split("/");
const path = hurl.pathname.split('/');
return path[path.length - 1];
}
@ -29,7 +29,7 @@
if (!$project.api) {
const apiProject = await api.projects.create($user.access_token, {
name: $project.title,
uid: $project.id,
uid: $project.id
});
await project.update({ api: { ...apiProject, sync } });
} else {
@ -44,9 +44,7 @@
<div class="space-y-0">
<div class="text-lg font-medium">Project Settings</div>
<div class="text-zinc-400">
Manage your project settings for <strong
>{$project?.title}</strong
>
Manage your project settings for <strong>{$project?.title}</strong>
</div>
</div>
<hr class="border-zinc-600" />
@ -74,15 +72,11 @@
<div class="flex flex-row">
{#if $project?.api?.git_url}
<div class="flex flex-col">
<div class="text-zinc-300">
Git Host
</div>
<div class="text-zinc-300">Git Host</div>
<div class="text-zinc-400 font-mono">
{hostname($project?.api?.git_url)}
</div>
<div class="text-zinc-300 mt-3">
Repository ID
</div>
<div class="text-zinc-300 mt-3">Repository ID</div>
<div class="text-zinc-400 font-mono">
{repo_id($project?.api?.git_url)}
</div>
@ -97,9 +91,7 @@
checked={$isSyncing}
on:change={onSyncChange}
/>
<label for="sync"
>Send Data to Server</label
>
<label for="sync">Send Data to Server</label>
</form>
</div>
</div>
@ -110,9 +102,7 @@
<div class="space-y-2">
<div class="flex flex-row space-x-2 items-end">
<div class="">GitButler Cloud</div>
<div class="text-zinc-400">
backup your work and access advanced features
</div>
<div class="text-zinc-400">backup your work and access advanced features</div>
</div>
<div class="flex flex-row items-center space-x-2">
<Login {user} {api} />

View File

@ -1,10 +1,10 @@
<script lang="ts">
import { Week } from "$lib/week";
import type { PageData } from "./$types";
import { WeekBlockEntry } from "$lib/components/week";
import MdKeyboardArrowLeft from "svelte-icons/md/MdKeyboardArrowLeft.svelte";
import MdKeyboardArrowRight from "svelte-icons/md/MdKeyboardArrowRight.svelte";
import { derived } from "svelte/store";
import { Week } from '$lib/week';
import type { PageData } from './$types';
import { WeekBlockEntry } from '$lib/components/week';
import MdKeyboardArrowLeft from 'svelte-icons/md/MdKeyboardArrowLeft.svelte';
import MdKeyboardArrowRight from 'svelte-icons/md/MdKeyboardArrowRight.svelte';
import { derived } from 'svelte/store';
export let data: PageData;
const { project, sessions } = data;
@ -13,10 +13,10 @@
$: canNavigateForwad = week.end.getTime() < new Date().getTime();
const formatDate = (date: Date) => {
return new Intl.DateTimeFormat("default", {
weekday: "short",
day: "numeric",
month: "short",
return new Intl.DateTimeFormat('default', {
weekday: 'short',
day: 'numeric',
month: 'short'
}).format(date);
};
@ -31,9 +31,7 @@
</script>
<div class="flex flex-col h-full select-none text-zinc-400">
<header
class="flex items-center justify-between flex-none px-8 py-1.5 border-b border-zinc-700"
>
<header class="flex items-center justify-between flex-none px-8 py-1.5 border-b border-zinc-700">
<div class="flex items-center justify-start w-64">
<button
class="-ml-2 w-8 h-8 hover:text-zinc-100"
@ -42,13 +40,9 @@
<MdKeyboardArrowLeft />
</button>
<div class="flex-grow text-center cursor-default grid grid-cols-7">
<span class="col-span-3"
>{formatDate(Week.nThDay(week, 0))}</span
>
<span class="col-span-3">{formatDate(Week.nThDay(week, 0))}</span>
<span>&mdash;</span>
<span class="col-span-3"
>{formatDate(Week.nThDay(week, 6))}</span
>
<span class="col-span-3">{formatDate(Week.nThDay(week, 6))}</span>
</div>
<button
class="-mr-2 w-8 h-8 hover:text-zinc-100 disabled:text-zinc-700"
@ -73,56 +67,49 @@
<div class="py-4" />
<div class="flex items-center justify-center">
<span
>Mon <span
class="items-center justify-center font-semibold"
>Mon <span class="items-center justify-center font-semibold"
>{Week.nThDay(week, 0).getDate()}</span
></span
>
</div>
<div class="flex items-center justify-center">
<span
>Tue <span
class="items-center justify-center font-semibold"
>Tue <span class="items-center justify-center font-semibold"
>{Week.nThDay(week, 1).getDate()}</span
></span
>
</div>
<div class="flex items-center justify-center">
<span
>Wed <span
class="items-center justify-center font-semibold"
>Wed <span class="items-center justify-center font-semibold"
>{Week.nThDay(week, 2).getDate()}</span
></span
>
</div>
<div class="flex items-center justify-center">
<span
>Thu <span
class="items-center justify-center font-semibold"
>Thu <span class="items-center justify-center font-semibold"
>{Week.nThDay(week, 3).getDate()}</span
></span
>
</div>
<div class="flex items-center justify-center">
<span
>Fri <span
class="items-center justify-center font-semibold"
>Fri <span class="items-center justify-center font-semibold"
>{Week.nThDay(week, 4).getDate()}</span
></span
>
</div>
<div class="flex items-center justify-center">
<span
>Sat <span
class="items-center justify-center font-semibold"
>Sat <span class="items-center justify-center font-semibold"
>{Week.nThDay(week, 5).getDate()}</span
></span
>
</div>
<div class="flex items-center justify-center">
<span
>Sun <span
class="items-center justify-center font-semibold"
>Sun <span class="items-center justify-center font-semibold"
>{Week.nThDay(week, 6).getDate()}</span
></span
>
@ -142,97 +129,73 @@
>
<div class="row-end-1 h-7" />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
12 AM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
2 AM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
4 AM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
6 AM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
8 AM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
10 AM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
12 PM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
2 PM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
4 PM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
6 PM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
8 PM
</div>
</div>
<div />
<div>
<div
class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500"
>
<div class="z-20 -mt-2.5 -ml-14 w-14 pr-4 text-right leading-5 text-zinc-500">
10 PM
</div>
</div>
@ -344,12 +307,8 @@
>
{#each $sessionsInWeek as session}
<WeekBlockEntry
startTime={new Date(
session.meta.startTimestampMs
)}
endTime={new Date(
session.meta.startTimestampMs
)}
startTime={new Date(session.meta.startTimestampMs)}
endTime={new Date(session.meta.startTimestampMs)}
label={session.meta.branch}
href="/projects/{$project?.id}/sessions/{session.id}/"
/>

View File

@ -1,8 +1,8 @@
<script lang="ts">
import { Login } from "$lib/components";
import type { PageData } from "./$types";
import MdAutorenew from "svelte-icons/md/MdAutorenew.svelte";
import { log, toasts } from "$lib";
import { Login } from '$lib/components';
import type { PageData } from './$types';
import MdAutorenew from 'svelte-icons/md/MdAutorenew.svelte';
import { log, toasts } from '$lib';
export let data: PageData;
const { user, api } = data;
@ -12,7 +12,7 @@
let userName = $user?.name;
let userPicture = $user?.picture;
const fileTypes = ["image/jpeg", "image/png"];
const fileTypes = ['image/jpeg', 'image/png'];
const validFileType = (file: File) => {
return fileTypes.includes(file.type);
@ -26,7 +26,7 @@
userPicture = URL.createObjectURL(file);
} else {
userPicture = $user?.picture;
toasts.error("Please use a valid image file");
toasts.error('Please use a valid image file');
}
};
@ -36,18 +36,18 @@
const target = e.target as HTMLFormElement;
const formData = new FormData(target);
const name = formData.get("name") as string | undefined;
const picture = formData.get("picture") as File | undefined;
const name = formData.get('name') as string | undefined;
const picture = formData.get('picture') as File | undefined;
try {
$user = await api.user.update($user.access_token, {
name,
picture: picture,
picture: picture
});
toasts.success("Profile updated");
toasts.success('Profile updated');
} catch (e) {
log.error(e);
toasts.error("Failed to update user");
toasts.error('Failed to update user');
}
saving = false;
@ -59,9 +59,7 @@
{#if $user}
<div class="flex flex-col gap-6 text-zinc-100">
<header class="flex items-center justify-between">
<h2 class="text-2xl font-medium">
GitButler Cloud Account
</h2>
<h2 class="text-2xl font-medium">GitButler Cloud Account</h2>
<Login {user} {api} />
</header>
@ -83,9 +81,7 @@
</div>
<div class="flex flex-col gap-1">
<label for="email" class="text-zinc-400"
>Email</label
>
<label for="email" class="text-zinc-400">Email</label>
<input
disabled
id="email"
@ -107,9 +103,7 @@
<span>Updating...</span>
</div>
{:else}
<button
type="submit"
class="py-1 px-3 rounded text-white bg-blue-400"
<button type="submit" class="py-1 px-3 rounded text-white bg-blue-400"
>Update profile</button
>
{/if}
@ -136,7 +130,7 @@
type="file"
id="picture"
name="picture"
accept={fileTypes.join("")}
accept={fileTypes.join('')}
class="hidden"
/>
</label>
@ -144,16 +138,9 @@
</form>
</div>
{:else}
<div
class="flex flex-col text-white space-y-6 items-center justify-items-center"
>
<div class="text-3xl font-bold text-white">
Connect to GitButler Cloud
</div>
<div>
Sign up or log in to GitButler Cloud for more tools and
features:
</div>
<div class="flex flex-col text-white space-y-6 items-center justify-items-center">
<div class="text-3xl font-bold text-white">Connect to GitButler Cloud</div>
<div>Sign up or log in to GitButler Cloud for more tools and features:</div>
<ul class="text-zinc-400 pb-4 space-y-2">
<li class="flex flex-row space-x-3">
<svg
@ -170,9 +157,7 @@
d="M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z"
/>
</svg>
<span
>Backup everything you do in any of your projects</span
>
<span>Backup everything you do in any of your projects</span>
</li>
<li class="flex flex-row space-x-3">
<svg
@ -214,9 +199,8 @@
<Login {user} {api} />
</div>
<div class="text-zinc-300 text-center">
You will still need to give us permission for each project
before we transfer any data to our servers. You can revoke
this permission at any time.
You will still need to give us permission for each project before we transfer any data to
our servers. You can revoke this permission at any time.
</div>
</div>
{/if}

View File

@ -1,22 +1,15 @@
import preprocess from "svelte-preprocess";
import staticAdapter from "@sveltejs/adapter-static";
import { vitePreprocess } from "@sveltejs/kit/vite";
import staticAdapter from '@sveltejs/adapter-static';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [
vitePreprocess(),
preprocess({
postcss: true,
typescript: true,
}),
],
preprocess: vitePreprocess(),
kit: {
adapter: staticAdapter({
precompress: true,
strict: false,
}),
},
strict: false
})
}
};
export default config;

View File

@ -1,22 +1,22 @@
const config = {
content: ["./src/**/*.{html,js,svelte,ts}"],
darkMode: "class",
content: ['./src/**/*.{html,js,svelte,ts}'],
darkMode: 'class',
theme: {
fontFamily: {
sans: ["Inter", "SF Pro", "-apple-system", "system-ui"],
sans: ['Inter', 'SF Pro', '-apple-system', 'system-ui']
},
fontSize: {
xs: "10px",
sm: "12px",
base: "13px",
lg: "15px",
xl: "22px",
xs: '10px',
sm: '12px',
base: '13px',
lg: '15px',
xl: '22px'
},
extend: {},
extend: {}
},
plugins: [],
plugins: []
};
module.exports = config;

View File

@ -1,5 +1,5 @@
import { defineConfig } from "vite";
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from 'vite';
import { sveltekit } from '@sveltejs/kit/vite';
export default defineConfig({
plugins: [sveltekit()],
@ -10,17 +10,17 @@ export default defineConfig({
// tauri expects a fixed port, fail if that port is not available
server: {
port: 1420,
strictPort: true,
strictPort: true
},
// to make use of `TAURI_DEBUG` and other env variables
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
envPrefix: ["VITE_", "TAURI_"],
envPrefix: ['VITE_', 'TAURI_'],
build: {
// Tauri supports es2021
target: process.env.TAURI_PLATFORM == "windows" ? "chrome105" : "safari13",
target: process.env.TAURI_PLATFORM == 'windows' ? 'chrome105' : 'safari13',
// don't minify for debug builds
minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
minify: !process.env.TAURI_DEBUG ? 'esbuild' : false,
// produce sourcemaps for debug builds
sourcemap: !!process.env.TAURI_DEBUG,
},
sourcemap: !!process.env.TAURI_DEBUG
}
});