@foxui/social 0.4.0

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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -0
  3. package/dist/components/blog-entry/BlogEntry.svelte +80 -0
  4. package/dist/components/blog-entry/BlogEntry.svelte.d.ts +14 -0
  5. package/dist/components/blog-entry/index.d.ts +1 -0
  6. package/dist/components/blog-entry/index.js +1 -0
  7. package/dist/components/bluesky-login/BlueskyLogin.svelte +23 -0
  8. package/dist/components/bluesky-login/BlueskyLogin.svelte.d.ts +4 -0
  9. package/dist/components/bluesky-login/BlueskyLoginModal.svelte +141 -0
  10. package/dist/components/bluesky-login/BlueskyLoginModal.svelte.d.ts +9 -0
  11. package/dist/components/bluesky-login/index.d.ts +8 -0
  12. package/dist/components/bluesky-login/index.js +3 -0
  13. package/dist/components/bluesky-post/BlueskyPost.svelte +36 -0
  14. package/dist/components/bluesky-post/BlueskyPost.svelte.d.ts +10 -0
  15. package/dist/components/bluesky-post/index.d.ts +5 -0
  16. package/dist/components/bluesky-post/index.js +110 -0
  17. package/dist/components/chat/Chat.svelte +0 -0
  18. package/dist/components/chat/Chat.svelte.d.ts +26 -0
  19. package/dist/components/chat/ChatMessage.svelte +0 -0
  20. package/dist/components/chat/ChatMessage.svelte.d.ts +26 -0
  21. package/dist/components/chat/index.d.ts +1 -0
  22. package/dist/components/chat/index.js +1 -0
  23. package/dist/components/emoji-picker/EmojiPicker.svelte +91 -0
  24. package/dist/components/emoji-picker/EmojiPicker.svelte.d.ts +11 -0
  25. package/dist/components/emoji-picker/PopoverEmojiPicker.svelte +24 -0
  26. package/dist/components/emoji-picker/PopoverEmojiPicker.svelte.d.ts +11 -0
  27. package/dist/components/emoji-picker/emoji.d.ts +7 -0
  28. package/dist/components/emoji-picker/emoji.js +56 -0
  29. package/dist/components/emoji-picker/index.d.ts +2 -0
  30. package/dist/components/emoji-picker/index.js +2 -0
  31. package/dist/components/github-corner/GithubCorner.svelte +62 -0
  32. package/dist/components/github-corner/GithubCorner.svelte.d.ts +4 -0
  33. package/dist/components/github-corner/index.d.ts +1 -0
  34. package/dist/components/github-corner/index.js +1 -0
  35. package/dist/components/index.d.ts +12 -0
  36. package/dist/components/index.js +20 -0
  37. package/dist/components/nested-comments/Comment.svelte +151 -0
  38. package/dist/components/nested-comments/Comment.svelte.d.ts +9 -0
  39. package/dist/components/nested-comments/NestedComments.svelte +14 -0
  40. package/dist/components/nested-comments/NestedComments.svelte.d.ts +7 -0
  41. package/dist/components/nested-comments/index.d.ts +1 -0
  42. package/dist/components/nested-comments/index.js +1 -0
  43. package/dist/components/post/Post.svelte +294 -0
  44. package/dist/components/post/Post.svelte.d.ts +23 -0
  45. package/dist/components/post/PostAction.svelte +27 -0
  46. package/dist/components/post/PostAction.svelte.d.ts +9 -0
  47. package/dist/components/post/embeds/Embed.svelte +24 -0
  48. package/dist/components/post/embeds/Embed.svelte.d.ts +7 -0
  49. package/dist/components/post/embeds/External.svelte +39 -0
  50. package/dist/components/post/embeds/External.svelte.d.ts +7 -0
  51. package/dist/components/post/embeds/Images.svelte +38 -0
  52. package/dist/components/post/embeds/Images.svelte.d.ts +7 -0
  53. package/dist/components/post/embeds/Video.svelte +45 -0
  54. package/dist/components/post/embeds/Video.svelte.d.ts +7 -0
  55. package/dist/components/post/index.d.ts +63 -0
  56. package/dist/components/post/index.js +1 -0
  57. package/dist/components/social-icons/All.svelte +47 -0
  58. package/dist/components/social-icons/All.svelte.d.ts +12 -0
  59. package/dist/components/social-icons/Bluesky.svelte +37 -0
  60. package/dist/components/social-icons/Bluesky.svelte.d.ts +8 -0
  61. package/dist/components/social-icons/Discord.svelte +37 -0
  62. package/dist/components/social-icons/Discord.svelte.d.ts +8 -0
  63. package/dist/components/social-icons/Facebook.svelte +37 -0
  64. package/dist/components/social-icons/Facebook.svelte.d.ts +8 -0
  65. package/dist/components/social-icons/Github.svelte +38 -0
  66. package/dist/components/social-icons/Github.svelte.d.ts +8 -0
  67. package/dist/components/social-icons/Twitter.svelte +37 -0
  68. package/dist/components/social-icons/Twitter.svelte.d.ts +8 -0
  69. package/dist/components/social-icons/Youtube.svelte +36 -0
  70. package/dist/components/social-icons/Youtube.svelte.d.ts +8 -0
  71. package/dist/components/social-icons/index.d.ts +7 -0
  72. package/dist/components/social-icons/index.js +8 -0
  73. package/dist/components/star-rating/StarRating.svelte +104 -0
  74. package/dist/components/star-rating/StarRating.svelte.d.ts +13 -0
  75. package/dist/components/star-rating/index.d.ts +1 -0
  76. package/dist/components/star-rating/index.js +1 -0
  77. package/dist/components/swiper-cards/CardSwiper.svelte +235 -0
  78. package/dist/components/swiper-cards/CardSwiper.svelte.d.ts +18 -0
  79. package/dist/components/swiper-cards/index.d.ts +14 -0
  80. package/dist/components/swiper-cards/index.js +1 -0
  81. package/dist/components/user-profile/UserProfile.svelte +60 -0
  82. package/dist/components/user-profile/UserProfile.svelte.d.ts +13 -0
  83. package/dist/components/user-profile/index.d.ts +1 -0
  84. package/dist/components/user-profile/index.js +1 -0
  85. package/dist/index.d.ts +1 -0
  86. package/dist/index.js +1 -0
  87. package/dist/types.d.ts +1 -0
  88. package/package.json +79 -0
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
3
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
4
+ import { cn } from '@foxui/core';
5
+
6
+ const {
7
+ class: className,
8
+ target = '_blank',
9
+ svgClasses,
10
+ ...restProps
11
+ }: WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
12
+ svgClasses?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <a
17
+ {target}
18
+ class={cn(
19
+ 'text-base-800 hover:text-accent-600 dark:text-base-300 dark:hover:text-accent-400 transition-colors',
20
+ className
21
+ )}
22
+ {...restProps}
23
+ >
24
+ <span class="sr-only">Bluesky</span>
25
+
26
+ <svg
27
+ role="img"
28
+ viewBox="0 0 24 24"
29
+ xmlns="http://www.w3.org/2000/svg"
30
+ class={['size-6', svgClasses]}
31
+ aria-hidden="true"
32
+ fill="currentColor"
33
+ ><path
34
+ d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"
35
+ /></svg
36
+ >
37
+ </a>
@@ -0,0 +1,8 @@
1
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ type $$ComponentProps = WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
4
+ svgClasses?: string;
5
+ };
6
+ declare const Bluesky: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Bluesky = ReturnType<typeof Bluesky>;
8
+ export default Bluesky;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
3
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
4
+ import { cn } from '@foxui/core';
5
+
6
+ const {
7
+ class: className,
8
+ target = '_blank',
9
+ svgClasses,
10
+ ...restProps
11
+ }: WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
12
+ svgClasses?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <a
17
+ {target}
18
+ class={cn(
19
+ 'text-base-800 hover:text-accent-600 dark:text-base-300 dark:hover:text-accent-400 transition-colors',
20
+ className
21
+ )}
22
+ {...restProps}
23
+ >
24
+ <span class="sr-only">Discord</span>
25
+
26
+ <svg
27
+ role="img"
28
+ viewBox="0 0 24 24"
29
+ xmlns="http://www.w3.org/2000/svg"
30
+ class={['size-6', svgClasses]}
31
+ fill="currentColor"
32
+ aria-hidden="true"
33
+ ><path
34
+ d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"
35
+ /></svg
36
+ >
37
+ </a>
@@ -0,0 +1,8 @@
1
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ type $$ComponentProps = WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
4
+ svgClasses?: string;
5
+ };
6
+ declare const Discord: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Discord = ReturnType<typeof Discord>;
8
+ export default Discord;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
3
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
4
+ import { cn } from '@foxui/core';
5
+
6
+ const {
7
+ class: className,
8
+ target = '_blank',
9
+ svgClasses,
10
+ ...restProps
11
+ }: WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
12
+ svgClasses?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <a
17
+ {target}
18
+ class={cn(
19
+ 'text-base-800 hover:text-accent-600 dark:text-base-300 dark:hover:text-accent-400 transition-colors',
20
+ className
21
+ )}
22
+ {...restProps}
23
+ >
24
+ <span class="sr-only">Facebook</span>
25
+
26
+ <svg
27
+ role="img"
28
+ viewBox="0 0 24 24"
29
+ xmlns="http://www.w3.org/2000/svg"
30
+ class={['size-6', svgClasses]}
31
+ fill="currentColor"
32
+ aria-hidden="true"
33
+ ><path
34
+ d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"
35
+ /></svg
36
+ >
37
+ </a>
@@ -0,0 +1,8 @@
1
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ type $$ComponentProps = WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
4
+ svgClasses?: string;
5
+ };
6
+ declare const Facebook: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Facebook = ReturnType<typeof Facebook>;
8
+ export default Facebook;
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
3
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
4
+ import { cn } from '@foxui/core';
5
+
6
+ const {
7
+ class: className,
8
+ target = '_blank',
9
+ svgClasses,
10
+ ...restProps
11
+ }: WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
12
+ svgClasses?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <a
17
+ {target}
18
+ class={cn(
19
+ 'text-base-800 hover:text-accent-600 dark:text-base-300 dark:hover:text-accent-400 rounded-2xl transition-colors',
20
+ 'focus-visible:outline-base-900 dark:focus-visible:outline-base-100 focus-visible:outline-2 focus-visible:outline-offset-2',
21
+ className
22
+ )}
23
+ {...restProps}
24
+ >
25
+ <span class="sr-only">GitHub</span>
26
+
27
+ <svg
28
+ role="img"
29
+ viewBox="0 0 24 24"
30
+ xmlns="http://www.w3.org/2000/svg"
31
+ fill="currentColor"
32
+ aria-hidden="true"
33
+ class={['size-5', svgClasses]}
34
+ ><path
35
+ d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
36
+ /></svg
37
+ >
38
+ </a>
@@ -0,0 +1,8 @@
1
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ type $$ComponentProps = WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
4
+ svgClasses?: string;
5
+ };
6
+ declare const Github: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Github = ReturnType<typeof Github>;
8
+ export default Github;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
3
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
4
+ import { cn } from '@foxui/core';
5
+
6
+ const {
7
+ class: className,
8
+ target = '_blank',
9
+ svgClasses,
10
+ ...restProps
11
+ }: WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
12
+ svgClasses?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <a
17
+ {target}
18
+ class={cn(
19
+ 'text-base-800 hover:text-accent-600 dark:text-base-300 dark:hover:text-accent-400 transition-colors',
20
+ className
21
+ )}
22
+ {...restProps}
23
+ >
24
+ <span class="sr-only">X</span>
25
+
26
+ <svg
27
+ role="img"
28
+ viewBox="0 0 24 24"
29
+ class={['size-6', svgClasses]}
30
+ fill="currentColor"
31
+ aria-hidden="true"
32
+ xmlns="http://www.w3.org/2000/svg"
33
+ ><title>X</title><path
34
+ d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"
35
+ /></svg
36
+ >
37
+ </a>
@@ -0,0 +1,8 @@
1
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ type $$ComponentProps = WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
4
+ svgClasses?: string;
5
+ };
6
+ declare const Twitter: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Twitter = ReturnType<typeof Twitter>;
8
+ export default Twitter;
@@ -0,0 +1,36 @@
1
+ <script lang="ts">
2
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
3
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
4
+ import { cn } from '@foxui/core';
5
+
6
+ const {
7
+ class: className,
8
+ target = '_blank',
9
+ svgClasses,
10
+ ...restProps
11
+ }: WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
12
+ svgClasses?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <a
17
+ {target}
18
+ class={cn(
19
+ 'text-base-800 hover:text-accent-600 dark:text-base-300 dark:hover:text-accent-400 transition-colors',
20
+ className
21
+ )}
22
+ {...restProps}
23
+ >
24
+ <span class="sr-only">YouTube</span>
25
+ <svg
26
+ class={['size-7', svgClasses]}
27
+ fill="currentColor"
28
+ aria-hidden="true"
29
+ role="img"
30
+ viewBox="0 0 24 24"
31
+ xmlns="http://www.w3.org/2000/svg"
32
+ ><path
33
+ d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
34
+ /></svg
35
+ >
36
+ </a>
@@ -0,0 +1,8 @@
1
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ type $$ComponentProps = WithoutChildrenOrChild<WithElementRef<HTMLAnchorAttributes>> & {
4
+ svgClasses?: string;
5
+ };
6
+ declare const Youtube: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Youtube = ReturnType<typeof Youtube>;
8
+ export default Youtube;
@@ -0,0 +1,7 @@
1
+ export { default as SocialIcons } from './All.svelte';
2
+ export { default as Discord } from './Discord.svelte';
3
+ export { default as Github } from './Github.svelte';
4
+ export { default as Twitter } from './Twitter.svelte';
5
+ export { default as Youtube } from './Youtube.svelte';
6
+ export { default as Bluesky } from './Bluesky.svelte';
7
+ export { default as Facebook } from './Facebook.svelte';
@@ -0,0 +1,8 @@
1
+ // all icons from https://simpleicons.org/
2
+ export { default as SocialIcons } from './All.svelte';
3
+ export { default as Discord } from './Discord.svelte';
4
+ export { default as Github } from './Github.svelte';
5
+ export { default as Twitter } from './Twitter.svelte';
6
+ export { default as Youtube } from './Youtube.svelte';
7
+ export { default as Bluesky } from './Bluesky.svelte';
8
+ export { default as Facebook } from './Facebook.svelte';
@@ -0,0 +1,104 @@
1
+ <script lang="ts">
2
+ // todo convert to radio group
3
+ import { cn } from '@foxui/core';
4
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
5
+ import type { HTMLAttributes } from 'svelte/elements';
6
+
7
+ let {
8
+ rating = $bindable(),
9
+ size = 'size-8',
10
+ changeable = true,
11
+ class: className,
12
+ ref = $bindable(null),
13
+ strokeWidth = 0.8,
14
+ buttonClasses,
15
+ svgClasses,
16
+ ...restProps
17
+ }: WithElementRef<WithoutChildrenOrChild<HTMLAttributes<HTMLDivElement>>> & {
18
+ rating: number;
19
+ size?: string;
20
+ changeable?: boolean;
21
+
22
+ strokeWidth?: number;
23
+
24
+ buttonClasses?: string;
25
+ svgClasses?: string;
26
+ } = $props();
27
+
28
+ let hoverRating = $state(rating);
29
+
30
+ $effect(() => {
31
+ hoverRating = rating;
32
+ });
33
+ </script>
34
+
35
+ <div class={cn('flex items-center', className)} {...restProps} bind:this={ref}>
36
+ {#if changeable}
37
+ {#each Array.from({ length: 5 }).map((_, i) => i + 1) as i}
38
+ <button
39
+ class={cn(
40
+ 'group focus-visible:outline-base-900 dark:focus-visible:outline-base-100 cursor-pointer rounded-xl focus-visible:outline-2',
41
+ buttonClasses
42
+ )}
43
+ onclick={() => (rating = i)}
44
+ onfocus={() => (hoverRating = i)}
45
+ onblur={() => (hoverRating = rating)}
46
+ onmouseenter={() => (hoverRating = i)}
47
+ onmouseleave={() => (hoverRating = rating)}
48
+ >
49
+ <svg
50
+ class={cn(
51
+ size,
52
+ 'shrink-0',
53
+ i > rating &&
54
+ i > hoverRating &&
55
+ 'stroke-base-400 text-base-100 dark:stroke-base-700/70 dark:text-base-900',
56
+ i <= rating &&
57
+ i <= hoverRating &&
58
+ 'stroke-accent-600 text-accent-400 dark:stroke-accent-500/80 dark:text-accent-500/40',
59
+
60
+ ((i > rating && i <= hoverRating) || (i > hoverRating && i <= rating)) &&
61
+ 'stroke-accent-600/50 text-accent-400/50 dark:stroke-accent-500/40 dark:text-accent-500/20',
62
+ svgClasses
63
+ )}
64
+ viewBox="0 0 24 24"
65
+ fill="currentColor"
66
+ aria-hidden="true"
67
+ stroke-width={strokeWidth}
68
+ data-slot="icon"
69
+ >
70
+ <path
71
+ fill-rule="evenodd"
72
+ d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z"
73
+ clip-rule="evenodd"
74
+ />
75
+ </svg>
76
+
77
+ <span class="sr-only">rate {i} stars</span>
78
+ </button>
79
+ {/each}
80
+ {:else}
81
+ {#each Array.from({ length: 5 }).map((_, i) => i + 1) as i}
82
+ <svg
83
+ class={cn(
84
+ size,
85
+ 'stroke-base-400 text-base-100 dark:stroke-base-700 dark:text-base-800 shrink-0',
86
+ i <= rating &&
87
+ 'stroke-accent-600 text-accent-400 dark:stroke-accent-500/80 dark:text-accent-500/50',
88
+ svgClasses
89
+ )}
90
+ viewBox="0 0 24 24"
91
+ fill="currentColor"
92
+ aria-hidden="true"
93
+ stroke-width={strokeWidth}
94
+ data-slot="icon"
95
+ >
96
+ <path
97
+ fill-rule="evenodd"
98
+ d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z"
99
+ clip-rule="evenodd"
100
+ />
101
+ </svg>
102
+ {/each}
103
+ {/if}
104
+ </div>
@@ -0,0 +1,13 @@
1
+ import type { WithElementRef, WithoutChildrenOrChild } from 'bits-ui';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ type $$ComponentProps = WithElementRef<WithoutChildrenOrChild<HTMLAttributes<HTMLDivElement>>> & {
4
+ rating: number;
5
+ size?: string;
6
+ changeable?: boolean;
7
+ strokeWidth?: number;
8
+ buttonClasses?: string;
9
+ svgClasses?: string;
10
+ };
11
+ declare const StarRating: import("svelte").Component<$$ComponentProps, {}, "ref" | "rating">;
12
+ type StarRating = ReturnType<typeof StarRating>;
13
+ export default StarRating;
@@ -0,0 +1 @@
1
+ export { default as StarRating } from './StarRating.svelte';
@@ -0,0 +1 @@
1
+ export { default as StarRating } from './StarRating.svelte';
@@ -0,0 +1,235 @@
1
+ <script lang="ts">
2
+ // TODO: fix types
3
+
4
+ import { onMount, type Snippet } from 'svelte';
5
+ import { DragGesture, type FullGestureState } from '@use-gesture/vanilla';
6
+ import type { CardData, Direction, SwipeEventData } from '.';
7
+ import { Image } from '@foxui/core';
8
+
9
+ let {
10
+ card = DefaultCard,
11
+ cardData,
12
+ onswipe,
13
+ swipe = $bindable(),
14
+
15
+ minSwipeDistance = 0.5,
16
+ minSwipeVelocity = 0.5,
17
+ arrowKeys = true,
18
+ thresholdPassed = $bindable(0),
19
+ anchor = null,
20
+ rotate = true,
21
+ cardCount = 5
22
+ }: {
23
+ card?: Snippet<[CardData]>;
24
+
25
+ cardData: (index: number) => CardData;
26
+ onswipe?: (cardInfo: SwipeEventData) => void;
27
+ swipe?: (direction: Direction) => void;
28
+
29
+ minSwipeDistance?: number;
30
+ minSwipeVelocity?: number;
31
+ arrowKeys?: boolean;
32
+ thresholdPassed?: number;
33
+ anchor?: number | null;
34
+ rotate?: boolean;
35
+ cardCount?: number;
36
+ } = $props();
37
+
38
+ swipe = (direction: Direction = 'right') => {
39
+ if (thresholdPassed !== 0) return;
40
+
41
+ let dir = direction === 'left' ? -1 : 1;
42
+
43
+ if (!topCard) throw new Error('No top card found');
44
+ cardSwiped(topCard, [dir, 0.1], [dir, 1]);
45
+ };
46
+
47
+ let container: HTMLElement;
48
+
49
+ let cardIndex = 0;
50
+ let topCard: HTMLElement | undefined = $state();
51
+ let topCardIndex = 0;
52
+
53
+ let currentZ = 100000;
54
+
55
+ let cards: HTMLElement[] = $state(new Array(cardCount));
56
+ let cardsData: CardData[] = $state([]);
57
+
58
+ onMount(() => {
59
+ for (let i = 0; i < cardCount; i++) {
60
+ cardsData.push(cardData(cardIndex++));
61
+ cards.push();
62
+ }
63
+
64
+ let gestures: DragGesture[] = [];
65
+
66
+ cards.forEach((el) => {
67
+ if (!el) return;
68
+
69
+ el.style.zIndex = currentZ.toString();
70
+ currentZ--;
71
+
72
+ let gesture = new DragGesture(el, (state) => {
73
+ ondrag(el, state);
74
+ });
75
+
76
+ gestures.push(gesture);
77
+ });
78
+
79
+ topCardIndex = 0;
80
+ topCard = cards[topCardIndex];
81
+
82
+ container.classList.remove('hidden');
83
+
84
+ return () => {
85
+ gestures.forEach((gesture) => gesture.destroy());
86
+ };
87
+ });
88
+
89
+ const cardSwiped = (el: HTMLElement, velocity: [number, number], movement: [number, number]) => {
90
+ el.classList.add('transition-transform', 'duration-300');
91
+ let index = cards.indexOf(el);
92
+
93
+ let direction: Direction = movement[0] > 0 ? 'right' : 'left';
94
+ let data = cardsData[index];
95
+
96
+ onswipe?.({ direction, element: el, data, index: cardIndex - 2 });
97
+
98
+ thresholdPassed = movement[0] > 0 ? 1 : -1;
99
+
100
+ let moveOutWidth = document.body.clientWidth;
101
+
102
+ let endX = Math.max(Math.abs(velocity[0]) * moveOutWidth, moveOutWidth);
103
+ let toX = movement[0] > 0 ? endX : -endX;
104
+ let endY = Math.abs(velocity[1]) * moveOutWidth;
105
+ let toY = movement[1] > 0 ? endY : -endY;
106
+
107
+ let rotate = movement[0] * 0.03 * (movement[1] / 80);
108
+
109
+ el.style.transform = `translate(${toX}px, ${toY + movement[1]}px) rotate(${rotate}deg)`;
110
+
111
+ setTimeout(async () => {
112
+ thresholdPassed = 0;
113
+
114
+ cardsData[index] = cardData(cardIndex++);
115
+
116
+ // next card
117
+ topCardIndex = (topCardIndex + 1) % cardCount;
118
+ topCard = cards[topCardIndex];
119
+
120
+ currentZ--;
121
+ el.style.zIndex = currentZ.toString();
122
+
123
+ el.classList.remove('transition-transform', 'duration-300');
124
+ el.style.transform = '';
125
+ }, 350);
126
+ };
127
+
128
+ const ondrag = (
129
+ el: HTMLElement,
130
+ state: Omit<FullGestureState<'drag'>, 'event'> & {
131
+ event: PointerEvent | MouseEvent | TouchEvent | KeyboardEvent;
132
+ }
133
+ ) => {
134
+ let elWidth = el.offsetWidth;
135
+
136
+ if (state.active) {
137
+ let angle = state.movement[0] * 0.03 * (state.movement[1] / 80);
138
+
139
+ // fix movement on a curved path if anchor is set
140
+ if (anchor) {
141
+ let vec = [state.movement[0], state.movement[1] - anchor];
142
+ let len = Math.sqrt(vec[0] ** 2 + vec[1] ** 2);
143
+ vec = [(vec[0] / len) * anchor, (vec[1] / len) * anchor];
144
+
145
+ state.movement[0] = vec[0];
146
+ state.movement[1] = vec[1] + anchor;
147
+ }
148
+
149
+ el.style.transform = `translate(${state.movement[0]}px, ${state.movement[1]}px)`;
150
+
151
+ if (rotate) {
152
+ el.style.transform += ` rotate(${angle}deg)`;
153
+ }
154
+
155
+ if (Math.abs(state.movement[0]) / elWidth > minSwipeDistance) {
156
+ thresholdPassed = state.movement[0] > 0 ? 1 : -1;
157
+ } else {
158
+ thresholdPassed = 0;
159
+ }
160
+ return;
161
+ }
162
+ // if dragging is finished
163
+ let keep =
164
+ Math.abs(state.movement[0]) / elWidth < minSwipeDistance &&
165
+ Math.abs(state.velocity[0]) < minSwipeVelocity;
166
+
167
+ if (keep) {
168
+ thresholdPassed = 0;
169
+ el.classList.add('transition-transform', 'duration-300');
170
+ el.style.transform = '';
171
+ setTimeout(() => {
172
+ el.classList.remove('transition-transform', 'duration-300');
173
+ }, 300);
174
+ } else {
175
+ cardSwiped(el, state.velocity, state.movement);
176
+ }
177
+ };
178
+ </script>
179
+
180
+ <svelte:body
181
+ onkeydown={(e) => {
182
+ if (!arrowKeys) return;
183
+ if (e.key === 'ArrowLeft') {
184
+ swipe('left');
185
+ } else if (e.key === 'ArrowRight') {
186
+ swipe('right');
187
+ }
188
+ }}
189
+ />
190
+
191
+ {#snippet DefaultCard({ image, title, description }: CardData)}
192
+ <div
193
+ class="border-base-400 dark:border-base-600 bg-base-50 dark:bg-base-900 relative h-full w-full overflow-hidden rounded-2xl border"
194
+ >
195
+ {#key image}
196
+ {#if image}
197
+ <Image
198
+ containerClasses="absolute inset-0 h-full w-full rounded-2xl"
199
+ src={image}
200
+ alt={title ?? ''}
201
+ loading="eager"
202
+ class="h-full w-full object-cover"
203
+ />
204
+ {/if}
205
+ {/key}
206
+ <div
207
+ class="from-base-50/80 dark:from-base-950/80 absolute inset-0 rounded-b-xl bg-gradient-to-t via-transparent"
208
+ ></div>
209
+ <div class="absolute bottom-0 flex w-full justify-start px-3 py-16 sm:px-12">
210
+ <div class="flex flex-col">
211
+ <h3 class="text-base-900 dark:text-base-50 pb-2 text-3xl font-bold">{title}</h3>
212
+ <p class="text-base-800 dark:text-base-200 text-sm">{description}</p>
213
+ </div>
214
+ </div>
215
+ </div>
216
+ {/snippet}
217
+
218
+ <div class="isolate h-full w-full touch-none select-none">
219
+ <div class="relative z-0 hidden h-full w-full" bind:this={container}>
220
+ {#each cards as _, i}
221
+ <div
222
+ bind:this={cards[i]}
223
+ class="absolute h-full w-full cursor-grab touch-none overflow-hidden ease-in-out select-none"
224
+ >
225
+ {#if cardsData[i]}
226
+ {@render card({
227
+ image: cardsData[i].image,
228
+ title: cardsData[i].title,
229
+ description: cardsData[i].description
230
+ })}
231
+ {/if}
232
+ </div>
233
+ {/each}
234
+ </div>
235
+ </div>