Add colours and Sentry feedback form

This commit is contained in:
Jade Ellis
2024-09-10 04:11:45 +01:00
parent 3ff04eba7e
commit d6da36314d
10 changed files with 294 additions and 147 deletions
+4 -3
View File
@@ -1,5 +1,5 @@
import { SENTRY_DSN } from '$lib/config'; import { SENTRY_DSN } from '$lib/config';
import { init as initSentry, handleErrorWithSentry, makeBrowserOfflineTransport, makeFetchTransport } from '@sentry/sveltekit'; import { init as initSentry, handleErrorWithSentry, makeBrowserOfflineTransport, makeFetchTransport, feedbackIntegration } from '@sentry/sveltekit';
initSentry({ initSentry({
dsn: SENTRY_DSN, dsn: SENTRY_DSN,
@@ -14,8 +14,9 @@ initSentry({
// sessions when an error occurs. // sessions when an error occurs.
replaysOnErrorSampleRate: 1.0, replaysOnErrorSampleRate: 1.0,
// If you don't want to use Session Replay, just remove the line below: integrations: [feedbackIntegration({
// integrations: [replayIntegration()], autoInject: false,
})],
// To enable offline events caching, use makeBrowserOfflineTransport to wrap // To enable offline events caching, use makeBrowserOfflineTransport to wrap
// existing transports and queue events using the browsers' IndexedDB storage // existing transports and queue events using the browsers' IndexedDB storage
+34 -1
View File
@@ -33,6 +33,11 @@
--code-background-color: #0d1117; --code-background-color: #0d1117;
--code-color: #fff; --code-color: #fff;
--color-primary: hsl(230, 50%, 90%);
--color-secondary: hsl(230, 50%, 10%);
--color-tertiary: hsl(290, 80%, 20%);
--color-accent: hsl(227, 80%, 20%);
--color-red: #e93147; --color-red: #e93147;
--color-orange: #ec7500; --color-orange: #ec7500;
--color-yellow: #e0ac00; --color-yellow: #e0ac00;
@@ -61,6 +66,11 @@
--font-color-contrast: rgba(0, 0, 0, .87); --font-color-contrast: rgba(0, 0, 0, .87);
--font-color-secondary: rgba(255, 255, 255, .6); --font-color-secondary: rgba(255, 255, 255, .6);
--color-primary: hsl(230, 50%, 10%);
--color-secondary: hsl(230, 50%, 90%);
--color-tertiary: hsl(290, 80%, 80%);
--color-accent: hsl(195, 80%, 80%);
--color-red: #fb464c; --color-red: #fb464c;
--color-orange: #e9973f; --color-orange: #e9973f;
--color-yellow: #e0de71; --color-yellow: #e0de71;
@@ -109,7 +119,8 @@ html {
body { body {
padding: 0; padding: 0;
margin: 0 margin: 0;
min-height: 100vh;
} }
iframe, iframe,
@@ -125,6 +136,13 @@ svg {
display: block; display: block;
} }
a {
color: var(--color-accent);
}
a:visited {
color: var(--color-tertiary);
}
.container { .container {
--container-max-width: var(--page-width); --container-max-width: var(--page-width);
--padding-x: var(--spacing); --padding-x: var(--spacing);
@@ -176,3 +194,18 @@ svg {
} }
button {
display: inline-block;
color: var(--color-primary);
background: var(--color-accent);
border-radius: 4px;
margin: 8px 8px 8px 0px;
padding: 12px 24px;
border: solid 2px var(--color-accent);
}
.secondary {
border: solid 2px var(--color-accent);
color: var(--color-accent);
background: transparent;
}
@@ -5,7 +5,7 @@
import { bookmarkify, parseMeta } from "./bookmarklets"; import { bookmarkify, parseMeta } from "./bookmarklets";
import type { Config } from "./config"; import type { Config } from "./config";
import { init } from "$lib/workers/terser"; import { init } from "$lib/workers/terser";
import { SITE_URL } from '$lib/metadata'; import { SITE_URL } from "$lib/metadata";
/** @type {import('./$types').Snapshot<string>} */ /** @type {import('./$types').Snapshot<string>} */
export const snapshot = { export const snapshot = {
@@ -13,7 +13,7 @@
restore: (v: string) => (value = v), restore: (v: string) => (value = v),
}; };
let minify = init().minify let minify = init().minify;
let value = ""; let value = "";
let output = ""; let output = "";
@@ -26,7 +26,7 @@
} }
} }
let contentAttributes = {"aria-label": "Bookmarklet editor"} let contentAttributes = { "aria-label": "Bookmarklet editor" };
$: progress = process(value); $: progress = process(value);
</script> </script>
@@ -36,34 +36,45 @@
description="Make booklets in your browser with this tool. Make handy shortcuts to save time." description="Make booklets in your browser with this tool. Make handy shortcuts to save time."
canonical={SITE_URL + "/bookmarklets"} canonical={SITE_URL + "/bookmarklets"}
/> />
<h1>Bookmarklet Maker</h1>
<Editor
{value}
on:change={(e) => (value = e.detail)}
lang={javascript()}
{contentAttributes}
>
<div slot="header" class="code-header">Input</div>
</Editor>
<h2>Output</h2> <main class="main container" id="page-content">
{#await progress} <h1>Bookmarklet Maker</h1>
<p>...waiting</p> <Editor
{:catch error} {value}
<p style="color: red">{error.message}</p> on:change={(e) => (value = e.detail)}
{/await} lang={javascript()}
<label for="output">Bookmarklet code</label> {contentAttributes}
<textarea name="output" id="output" class="output card" rows="1" value={output} readonly >
></textarea> <div slot="header" class="code-header">Input</div>
</Editor>
<!-- <Editor readonly={true} /> --> <h2>Output</h2>
<p> {#await progress}
Bookmark this link: <a href={output}>{options.name || "My Bookmarklet"}</a> <p>...waiting</p>
</p> {:catch error}
<p> <p style="color: red">{error.message}</p>
Either drag the link to your bookmarlets bar or, on FireFox, right click and {/await}
select "Bookmark Link". <label for="output">Bookmarklet code</label>
</p> <textarea
name="output"
id="output"
class="output card"
rows="1"
value={output}
readonly
></textarea>
<!-- <Editor readonly={true} /> -->
<p>
Bookmark this link: <a href={output}
>{options.name || "My Bookmarklet"}</a
>
</p>
<p>
Either drag the link to your bookmarlets bar or, on FireFox, right click
and select "Bookmark Link".
</p>
</main>
<style> <style>
.code-header { .code-header {
@@ -3,7 +3,7 @@
import { javascript } from "@codemirror/lang-javascript"; import { javascript } from "@codemirror/lang-javascript";
import SvelteSeo from "svelte-seo"; import SvelteSeo from "svelte-seo";
import { init } from "$lib/workers/terser"; import { init } from "$lib/workers/terser";
import { SITE_URL } from '$lib/metadata'; import { SITE_URL } from "$lib/metadata";
/** @type {import('./$types').Snapshot<string>} */ /** @type {import('./$types').Snapshot<string>} */
export const snapshot = { export const snapshot = {
@@ -11,24 +11,24 @@
restore: (v: string) => (value = v), restore: (v: string) => (value = v),
}; };
let minify = init().minify let minify = init().minify;
let value = ""; let value = "";
let output = ""; let output = "";
async function process(str: string) { async function process(str: string) {
if (value === "") { if (value === "") {
output = ""; output = "";
return return;
} }
let result = await minify(str) let result = await minify(str);
if (typeof result.code == "string") { if (typeof result.code == "string") {
output = result.code output = result.code;
} else { } else {
console.error(result) console.error(result);
} }
} }
let contentAttributes = {"aria-label": "Javascript editor"} let contentAttributes = { "aria-label": "Javascript editor" };
$: progress = process(value); $: progress = process(value);
</script> </script>
@@ -38,26 +38,34 @@
description="Reduce JavaScript code size with this handy online tool. It's easy to minify your JavaScript code." description="Reduce JavaScript code size with this handy online tool. It's easy to minify your JavaScript code."
canonical={SITE_URL + "/javascript-minifier"} canonical={SITE_URL + "/javascript-minifier"}
/> />
<h1>Javascript Minifier</h1>
<Editor
{value}
on:change={(e) => (value = e.detail)}
lang={javascript()}
{contentAttributes}
>
<div slot="header" class="code-header">Input</div>
</Editor>
<h2>Output</h2> <main class="main container" id="page-content">
{#await progress} <h1>Javascript Minifier</h1>
<p>...waiting</p> <Editor
{:catch error} {value}
<p style="color: red">{error.message}</p> on:change={(e) => (value = e.detail)}
{/await} lang={javascript()}
<label for="output">Minified code</label> {contentAttributes}
<textarea name="output" id="output" class="output card" rows="1" value={output} readonly >
></textarea> <div slot="header" class="code-header">Input</div>
</Editor>
<h2>Output</h2>
{#await progress}
<p>...waiting</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
<label for="output">Minified code</label>
<textarea
name="output"
id="output"
class="output card"
rows="1"
value={output}
readonly
></textarea>
</main>
<style> <style>
.code-header { .code-header {
+78
View File
@@ -0,0 +1,78 @@
<script lang="ts">
import { page } from "$app/stores";
import * as Sentry from "@sentry/sveltekit";
import { onMount } from "svelte";
import SvelteSeo from "svelte-seo";
const { status, error } = $page;
const message = error?.message || "Hmm";
const title = `${status}: ${message}`;
let sentryElement: HTMLDivElement;
let openForm = () => {};
onMount(async () => {
const feedback = Sentry.getFeedback({
el: sentryElement,
});
if (!feedback) {
return;
}
// console.log("feedback", feedback);
const form = await feedback.createForm({});
form.appendToDom();
form.open();
openForm = async () => {
form.open();
};
});
</script>
<SvelteSeo {title} />
<main class="main container" id="page-content">
<div class="wrapper">
<h1>{title}</h1>
<div bind:this={sentryElement} class="feedback"></div>
<button on:click={openForm}>Send Feedback</button>
<button class="secondary" on:click={()=> window.location.reload()}>Reload</button>
<!-- <div role="doc-subtitle">{status}</div> -->
</div>
</main>
<style>
main {
display: grid;
place-items: center;
}
.wrapper {
flex-grow: 2;
width: 40vw;
max-width: 500px;
margin: 0 auto;
/* display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing);
margin: 48px auto;
max-width: 320px;
padding: 3rem 0.5rem; */
}
h1 {
margin: 0;
font-size: 4em;
/* font-weight: 100; */
}
/* [role="doc-subtitle"] {
padding-block-start: 0;
font-size: 2em;
font-weight: 600;
} */
:global(#sentry-feedback) {
--dialog-inset: auto auto 0;
}
p {
width: 95%;
font-size: 1.5em;
line-height: 1.4;
}
</style>
+1 -4
View File
@@ -11,7 +11,4 @@
<meta property="og:site_name" content={SITE_TITLE}> <meta property="og:site_name" content={SITE_TITLE}>
</svelte:head> </svelte:head>
<Nav /> <Nav />
<main class="main container" id="page-content"> <slot />
<slot />
</main>
+19 -7
View File
@@ -6,15 +6,27 @@
</script> </script>
<svelte:head> <svelte:head>
<link rel="alternate" type="application/rss+xml" title={SITE_TITLE} href={SITE_URL + "/blog/rss.xml"}> <link
<link rel="alternate" type="application/feed+json" title={SITE_TITLE} href={SITE_URL + "/blog/feed.json"}> rel="alternate"
type="application/rss+xml"
title={SITE_TITLE}
href={SITE_URL + "/blog/rss.xml"}
/>
<link
rel="alternate"
type="application/feed+json"
title={SITE_TITLE}
href={SITE_URL + "/blog/feed.json"}
/>
</svelte:head> </svelte:head>
<SvelteSeo <SvelteSeo
title="Jade Ellis" title="Jade Ellis"
description="Student, Creative & Computer Scientist. See what I'm doing." description="Student, Creative & Computer Scientist. See what I'm doing."
canonical="https://jade.ellis.link" canonical="https://jade.ellis.link"
/> />
<Hero />
<Homepage /> <main class="main container" id="page-content">
<Hero />
<Homepage />
</main>
+38 -36
View File
@@ -53,44 +53,46 @@
<SvelteSeo title="Jade's Blog - Posts" canonical={SITE_URL + "/blog"} /> <SvelteSeo title="Jade's Blog - Posts" canonical={SITE_URL + "/blog"} />
<section role="feed" class="h-feed" id="feed"> <main class="main container" id="page-content">
<h1 class="p-name"> <section role="feed" class="h-feed" id="feed">
<a <h1 class="p-name">
aria-hidden="true" <a
tabindex="-1" aria-hidden="true"
class="u-url permalink" tabindex="-1"
href={SITE_URL + "/blog#feed"}>#</a class="u-url permalink"
>Jade's Blog - Posts href={SITE_URL + "/blog#feed"}>#</a
</h1> >Jade's Blog - Posts
{#each pages as post, index} </h1>
<article {#each pages as post, index}
aria-posinset={index + 1} <article
aria-setsize={pages.length} aria-posinset={index + 1}
class="h-entry" aria-setsize={pages.length}
> class="h-entry"
<div class="content" data-sveltekit-preload-data="hover"> >
<h2> <div class="content" data-sveltekit-preload-data="hover">
<a class="u-url p-name" href="/blog/{post.canonical}"> <h2>
{post.title} <a class="u-url p-name" href="/blog/{post.canonical}">
</a> {post.title}
</h2> </a>
<span class="quiet" </h2>
><time class="dt-published" datetime={post.date} <span class="quiet"
>{new Date(post.date).toLocaleDateString()}</time ><time class="dt-published" datetime={post.date}
></span >{new Date(post.date).toLocaleDateString()}</time
> ></span
{#if post.description} >
<p class="p-summary">{post.description}</p> {#if post.description}
{/if} <p class="p-summary">{post.description}</p>
</div> {/if}
</article> </div>
{:else} </article>
<p>No posts yet!</p> {:else}
{/each} <p>No posts yet!</p>
<!-- {#if showPosts < postCount} {/each}
<!-- {#if showPosts < postCount}
<button type="submit" on:click={handleClick}>See more {H_ELLIPSIS_ENTITY}</button> <button type="submit" on:click={handleClick}>See more {H_ELLIPSIS_ENTITY}</button>
{/if} --> {/if} -->
</section> </section>
</main>
<style> <style>
.permalink { .permalink {
@@ -48,11 +48,11 @@
}); });
gtag("event", "share", { gtag("event", "share", {
"share_url": url.href, share_url: url.href,
"share_title": data.post.title, share_title: data.post.title,
"share_button": "article_top", share_button: "article_top",
"method": "navigator_share", method: "navigator_share",
"content_type": "article", content_type: "article",
}); });
} catch (error: any) { } catch (error: any) {
if (error.toString().includes("AbortError")) { if (error.toString().includes("AbortError")) {
@@ -176,42 +176,44 @@
}} }}
/> />
<article class="h-entry"> <main class="main container" id="page-content">
<h1 id="title" class="p-name">{data.post.title}</h1> <article class="h-entry">
<aside> <h1 id="title" class="p-name">{data.post.title}</h1>
<a class="u-url ib" href={canonical} <aside>
>Published on <time <a class="u-url ib" href={canonical}
class="dt-published ib" >Published on <time
datetime={data.post.date} class="dt-published ib"
>{new Date(data.post.date).toLocaleDateString()}</time datetime={data.post.date}
></a >{new Date(data.post.date).toLocaleDateString()}</time
> ></a
<span class="author p-author h-card vcard ib"> >
by <img <span class="author p-author h-card vcard ib">
loading="lazy" by <img
style="display: none;" loading="lazy"
src={defaultAuthor.image} style="display: none;"
class="avatar avatar-96 photo u-photo" src={defaultAuthor.image}
/><a class="u-url url fn n p-name" href={defaultAuthor.url} class="avatar avatar-96 photo u-photo"
>{defaultAuthor.name}</a /><a class="u-url url fn n p-name" href={defaultAuthor.url}
></span >{defaultAuthor.name}</a
> ></span
· <span class="reading-time ib">{data.post.readingTime.text}</span> >
{#if webShareAPISupported} · <span class="reading-time ib">{data.post.readingTime.text}</span>
· <button class="link" on:click={handleWebShare}>Share</button> {#if webShareAPISupported}
{/if} · <button class="link" on:click={handleWebShare}>Share</button>
</aside> {/if}
<Toc headings={data.post.headings} /> </aside>
<!-- {#await GhReleasesDownload} <Toc headings={data.post.headings} />
<!-- {#await GhReleasesDownload}
{:then component} {:then component}
<svelte:component this={component} releaseData={data.ghReleaseData} /> <svelte:component this={component} releaseData={data.ghReleaseData} />
{/await} --> {/await} -->
<div class="e-content"> <div class="e-content">
<svelte:component this={data.component} /> <svelte:component this={data.component} />
</div> </div>
</article> </article>
</main>
<style> <style>
aside { aside {
@@ -18,15 +18,18 @@
description={data.post.description} description={data.post.description}
canonical={SITE_URL + "/projects/" + data.post.slug} canonical={SITE_URL + "/projects/" + data.post.slug}
/> />
<h1>{data.post.title}</h1>
<!-- {#await GhReleasesDownload} <main class="main container" id="page-content">
<h1>{data.post.title}</h1>
<!-- {#await GhReleasesDownload}
{:then component} {:then component}
<svelte:component this={component} releaseData={data.ghReleaseData} /> <svelte:component this={component} releaseData={data.ghReleaseData} />
{/await} --> {/await} -->
{#if data.ghReleaseData} {#if data.ghReleaseData}
<GhReleasesDownload releaseData={data.ghReleaseData} /> <GhReleasesDownload releaseData={data.ghReleaseData} />
{/if} {/if}
<svelte:component this={data.component} /> <svelte:component this={data.component} />
</main>