@turnipxenon/pineapple 2.4.13 → 2.4.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.idea/discord.xml +1 -1
  2. package/.idea/workspace.xml +125 -110
  3. package/.svelte-kit/__package__/app.postcss +28 -2
  4. package/.svelte-kit/__package__/assets/icons/close.svg +1 -0
  5. package/.svelte-kit/__package__/components/Card.svelte +1 -1
  6. package/.svelte-kit/__package__/components/Chip.svelte +1 -0
  7. package/.svelte-kit/__package__/components/{layouts → pineapple}/PineappleBaseLayout.svelte +48 -24
  8. package/.svelte-kit/__package__/components/pineapple/overlay_manager/OverlayManager.d.ts +0 -0
  9. package/.svelte-kit/__package__/components/pineapple/overlay_manager/OverlayManager.js +1 -0
  10. package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.d.ts +8 -0
  11. package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.js +1 -0
  12. package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.svelte +48 -0
  13. package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.svelte.d.ts +20 -0
  14. package/.svelte-kit/__package__/components/pineapple/toast/Toast.d.ts +27 -0
  15. package/.svelte-kit/__package__/components/pineapple/toast/Toast.js +37 -0
  16. package/.svelte-kit/__package__/components/pineapple/toast/Toast.svelte +89 -0
  17. package/.svelte-kit/__package__/components/pineapple/toast/Toast.svelte.d.ts +14 -0
  18. package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.d.ts +5 -0
  19. package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.js +1 -0
  20. package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.svelte +1 -0
  21. package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.svelte.d.ts +23 -0
  22. package/.svelte-kit/__package__/index.d.ts +1 -1
  23. package/.svelte-kit/__package__/index.js +1 -1
  24. package/.svelte-kit/generated/client/app.js +1 -1
  25. package/.svelte-kit/generated/client/nodes/5.js +1 -1
  26. package/.svelte-kit/generated/server/internal.js +1 -1
  27. package/.svelte-kit/types/route_meta_data.json +1 -1
  28. package/.svelte-kit/types/src/routes/$types.d.ts +1 -1
  29. package/.svelte-kit/types/src/routes/(pineapple)/$types.d.ts +1 -1
  30. package/.svelte-kit/types/src/routes/(pineapple)/{personal → pineapple}/$types.d.ts +1 -1
  31. package/dist/app.postcss +28 -2
  32. package/dist/assets/icons/close.svg +1 -0
  33. package/dist/components/Card.svelte +1 -1
  34. package/dist/components/Chip.svelte +1 -0
  35. package/dist/components/{layouts → pineapple}/PineappleBaseLayout.svelte +48 -24
  36. package/dist/components/pineapple/overlay_manager/OverlayManager.d.ts +0 -0
  37. package/dist/components/pineapple/overlay_manager/OverlayManager.js +1 -0
  38. package/dist/components/pineapple/toast/DefaultToastBody.d.ts +8 -0
  39. package/dist/components/pineapple/toast/DefaultToastBody.js +1 -0
  40. package/dist/components/pineapple/toast/DefaultToastBody.svelte +48 -0
  41. package/dist/components/pineapple/toast/DefaultToastBody.svelte.d.ts +20 -0
  42. package/dist/components/pineapple/toast/Toast.d.ts +27 -0
  43. package/dist/components/pineapple/toast/Toast.js +37 -0
  44. package/dist/components/pineapple/toast/Toast.svelte +89 -0
  45. package/dist/components/pineapple/toast/Toast.svelte.d.ts +14 -0
  46. package/dist/components/pineapple/toast/custom-toast/TestCustomToast.d.ts +5 -0
  47. package/dist/components/pineapple/toast/custom-toast/TestCustomToast.js +1 -0
  48. package/dist/components/pineapple/toast/custom-toast/TestCustomToast.svelte +1 -0
  49. package/dist/components/pineapple/toast/custom-toast/TestCustomToast.svelte.d.ts +23 -0
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +1 -1
  52. package/docs/OverlaySpec.md +23 -0
  53. package/docs/pull_request_template.md +34 -0
  54. package/package.json +1 -1
  55. package/src/lib/app.postcss +28 -2
  56. package/src/lib/assets/icons/close.svg +1 -0
  57. package/src/lib/components/Card.svelte +1 -1
  58. package/src/lib/components/Chip.svelte +1 -0
  59. package/src/lib/components/pineapple/PineappleBaseLayout.svelte +207 -0
  60. package/src/lib/components/pineapple/overlay_manager/OverlayManager.ts +0 -0
  61. package/src/lib/components/pineapple/toast/DefaultToastBody.svelte +43 -0
  62. package/src/lib/components/pineapple/toast/DefaultToastBody.ts +10 -0
  63. package/src/lib/components/pineapple/toast/Toast.svelte +113 -0
  64. package/src/lib/components/pineapple/toast/Toast.ts +57 -0
  65. package/src/lib/components/pineapple/toast/custom-toast/TestCustomToast.svelte +1 -0
  66. package/src/lib/components/pineapple/toast/custom-toast/TestCustomToast.ts +6 -0
  67. package/src/lib/index.ts +1 -1
  68. package/src/routes/(pineapple)/+layout.svelte +1 -1
  69. package/src/routes/(pineapple)/+page.svelte +2 -2
  70. package/src/routes/(pineapple)/pineapple/+page.svelte +44 -0
  71. package/src/lib/components/layouts/PineappleBaseLayout.svelte +0 -182
  72. package/src/routes/(pineapple)/personal/+page.svelte +0 -37
  73. /package/.svelte-kit/__package__/components/{layouts → pineapple}/PineappleBaseLayout.svelte.d.ts +0 -0
  74. /package/dist/components/{layouts → pineapple}/PineappleBaseLayout.svelte.d.ts +0 -0
@@ -0,0 +1,89 @@
1
+ <script>import {
2
+ activeToast,
3
+ DefaultToastParamsDuration,
4
+ toastQueue
5
+ } from "./Toast";
6
+ import {} from "svelte";
7
+ import Card from "../../Card.svelte";
8
+ import { spring, tweened } from "svelte/motion";
9
+ let localComponent;
10
+ let localProps;
11
+ const HIDDEN_VALUE = -15;
12
+ const SHOWN_VALUE = 0;
13
+ const progress = tweened(0, { duration: DefaultToastParamsDuration });
14
+ const position = spring(HIDDEN_VALUE);
15
+ position.damping = 0.4;
16
+ let isDismissed = false;
17
+ let shouldEnableButton = false;
18
+ const onToastDisappear = () => {
19
+ localComponent = void 0;
20
+ activeToast.update(() => {
21
+ if (toastQueue.length === 0) {
22
+ return void 0;
23
+ }
24
+ return toastQueue.shift();
25
+ });
26
+ };
27
+ activeToast.subscribe((params) => {
28
+ if (!params) {
29
+ return;
30
+ }
31
+ if (params.componentAndProps?.component === localComponent) {
32
+ return;
33
+ }
34
+ localComponent = params.componentAndProps.component;
35
+ localProps = params.componentAndProps.props;
36
+ progress.set(0, { duration: 0 }).then(() => {
37
+ position.set(SHOWN_VALUE).then(() => {
38
+ shouldEnableButton = true;
39
+ progress.set(100, { delay: 500, duration: params.duration ?? DefaultToastParamsDuration }).then(() => {
40
+ shouldEnableButton = false;
41
+ if (isDismissed) {
42
+ return;
43
+ }
44
+ position.set(HIDDEN_VALUE).then(onToastDisappear);
45
+ });
46
+ });
47
+ });
48
+ });
49
+ const dismissToast = () => {
50
+ shouldEnableButton = false;
51
+ isDismissed = true;
52
+ position.set(HIDDEN_VALUE).then(onToastDisappear);
53
+ };
54
+ </script>
55
+
56
+ {#if (localComponent !== undefined)}
57
+ <div class="toast-positioner" style={`bottom: ${$position}lh;`}>
58
+ <!-- todo: adjust shadow to be more dynamic or transparent -->
59
+ <Card marginBottom="1lh" overrideStyle="box-shadow: 3px 3px 3px var(--shadow-color);">
60
+ <div slot="content">
61
+ {#if (localProps !== undefined)}
62
+ <svelte:component this={localComponent}
63
+ props={localProps}
64
+ dismissToastCallback={dismissToast}
65
+ shouldEnableButton={shouldEnableButton} />
66
+ {:else }
67
+ <svelte:component this={localComponent} />
68
+ {/if}
69
+ <progress id="toast-progress" value={$progress/100}></progress>
70
+ </div>
71
+ </Card>
72
+ </div>
73
+ {/if}
74
+
75
+ <style>
76
+ .toast-positioner {
77
+ position: fixed;
78
+ /* 12em = this component's margin (4em) + fab margin + width (8em) */
79
+ max-width: calc(100vw - 12em);
80
+ }
81
+
82
+ .toast-positioner:dir(ltr) {
83
+ left: 2em;
84
+ }
85
+
86
+ .toast-positioner:dir(rtl) {
87
+ right: 2em;
88
+ }
89
+ </style>
@@ -0,0 +1,14 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ };
9
+ export type ToastProps = typeof __propDef.props;
10
+ export type ToastEvents = typeof __propDef.events;
11
+ export type ToastSlots = typeof __propDef.slots;
12
+ export default class Toast extends SvelteComponent<ToastProps, ToastEvents, ToastSlots> {
13
+ }
14
+ export {};
@@ -0,0 +1,5 @@
1
+ import TestCustomToast from "./TestCustomToast.svelte";
2
+ export interface TestCustomToastPair {
3
+ component: typeof TestCustomToast;
4
+ props: undefined;
5
+ }
@@ -0,0 +1 @@
1
+ import TestCustomToast from "./TestCustomToast.svelte";
@@ -0,0 +1 @@
1
+ <h1>Testing bad custom card</h1>
@@ -0,0 +1,23 @@
1
+ /** @typedef {typeof __propDef.props} TestCustomToastProps */
2
+ /** @typedef {typeof __propDef.events} TestCustomToastEvents */
3
+ /** @typedef {typeof __propDef.slots} TestCustomToastSlots */
4
+ export default class TestCustomToast extends SvelteComponent<{
5
+ [x: string]: never;
6
+ }, {
7
+ [evt: string]: CustomEvent<any>;
8
+ }, {}> {
9
+ }
10
+ export type TestCustomToastProps = typeof __propDef.props;
11
+ export type TestCustomToastEvents = typeof __propDef.events;
12
+ export type TestCustomToastSlots = typeof __propDef.slots;
13
+ import { SvelteComponent } from "svelte";
14
+ declare const __propDef: {
15
+ props: {
16
+ [x: string]: never;
17
+ };
18
+ events: {
19
+ [evt: string]: CustomEvent<any>;
20
+ };
21
+ slots: {};
22
+ };
23
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { default as PineappleLayoutBase } from "./components/layouts/PineappleBaseLayout.svelte";
1
+ export { default as PineappleLayoutBase } from "./components/pineapple/PineappleBaseLayout.svelte";
2
2
  export { default as SeaweedTemplate } from "./template/SeaweedTemplate.svelte";
3
3
  export { default as LazyAsset } from "./components/LazyAsset.svelte";
4
4
  export * from "./components/dialog_manager/DialogManagerStore";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { default as PineappleLayoutBase } from "./components/layouts/PineappleBaseLayout.svelte";
1
+ export { default as PineappleLayoutBase } from "./components/pineapple/PineappleBaseLayout.svelte";
2
2
  export { default as SeaweedTemplate } from "./template/SeaweedTemplate.svelte";
3
3
  export { default as LazyAsset } from "./components/LazyAsset.svelte";
4
4
  export * from "./components/dialog_manager/DialogManagerStore";
@@ -0,0 +1,23 @@
1
+ # Overlay Spec
2
+
3
+ **What are the things that can appear on top of the normal content?**
4
+
5
+ - Toast
6
+ - Modal
7
+ - Dialog
8
+ - Choices
9
+ - Backstage
10
+ - Preferences
11
+ - Optional: Dialog??
12
+
13
+ **Which one appears on top?**
14
+
15
+ - Toast
16
+ - Modal
17
+ - blocks access on anything below
18
+ - Backstage
19
+ - blocks access on anything below
20
+ - Dialog: choices
21
+ - blocks access on anything below
22
+ - Dialog
23
+ - Everything else
@@ -0,0 +1,34 @@
1
+ ## Which issues does this affect?
2
+
3
+ - Closes #*PR number*
4
+
5
+ ## Overview
6
+
7
+ *Insert brief description here*
8
+
9
+ ## Description
10
+
11
+ *If there are more details or more things that needs to be talked about, put it here.*
12
+
13
+ ## Checks
14
+
15
+ - [ ] If some of the checks below are deferred, link an issue for it under as a child
16
+
17
+ ### Accessibility
18
+
19
+ - [ ] [Changes are keyboard accessible](https://accessibility.18f.gov/keyboard/)
20
+ - [ ] [All form inputs have explicit labels](https://accessibility.18f.gov/forms/)
21
+ - [ ] [Page content has a meaningful heading hierarchy](https://accessibility.18f.gov/headings/)
22
+ - [ ] [All relevant images use an img tag and have alt attributes](https://accessibility.18f.gov/images/)
23
+ - [ ] [Text has sufficient color contrast](https://accessibility.18f.gov/color/) (a contrast ratio of 4.5:1 with the
24
+ background)
25
+ - [ ] [No red flags when running WAVE on the page](http://wave.webaim.org/)
26
+ - [ ] The UI should also work in left-to-right direction
27
+
28
+ For the full list, see [18F's Accessibility Checklist](https://accessibility.18f.gov/checklist/).
29
+
30
+
31
+ <!--
32
+ References:
33
+ - https://github.com/ministryofjustice/accessibility-checklist/blob/master/README.md
34
+ -->
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@turnipxenon/pineapple",
3
3
  "description": "personal package for base styling for other personal projects",
4
- "version": "2.4.13",
4
+ "version": "2.4.14",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
7
7
  "build": "npm run check-requirements && vite build && yarn package",
@@ -41,11 +41,11 @@ html, body {
41
41
  }
42
42
 
43
43
  /* todo: add some hues to the icon that should be in sync with primary and make them not pure darkness */
44
- .turnip-button > img {
44
+ .turnip-button > img, .img-icon {
45
45
  filter: grayscale(100%) brightness(0%) invert(25%);
46
46
  }
47
47
 
48
- .dark .turnip-button > img {
48
+ .dark .turnip-button > img, .dark .img-icon {
49
49
  filter: grayscale(100%) brightness(0%) invert(100%);
50
50
  }
51
51
 
@@ -164,4 +164,30 @@ a:active {
164
164
  .accordion-item {
165
165
  @apply variant-filled-primary rounded-md;
166
166
  }
167
+
167
168
  /* endregion Accordion css for handling missing styles in package */
169
+
170
+ :root {
171
+ --shadow-color: rgba(91, 79, 54, 0.5);
172
+ }
173
+
174
+ /* todo: adjust shadow for each component + change depending on dark mode or not */
175
+ .fab, #shell-header {
176
+ box-shadow: 3px 3px 3px var(--shadow-color);
177
+ }
178
+
179
+ #toast-progress {
180
+ position: relative;
181
+ top: 5px;
182
+ left: 6px;
183
+ width: calc(100% - 12px);
184
+ border-radius: 8px;
185
+ background: transparent;
186
+ height: 10px;
187
+ }
188
+
189
+ #toast-progress::-moz-progress-bar {
190
+ /*background-color: red;*/
191
+ background: rgba(var(--color-secondary-500));
192
+ }
193
+
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  export let margin = "0";
3
- export let marginBottom = "3em";
3
+ export let marginBottom = "2lh";
4
4
  export let overrideStyle = "";
5
5
  export let includeDataNoSnippet = true;
6
6
 
@@ -8,5 +8,6 @@
8
8
  margin: 0.25em;
9
9
  font-weight: bold;
10
10
  pointer-events: none;
11
+ background-color: rgb(var(--color-tertiary-500) / var(--tw-bg-opacity));
11
12
  }
12
13
  </style>
@@ -0,0 +1,207 @@
1
+ <script lang="ts">
2
+ // For auto dark/light mode
3
+ import { AppBar, AppShell, autoModeWatcher, LightSwitch } from "@skeletonlabs/skeleton";
4
+ import RandomizedBackground from "$pkg/components/RandomizedBackground.svelte";
5
+
6
+ // navigation
7
+ import { page } from "$app/stores";
8
+ // store
9
+ import { enableBackground } from "$pkg/store";
10
+ import type { BreadcrumbData } from "$pkg/types/BreadcrumbData";
11
+ // assets
12
+ // import DialogOverlay from "$lib/components/DialogOverlay.svelte";
13
+ import AresLogo from "$pkg/assets/characters/ares/ares_logo.webp";
14
+ import FABIcon from "$pkg/assets/placeholder/placeholder_circle.png";
15
+ import { enableDialogueOverlay } from "$pkg/components/dialog_manager/DialogManagerStore";
16
+ import Toast from "$pkg/components/pineapple/toast/Toast.svelte";
17
+ // todo: clean up all these imports!
18
+
19
+ let pages: BreadcrumbData[] = [];
20
+
21
+ const updateBreadcrumb = (pathname: string) => {
22
+ pages = [];
23
+ let basePath = "";
24
+ pathname.split("/").forEach((value, index) => {
25
+ if (index === 0) {
26
+ basePath = "/";
27
+ pages.push({
28
+ path: "/",
29
+ name: "Home"
30
+ });
31
+ return;
32
+ }
33
+
34
+ if (value === "") {
35
+ return;
36
+ }
37
+
38
+ basePath += value + "/";
39
+ pages.push({
40
+ path: basePath,
41
+ name: value
42
+ });
43
+ });
44
+ pages = pages;
45
+ };
46
+
47
+ $: updateBreadcrumb($page.url.pathname); // run every time we navigate
48
+
49
+ let enableBackgroundValue = true;
50
+ enableBackground.subscribe((value) => {
51
+ enableBackgroundValue = value;
52
+ });
53
+
54
+ let enableDialogueOverlayValue = true;
55
+ enableDialogueOverlay.subscribe((value) => {
56
+ enableDialogueOverlayValue = value;
57
+ });
58
+ </script>
59
+
60
+ <!-- App Shell -->
61
+ <svelte:head>
62
+ {@html `<script>${autoModeWatcher.toString()} autoModeWatcher();</script>`}
63
+ </svelte:head>
64
+
65
+ <!--todo: turn off hidden when it's time-->
66
+ <button type="button" class="fab" on:click={()=>{
67
+ enableDialogueOverlay.set(!enableDialogueOverlayValue);
68
+ }}>
69
+ <img src={FABIcon} alt="interactive floating action button represented as a turnip">
70
+ </button>
71
+
72
+ <AppShell>
73
+ <svelte:fragment slot="header">
74
+ <!-- App Bar -->
75
+ <AppBar
76
+ background="app-shell-token"
77
+ slotDefault="place-content-start"
78
+ slotTrail="place-content-end">
79
+ <svelte:fragment slot="lead">
80
+ <!--TODO: add logo or something for the lead in layout-->
81
+ <img
82
+ alt="Ares's head titled towards the left with his tongue out and winking"
83
+ class="ares-logo"
84
+ src={AresLogo}
85
+ />
86
+ <span class="mr-2" />
87
+ <ol class="breadcrumb">
88
+ {#each pages as crumb, i}
89
+ {#if i < pages.length - 1}
90
+ <li class="crumb">
91
+ <a href={crumb.path}>{crumb.name.charAt(0).toUpperCase() + crumb.name.slice(1)}</a>
92
+ </li>
93
+ <li class="crumb-separator" aria-hidden="true">&rsaquo;</li>
94
+ {:else}
95
+ <li class="crumb">{crumb.name.charAt(0).toUpperCase() + crumb.name.slice(1)}</li>
96
+ {/if}
97
+ {/each}
98
+ </ol>
99
+ </svelte:fragment>
100
+ <svelte:fragment slot="trail">
101
+ <LightSwitch bgLight="bg-surface-400" />
102
+ </svelte:fragment>
103
+ </AppBar>
104
+ </svelte:fragment>
105
+
106
+ <RandomizedBackground enable={enableBackgroundValue} />
107
+
108
+ <Toast></Toast>
109
+
110
+ <div class="default-page-container">
111
+ <slot />
112
+ <div class="footer-space" />
113
+ </div>
114
+ <!--{#if enableDialogueOverlayValue}-->
115
+ <!-- &lt;!&ndash; Page Route Content &ndash;&gt;-->
116
+ <!-- <div class="default-page-container">-->
117
+ <!-- <slot />-->
118
+ <!-- <div class="footer-space" />-->
119
+ <!-- </div>-->
120
+ <!-- <DialogOverlay />-->
121
+ <!--{:else}-->
122
+ <!-- <DialogOverlay />-->
123
+ <!-- <slot />-->
124
+ <!--{/if}-->
125
+ </AppShell>
126
+
127
+ <style lang="postcss">
128
+ :root {
129
+ --dialog-left-pad: clamp(0em, 5vw, 2em);
130
+ --dialog-box-width: min(calc(50em + 4em), calc(100vw - var(--dialog-left-pad) - var(--theme-border-base)));
131
+ --dialog-box-height: clamp(15em, 50vw, 18em);
132
+
133
+ /** FAB icon margin/position calculation origin:
134
+ Criteria:
135
+ - We want at mobile (360px) our margin to be at 1em (16px)
136
+ - We want at web (1960px) our margin to be at 2em (32px)
137
+
138
+ A useful scaling factor might vw. At 360px, 16px would be around 4.44vw (360/16).
139
+ At 360px: margin is at 16px or 1em.
140
+ At 1960px: 4.44vw is at 87px but that will be clamped to 32px or 2em.
141
+ The calculation implies that the natural point that the margin becomes 2em is clamped on
142
+ wider screens is at 727px.
143
+ */
144
+ --fab-margin: clamp(1em, 4.44vw, 2em);
145
+ }
146
+
147
+ .default-page-container {
148
+ @apply flex justify-center items-center;
149
+ margin-top: 4em;
150
+ margin-left: clamp(1em, 15vw, 10em);
151
+ margin-right: 1em;
152
+ flex-direction: column;
153
+ z-index: 0;
154
+ }
155
+
156
+ .ares-logo {
157
+ object-fit: contain;
158
+ height: 2em;
159
+ margin-inline-end: 0.5em;
160
+ }
161
+
162
+ /* breadcrumb does not work due to a lot of magic stuff i do
163
+ the code below is from skeleton's tailwind css:
164
+ https://github.com/skeletonlabs/skeleton/blob/54f4ecedabf2be6d94a670b56dc8821095ca3fc9/packages/plugin/src/styles/components/breadcrumbs.css
165
+
166
+ it likely disappeared due to code gen shenanigans and package magic */
167
+ .breadcrumb,
168
+ .breadcrumb-nonresponsive {
169
+ @apply flex items-center space-x-4 w-full overflow-x-auto;
170
+ /*@apply flex items-center space-x-4 w-full hide-scrollbar overflow-x-auto;*/
171
+ }
172
+
173
+ .crumb {
174
+ @apply flex justify-center items-center space-x-2;
175
+ }
176
+
177
+ .crumb-separator {
178
+ @apply flex text-surface-700-200-token opacity-50;
179
+ }
180
+
181
+ /* === Auto-Responsive === */
182
+
183
+ .breadcrumb li {
184
+ @apply hidden md:block;
185
+ }
186
+
187
+ .breadcrumb li:nth-last-child(3),
188
+ .breadcrumb li:nth-last-child(2),
189
+ .breadcrumb li:nth-last-child(1) {
190
+ @apply block;
191
+ }
192
+
193
+ .fab {
194
+ position: fixed;
195
+ bottom: var(--fab-margin);
196
+ width: 4em;
197
+ border-radius: 50%;
198
+ }
199
+
200
+ .fab:dir(ltr) {
201
+ right: var(--fab-margin);
202
+ }
203
+
204
+ .fab:dir(rtl) {
205
+ left: var(--fab-margin);
206
+ }
207
+ </style>
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import type { Props } from "$pkg/components/pineapple/toast/DefaultToastBody";
3
+ import type { DismissToastCallback } from "$pkg/components/pineapple/toast/Toast";
4
+ import CloseIcon from "$pkg/assets/icons/close.svg";
5
+
6
+ export let props: Props;
7
+ export let dismissToastCallback: DismissToastCallback | undefined;
8
+ export let shouldEnableButton = false;
9
+ </script>
10
+
11
+ <div class="body-container">
12
+ <!-- todo: support markdown? -->
13
+ <button class="btn"
14
+ disabled={!shouldEnableButton}
15
+ on:click={dismissToastCallback}>
16
+ <img class="img-icon" src={CloseIcon} alt="close button">
17
+ </button>
18
+ <div class="text-container">
19
+ <span>{props.message}</span>
20
+ </div>
21
+ </div>
22
+
23
+ <style lang="postcss">
24
+ .body-container {
25
+ display: flex;
26
+ gap: 1em;
27
+ }
28
+
29
+ .text-container {
30
+ margin-top: 0.25lh;
31
+ margin-right: 1em;
32
+ }
33
+
34
+ .text-container:dir(rtl) {
35
+ margin-left: 1em;
36
+ }
37
+
38
+ .btn {
39
+ @apply bg-surface-100 dark:bg-surface-900;
40
+ border-radius: 8px;
41
+ padding: 0.5em;
42
+ }
43
+ </style>
@@ -0,0 +1,10 @@
1
+ import DefaultToastBody from "./DefaultToastBody.svelte";
2
+
3
+ export interface Props {
4
+ message: string;
5
+ }
6
+
7
+ export interface DefaultToastPair {
8
+ component: typeof DefaultToastBody;
9
+ props: Props;
10
+ }
@@ -0,0 +1,113 @@
1
+ <script lang="ts">
2
+ import {
3
+ activeToast,
4
+ type CustomToastPairs,
5
+ DefaultToastParamsDuration,
6
+ toastQueue
7
+ } from "$pkg/components/pineapple/toast/Toast";
8
+ import { type ComponentType } from "svelte";
9
+ import Card from "$pkg/components/Card.svelte";
10
+ import { spring, tweened } from "svelte/motion";
11
+
12
+ let localComponent: ComponentType | undefined;
13
+ let localProps: CustomToastPairs["props"];
14
+
15
+ // todo: make hidden value reliant on current vh
16
+ const HIDDEN_VALUE = -15;
17
+ const SHOWN_VALUE = 0;
18
+ const progress = tweened(0, { duration: DefaultToastParamsDuration });
19
+ const position = spring(HIDDEN_VALUE);
20
+ position.damping = 0.4;
21
+ let isDismissed = false;
22
+ let shouldEnableButton = false;
23
+
24
+ const onToastDisappear = () => {
25
+ // clear the local component to undefined to make the component disappear
26
+ // also set activeToast to null to indicate to the system that it's ready to take new
27
+ // Toast requests
28
+ localComponent = undefined;
29
+ activeToast.update(() => {
30
+ if (toastQueue.length === 0) {
31
+ return undefined;
32
+ }
33
+ return toastQueue.shift();
34
+ });
35
+ };
36
+
37
+ activeToast.subscribe((params) => {
38
+ if (!params) {
39
+ return;
40
+ }
41
+
42
+ if (params.componentAndProps?.component === localComponent) {
43
+ return;
44
+ }
45
+
46
+ localComponent = params.componentAndProps.component;
47
+ localProps = params.componentAndProps.props;
48
+
49
+ // todo: make unnested
50
+ // set progress to 0 before showing
51
+ progress.set(0, { duration: 0 }).then(() => {
52
+ // animate showing the toast
53
+ position.set(SHOWN_VALUE).then(() => {
54
+ shouldEnableButton = true;
55
+
56
+ // now animate the lifespan of the current toast
57
+ progress.set(100, { delay: 500, duration: params.duration ?? DefaultToastParamsDuration }).then(() => {
58
+ // during the lifecycle the button to cause dismissal can only happen when
59
+ // position is completely set SHOWN_VALUE and when progress has reached to 100
60
+ shouldEnableButton = false;
61
+ if (isDismissed) {
62
+ return;
63
+ }
64
+
65
+ // when the lifespan duration is over, animate hiding the toast by putting its bottom
66
+ // position out of bounds
67
+ position.set(HIDDEN_VALUE).then(onToastDisappear);
68
+ });
69
+ });
70
+ });
71
+ });
72
+
73
+ const dismissToast = () => {
74
+ shouldEnableButton = false;
75
+ isDismissed = true;
76
+ position.set(HIDDEN_VALUE).then(onToastDisappear);
77
+ };
78
+ </script>
79
+
80
+ {#if (localComponent !== undefined)}
81
+ <div class="toast-positioner" style={`bottom: ${$position}lh;`}>
82
+ <!-- todo: adjust shadow to be more dynamic or transparent -->
83
+ <Card marginBottom="1lh" overrideStyle="box-shadow: 3px 3px 3px var(--shadow-color);">
84
+ <div slot="content">
85
+ {#if (localProps !== undefined)}
86
+ <svelte:component this={localComponent}
87
+ props={localProps}
88
+ dismissToastCallback={dismissToast}
89
+ shouldEnableButton={shouldEnableButton} />
90
+ {:else }
91
+ <svelte:component this={localComponent} />
92
+ {/if}
93
+ <progress id="toast-progress" value={$progress/100}></progress>
94
+ </div>
95
+ </Card>
96
+ </div>
97
+ {/if}
98
+
99
+ <style lang="postcss">
100
+ .toast-positioner {
101
+ position: fixed;
102
+ /* 12em = this component's margin (4em) + fab margin + width (8em) */
103
+ max-width: calc(100vw - 12em);
104
+ }
105
+
106
+ .toast-positioner:dir(ltr) {
107
+ left: 2em;
108
+ }
109
+
110
+ .toast-positioner:dir(rtl) {
111
+ right: 2em;
112
+ }
113
+ </style>