();
18 | const [isVisible, setVisible] = createSignal(false);
19 | createEffect(
20 | on(observerReference, () => {
21 | const element = observerReference();
22 | element &&
23 | createIntersectionObserver(
24 | () => [element],
25 | ([entry]) => {
26 | if (entry.intersectionRatio > 0 && owner) {
27 | setVisible(true);
28 | runWithOwner(owner, () => props.onEnter?.());
29 | }
30 | },
31 | {
32 | root: undefined,
33 | rootMargin: '400px',
34 | threshold: 0,
35 | }
36 | );
37 | })
38 | );
39 |
40 | return (
41 |
42 |
52 | }
53 | >
54 | {props_.children}
55 |
56 |
57 | );
58 | };
59 |
--------------------------------------------------------------------------------
/src/components/general-observer/index.ts:
--------------------------------------------------------------------------------
1 | export { GeneralObserver } from './general-observer';
2 | export type { GeneralObserverProps } from './general-observer';
3 |
--------------------------------------------------------------------------------
/src/components/gist/gist.tsx:
--------------------------------------------------------------------------------
1 | import { createMemo, onMount, Show } from 'solid-js';
2 | import { createStore } from 'solid-js/store';
3 | import { createScriptLoader } from '@solid-primitives/script-loader';
4 | import { GeneralObserver } from '../general-observer';
5 | import { createStyleSheet } from '../../utilities';
6 | import type { Component } from 'solid-js';
7 |
8 | export type GistProps = {
9 | /** Gist link */
10 | gistLink: string;
11 | };
12 |
13 | type GistState = {
14 | /** Loading status */
15 | isLoading: boolean;
16 | /** HTML response from api */
17 | div?: string;
18 | /** The file name of the Gist*/
19 | file?: string;
20 | };
21 |
22 | export const Gist: Component = (props) => {
23 | const [gistResponse, setGistResponse] = createStore<{ gist: GistState }>({
24 | gist: {
25 | isLoading: true,
26 | div: '',
27 | file: '',
28 | },
29 | });
30 |
31 | const gistId = createMemo(() => props.gistLink.split('/')[1]);
32 | const gistEmbedScript = createMemo(
33 | () => `//gist.github.com/${props.gistLink}.json?callback=gist_callback_${gistId()}`
34 | );
35 |
36 | onMount(() => {
37 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
38 | // @ts-expect-error
39 | window[`gist_callback_${gistId()}`] = (gist: {
40 | div: string;
41 | files: string[];
42 | stylesheet: string;
43 | }) => {
44 | createStyleSheet(gist.stylesheet);
45 | setGistResponse({
46 | gist: {
47 | isLoading: false,
48 | div: gist.div,
49 | file: gist.files[0],
50 | },
51 | });
52 | };
53 | createScriptLoader({ src: gistEmbedScript });
54 | });
55 |
56 | return (
57 |
58 |
59 | {/* eslint-disable-next-line solid/no-innerhtml */}
60 |
61 |
62 |
63 | );
64 | };
65 |
--------------------------------------------------------------------------------
/src/components/gist/index.ts:
--------------------------------------------------------------------------------
1 | export { Gist } from './gist';
2 | export type { GistProps } from './gist';
3 |
--------------------------------------------------------------------------------
/src/components/instagram/index.ts:
--------------------------------------------------------------------------------
1 | export { Instagram } from './instagram';
2 | export type { InstagramProps } from './instagram';
3 |
--------------------------------------------------------------------------------
/src/components/instagram/instagram.tsx:
--------------------------------------------------------------------------------
1 | import { GeneralObserver } from '../general-observer';
2 | import { handleInstagrmLoad } from './utilities';
3 | import type { Component } from 'solid-js';
4 |
5 | export type InstagramProps = {
6 | /** Instagram id */
7 | instagramId: string;
8 | };
9 |
10 | export const Instagram: Component = (props) => (
11 |
12 |
13 | {window.instgrm && ''}
14 |
15 |
16 | );
17 |
--------------------------------------------------------------------------------
/src/components/instagram/utilities.ts:
--------------------------------------------------------------------------------
1 | import { createScriptLoader } from '@solid-primitives/script-loader';
2 |
3 | export const instgrmClasses = ['.instagram-media', '.instagram-media-rendered'].join(',');
4 |
5 | const instgrmProcess = (): void => window.instgrm?.Embeds.process();
6 |
7 | export const handleInstagrmLoad = (): void => {
8 | if (document.querySelector(instgrmClasses) && !window.instgrm)
9 | createScriptLoader({ src: '//www.instagram.com/embed.js' });
10 | else instgrmProcess();
11 | };
12 |
--------------------------------------------------------------------------------
/src/components/lbry/index.ts:
--------------------------------------------------------------------------------
1 | export { Lbry } from './lbry';
2 | export type { LbryProps } from './lbry';
3 |
--------------------------------------------------------------------------------
/src/components/lbry/lbry.tsx:
--------------------------------------------------------------------------------
1 | import { getPadding } from '../../utilities';
2 | import { GeneralObserver } from '../general-observer';
3 | import type { Component } from 'solid-js';
4 |
5 | export type LbryProps = {
6 | /** Lbry id */
7 | lbryId: string;
8 | /** Skip to a time in the video in seconds */
9 | skipTo?: number;
10 | };
11 |
12 | export const Lbry: Component = (props) => (
13 |
14 |
22 |
35 |
36 |
37 | );
38 |
--------------------------------------------------------------------------------
/src/components/linkedin/index.ts:
--------------------------------------------------------------------------------
1 | export { LinkedInBadge } from './linkedin-badge';
2 | export type { LinkedInBadgeProps } from './linkedin-badge';
3 |
--------------------------------------------------------------------------------
/src/components/linkedin/linkedin-badge.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handleLinkedInLoad } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type LinkedInBadgeProps = {
7 | /** LinkedIn username */
8 | username: string;
9 | /** The type of badge */
10 | badgeType?: 'horizontal' | 'vertical';
11 | /** The size of the badge */
12 | badgeSize?: 'medium' | 'large';
13 | /** The badge theme */
14 | theme?: 'light' | 'dark';
15 | /** data-locale */
16 | locale?: string;
17 | };
18 |
19 | export const LinkedInBadge: Component = (props) => {
20 | const props_ = mergeProps(
21 | {
22 | badgeType: 'vertical',
23 | badgeSize: 'medium',
24 | theme: 'light',
25 | locale: 'en_US',
26 | },
27 | props
28 | );
29 | return (
30 |
31 |
47 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/src/components/linkedin/utilities.ts:
--------------------------------------------------------------------------------
1 | import { createScriptLoader } from '@solid-primitives/script-loader';
2 |
3 | export const linkedInClasses = ['.LI-profile-badge', '.LI-simple-link'].join(',');
4 | const linkedInBadgesUrl = '//platform.linkedin.com/badges/js/profile.js';
5 |
6 | const LIRenderAll = (): undefined | unknown =>
7 | window.LI && typeof window.LIRenderAll === 'function' && window.LIRenderAll();
8 |
9 | export const handleLinkedInLoad = (): void => {
10 | if (document.querySelector(linkedInClasses) && !(window.LI && window.LIRenderAll))
11 | createScriptLoader({ src: linkedInBadgesUrl });
12 | else LIRenderAll();
13 | };
14 |
--------------------------------------------------------------------------------
/src/components/listennotes/index.tsx:
--------------------------------------------------------------------------------
1 | export { ListenNotesEpisode } from './listennotes-episode';
2 | export type { ListenNotesEpisodeProps } from './listennotes-episode';
3 |
--------------------------------------------------------------------------------
/src/components/listennotes/listennotes-episode.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import type { Component } from 'solid-js';
4 |
5 | export type ListenNotesEpisodeProps = {
6 | /** ListenNotes Episode */
7 | episodeId: string;
8 | /* width of the iframe: default to 100% */
9 | width?: string;
10 | /* height of the iframe: default to 200px */
11 | height?: string;
12 | };
13 |
14 | export const ListenNotesEpisode: Component = (props) => {
15 | const props_ = mergeProps(
16 | {
17 | width: '100%',
18 | height: '180px',
19 | },
20 | props
21 | );
22 | return (
23 |
24 |
32 |
49 |
50 |
51 | );
52 | };
53 |
--------------------------------------------------------------------------------
/src/components/pinterest/index.ts:
--------------------------------------------------------------------------------
1 | export { Pin } from './pin';
2 | export { PinterestBoard } from './pinterest-board';
3 | export { PinterestFollowButton } from './pinterest-follow-button';
4 | export type { PinProps } from './pin';
5 | export type { PinterestBoardProps } from './pinterest-board';
6 | export type { PinterestFollowButtonProps } from './pinterest-follow-button';
7 |
--------------------------------------------------------------------------------
/src/components/pinterest/pin.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handlePinterestBuild } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type PinProps = {
7 | /** Pinterest id */
8 | pinId: string;
9 | /** Size */
10 | size?: 'small' | 'medium' | 'large';
11 | };
12 |
13 | export const Pin: Component = (props) => {
14 | const props_ = mergeProps({ size: 'small' }, props);
15 | return (
16 |
17 | {/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
18 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/components/pinterest/pinterest-board.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handlePinterestBuild } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type PinterestBoardProps = {
7 | /** Pinterest link */
8 | pinterestLink: string;
9 | /** Width for the board */
10 | width?: number;
11 | /** Height for the board */
12 | height?: number;
13 | /** Size of the thumbnails */
14 | imageWidth?: number;
15 | /** The type of board */
16 | variant?: 'board' | 'user';
17 | };
18 |
19 | export const PinterestBoard: Component = (props) => {
20 | const props_ = mergeProps(
21 | {
22 | width: 400,
23 | height: 250,
24 | imageWidth: 80,
25 | variant: 'board',
26 | },
27 | props
28 | );
29 | return (
30 |
31 | {/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
32 |
40 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/src/components/pinterest/pinterest-follow-button.tsx:
--------------------------------------------------------------------------------
1 | import { GeneralObserver } from '../general-observer';
2 | import { handlePinterestBuild } from './utilities';
3 | import type { Component } from 'solid-js';
4 |
5 | export type PinterestFollowButtonProps = {
6 | /** Pinterest username */
7 | username: string;
8 | };
9 |
10 | export const PinterestFollowButton: Component = (props) => (
11 |
12 |
17 | {`Follow @${props.username}`}
18 |
19 |
20 | );
21 |
--------------------------------------------------------------------------------
/src/components/pinterest/utilities.ts:
--------------------------------------------------------------------------------
1 | import { createScriptLoader } from '@solid-primitives/script-loader';
2 |
3 | export const pinterestClasses = ['pinterest-pin', 'pinterest-board', 'pinterest-follow-button']
4 | .map((pinClass) => `.${pinClass}`)
5 | .join(',');
6 |
7 | const pinterestEmbedScript =
8 | '!function(a,b,c){var d,e,f;d="PIN_"+~~((new Date).getTime()/864e5),a[d]?a[d]+=1:(a[d]=1,a.setTimeout(function(){e=b.getElementsByTagName("SCRIPT")[0],f=b.createElement("SCRIPT"),f.type="text/javascript",f.async=!0,f.src=c.mainUrl+"?"+Math.random(),e.parentNode.insertBefore(f,e)},10))}(window,document,{mainUrl:"//assets.pinterest.com/js/pinit_main.js"});';
9 |
10 | export const handlePinterestBuild = (): void => {
11 | if (document.querySelector(pinterestClasses) && !window.PinUtils)
12 | createScriptLoader({ src: pinterestEmbedScript });
13 | else window.PinUtils?.build();
14 | };
15 |
--------------------------------------------------------------------------------
/src/components/simplecast/index.ts:
--------------------------------------------------------------------------------
1 | export { SimplecastEpisode } from './simplecast-episode';
2 | export type { SimplecastEpisodeProps } from './simplecast-episode';
3 |
--------------------------------------------------------------------------------
/src/components/simplecast/simplecast-episode.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import type { Component } from 'solid-js';
4 |
5 | export type SimplecastEpisodeProps = {
6 | /** Simplecast Episode */
7 | episodeId: string;
8 | /** Color theme of the Player */
9 | theme?: `light` | `dark`;
10 | };
11 |
12 | export const SimplecastEpisode: Component = (props) => {
13 | const props_ = mergeProps(
14 | {
15 | theme: `light`,
16 | },
17 | props
18 | );
19 | return (
20 |
21 |
29 |
46 |
47 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/src/components/snack/index.ts:
--------------------------------------------------------------------------------
1 | export { Snack } from './snack';
2 | export type { SnackProps } from './snack';
3 |
--------------------------------------------------------------------------------
/src/components/snack/snack.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { createScriptLoader } from '@solid-primitives/script-loader';
3 | import { GeneralObserver } from '../general-observer';
4 | import type { Component } from 'solid-js';
5 |
6 | const scriptUrl = '//snack.expo.io/embed.js';
7 |
8 | export type SnackProps = {
9 | /** The usename and snack id */
10 | snackId: string;
11 | /** Platform */
12 | platform?: 'web' | 'android' | 'ios' | 'mydevice';
13 | /** The snack theme */
14 | theme?: 'light' | 'dark';
15 | };
16 |
17 | export const Snack: Component = (props) => {
18 | const props_ = mergeProps(
19 | {
20 | platform: 'web',
21 | theme: 'light',
22 | },
23 | props
24 | );
25 | return (
26 | createScriptLoader({ src: scriptUrl })}>
27 |
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/src/components/soundcloud/index.ts:
--------------------------------------------------------------------------------
1 | export { SoundCloud } from './soundcloud';
2 | export type { SoundCloudProps } from './soundcloud';
3 |
--------------------------------------------------------------------------------
/src/components/soundcloud/soundcloud.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import type { Component } from 'solid-js';
4 |
5 | export type SoundCloudProps = {
6 | /** SoundCloud link */
7 | soundCloudLink: string;
8 | /** Auto play audio */
9 | autoPlay?: boolean;
10 | /** Show the visual artwork */
11 | visual?: boolean;
12 | /** Width for the iFrame */
13 | width?: number | string;
14 | /** Height for the iFrame */
15 | height?: number | string;
16 | /** The color of the play button without the # */
17 | color?: string;
18 | };
19 |
20 | export const SoundCloud: Component = (props) => {
21 | const props_ = mergeProps(
22 | {
23 | width: '100%',
24 | height: 'auto',
25 | autoPlay: false,
26 | visual: false,
27 | color: '23ff00f5',
28 | },
29 | props
30 | );
31 | return (
32 |
33 |
45 |
46 | );
47 | };
48 |
--------------------------------------------------------------------------------
/src/components/spotify/index.ts:
--------------------------------------------------------------------------------
1 | export { Spotify } from './spotify';
2 | export type { SpotifyProps } from './spotify';
3 |
--------------------------------------------------------------------------------
/src/components/spotify/spotify.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps, type Component } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 |
4 | export type SpotifyProps = {
5 | /** Spotify link */
6 | spotifyLink: string;
7 | /** Width for the iFrame */
8 | width?: number | string;
9 | /** Height for the iFrame */
10 | height?: number | string;
11 | /** theme */
12 | theme?: 'dark';
13 | };
14 |
15 | export const Spotify: Component = (props) => {
16 | const props_ = mergeProps(
17 | {
18 | width: '100%',
19 | height: 352,
20 | },
21 | props
22 | );
23 |
24 | return (
25 |
26 |
40 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/src/components/strava/index.ts:
--------------------------------------------------------------------------------
1 | export { Strava } from './strava';
2 | export type { StravaProps } from './strava';
3 |
--------------------------------------------------------------------------------
/src/components/strava/strava.tsx:
--------------------------------------------------------------------------------
1 | import { GeneralObserver } from '../general-observer';
2 | import type { Component } from 'solid-js';
3 |
4 | export type StravaProps = {
5 | /** The Strava activityId */
6 | activityId: string;
7 | };
8 |
9 | export const Strava: Component = (props) => (
10 |
11 |
21 |
31 |
32 |
33 | );
34 |
--------------------------------------------------------------------------------
/src/components/tiktok/index.ts:
--------------------------------------------------------------------------------
1 | export { TikTok } from './tiktok';
2 | export type { TikTokProps } from './tiktok';
3 |
--------------------------------------------------------------------------------
/src/components/tiktok/tiktok.tsx:
--------------------------------------------------------------------------------
1 | import { GeneralObserver } from '../general-observer';
2 | import { handleTikTokLoad } from './utilities';
3 | import type { Component } from 'solid-js';
4 |
5 | export type TikTokProps = {
6 | /** TikTok id */
7 | tikTokId: string;
8 | };
9 |
10 | export const TikTok: Component = (props) => (
11 |
12 |
17 |
20 |
21 |
22 | );
23 |
--------------------------------------------------------------------------------
/src/components/tiktok/utilities.ts:
--------------------------------------------------------------------------------
1 | import { createScriptLoader } from '@solid-primitives/script-loader';
2 |
3 | export const handleTikTokLoad = (): void => {
4 | if (document.querySelector('.tiktok') && !window.tiktok)
5 | createScriptLoader({ src: '//www.tiktok.com/embed.js' });
6 | };
7 |
--------------------------------------------------------------------------------
/src/components/twitch/index.ts:
--------------------------------------------------------------------------------
1 | export { Twitch } from './twitch';
2 | export type { TwitchProps } from './twitch';
3 |
--------------------------------------------------------------------------------
/src/components/twitch/twitch.tsx:
--------------------------------------------------------------------------------
1 | import { createMemo, mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { constructTwitchURL } from './utilities';
4 | import { getPadding } from '../../utilities';
5 | import type { Component } from 'solid-js';
6 |
7 | export type TwitchProps = {
8 | /** Domain(s) that will be embedding Twitch. You must have one parent key for each domain your site uses. */
9 | parent: string;
10 | /** Twitch id */
11 | twitchId?: string;
12 | /** Skip to a time in the video */
13 | skipTo?: {
14 | h?: number;
15 | m: number;
16 | s: number;
17 | };
18 | /** Auto play the video */
19 | autoPlay?: boolean;
20 | /** Name of the channel, for a live stream */
21 | channel?: string;
22 | /** Collection ID, for a collection of videos */
23 | collection?: string;
24 | };
25 |
26 | export const Twitch: Component = (props) => {
27 | const props_ = mergeProps(
28 | {
29 | parent: 'localhost',
30 | autoPlay: false,
31 | skipTo: { h: 0, m: 0, s: 0 },
32 | channel: '',
33 | collection: '',
34 | },
35 | props
36 | );
37 | const title = createMemo(() => (props_.twitchId ? `twitch-${props_.twitchId}` : `twitch`));
38 | const baseUrl = createMemo(
39 | () =>
40 | `//player.twitch.tv/?autoplay=${props_.autoPlay.toString()}&t=${props_.skipTo.h ?? 0}h${
41 | props_.skipTo.m
42 | }m${props_.skipTo.s}s&parent=${props_.parent}`
43 | );
44 | const constructedSourceURL = createMemo(() =>
45 | constructTwitchURL(props_.twitchId, props_.channel, props_.collection, baseUrl())
46 | );
47 |
48 | return (
49 |
50 |
58 |
71 |
72 |
73 | );
74 | };
75 |
--------------------------------------------------------------------------------
/src/components/twitch/utilities.ts:
--------------------------------------------------------------------------------
1 | export function constructTwitchURL(
2 | twitchId?: string,
3 | channel?: string,
4 | collection?: string,
5 | baseUrl?: string
6 | ): string {
7 | const sourceBlocks = [baseUrl];
8 |
9 | if (twitchId) {
10 | sourceBlocks.push(`&video=v${twitchId}`);
11 | } else if (channel) {
12 | sourceBlocks.push(`&channel=${channel}`);
13 | } else if (collection) {
14 | sourceBlocks.push(`&collection=${collection}`);
15 | }
16 |
17 | return sourceBlocks.join('');
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/twitter/index.ts:
--------------------------------------------------------------------------------
1 | export { Tweet } from './tweet';
2 | export { TwitterFollowButton } from './twitter-follow-button';
3 | export { TwitterHashtagButton } from './twitter-hashtag-button';
4 | export { TwitterList } from './twitter-list';
5 | export { TwitterMentionButton } from './twitter-mention-button';
6 | export { TwitterTimeline } from './twitter-timeline';
7 | export type { TweetProps } from './tweet';
8 | export type { TwitterFollowButtonProps } from './twitter-follow-button';
9 | export type { TwitterHashtagButtonProps } from './twitter-hashtag-button';
10 | export type { TwitterListProps } from './twitter-list';
11 | export type { TwitterMentionButtonProps } from './twitter-mention-button';
12 | export type { TwitterTimelineProps } from './twitter-timeline';
13 |
--------------------------------------------------------------------------------
/src/components/twitter/tweet.tsx:
--------------------------------------------------------------------------------
1 | import { createEffect, createMemo, mergeProps, on } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handleTwttrLoad, handleTwttrUpdate } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type TweetProps = {
7 | /** Tweet link */
8 | tweetLink: string;
9 | /** Color theme of the Tweet */
10 | theme?: 'light' | 'dark';
11 | /** Alignment of the Tweet */
12 | align?: 'left' | 'center' | 'right';
13 | /** Hides the conversation */
14 | hideConversation?: boolean;
15 | };
16 |
17 | export const Tweet: Component = (props) => {
18 | const props_ = mergeProps(
19 | {
20 | theme: 'light',
21 | align: 'left',
22 | hideConversation: false,
23 | } as const,
24 | props
25 | );
26 | const tweetId = createMemo(() => props_.tweetLink.split('/').at(-1) ?? '');
27 | createEffect(
28 | on(
29 | () => [props_.align, props_.theme, props_.hideConversation, props_.tweetLink],
30 | () => handleTwttrUpdate(`iframe[data-tweet-id="${tweetId()}"]`, props_),
31 | { defer: true }
32 | )
33 | );
34 | return (
35 |
36 |
50 |
51 | );
52 | };
53 |
--------------------------------------------------------------------------------
/src/components/twitter/twitter-follow-button.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handleTwttrLoad } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type TwitterFollowButtonProps = {
7 | /** Twitter username */
8 | username: string;
9 | /** Show the follower count */
10 | showFollowers?: boolean;
11 | /** Show the username */
12 | showUsername?: boolean;
13 | /** The size of the button */
14 | size?: 'large' | 'small';
15 | };
16 |
17 | export const TwitterFollowButton: Component = (props) => {
18 | const props_ = mergeProps(
19 | {
20 | showFollowers: false,
21 | showUsername: true,
22 | size: 'small',
23 | },
24 | props
25 | );
26 | return (
27 |
28 |
35 |
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/src/components/twitter/twitter-hashtag-button.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handleTwttrLoad } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type TwitterHashtagButtonProps = {
7 | /** Twitter hashtag */
8 | hashtag: string;
9 | /** The size of the button */
10 | size?: 'large' | 'small';
11 | };
12 |
13 | export const TwitterHashtagButton: Component = (props) => {
14 | const props_ = mergeProps(
15 | {
16 | size: 'small',
17 | },
18 | props
19 | );
20 | return (
21 |
22 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/components/twitter/twitter-list.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handleTwttrLoad } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type TwitterListProps = {
7 | /** Twitter username */
8 | username: string;
9 | /** The Twitter list name */
10 | listName: string;
11 | /** Color theme of the Timeline */
12 | theme?: 'light' | 'dark';
13 | /** Width for the iFrame */
14 | width?: number | string;
15 | /** Height for the iFrame. Null is full height */
16 | height?: number | string;
17 | };
18 |
19 | export const TwitterList: Component = (props) => {
20 | const props_ = mergeProps({ theme: 'light', width: '498px', height: undefined }, props);
21 | return (
22 |
23 |
34 |
35 | );
36 | };
37 |
--------------------------------------------------------------------------------
/src/components/twitter/twitter-mention-button.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handleTwttrLoad } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type TwitterMentionButtonProps = {
7 | /** Twitter username */
8 | username: string;
9 | /** The size of the button */
10 | size?: 'large' | 'small';
11 | };
12 |
13 | export const TwitterMentionButton: Component = (props) => {
14 | const props_ = mergeProps(
15 | {
16 | size: 'small',
17 | },
18 | props
19 | );
20 | return (
21 |
22 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/components/twitter/twitter-timeline.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { handleTwttrLoad } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type TwitterTimelineProps = {
7 | /** Twitter username */
8 | username: string;
9 | /** Show Tweets liked by the username */
10 | showLikes?: boolean;
11 | /** Color theme of the Timeline */
12 | theme?: 'light' | 'dark';
13 | /** Width for the iFrame */
14 | width?: number | string;
15 | /** Height for the iFrame. Null is full height */
16 | height?: number | string;
17 | };
18 |
19 | export const TwitterTimeline: Component = (props) => {
20 | const props_ = mergeProps(
21 | {
22 | theme: 'light',
23 | width: '498px',
24 | },
25 | props
26 | );
27 | return (
28 |
29 |
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/src/components/twitter/utilities.ts:
--------------------------------------------------------------------------------
1 | import { createScriptLoader } from '@solid-primitives/script-loader';
2 |
3 | const twttrClasses = [
4 | 'twitter-tweet',
5 | 'twitter-follow-button',
6 | 'twitter-hashtag-button',
7 | 'twitter-list',
8 | 'twitter-mention-button',
9 | 'twitter-timeline',
10 | ]
11 | .map((twttrClass) => `.${twttrClass}`)
12 | .join(',');
13 |
14 | const twttrLoad = (): void =>
15 | document
16 | .querySelectorAll(twttrClasses)
17 | .forEach((element) => void window.twttr?.widgets.load(element));
18 |
19 | export const handleTwttrLoad = (): void => {
20 | if (document.querySelector(twttrClasses) && !window.twttr)
21 | createScriptLoader({ src: '//platform.twitter.com/widgets.js' });
22 | else twttrLoad();
23 | };
24 |
25 | export const handleTwttrUpdate = (
26 | targetElement: string,
27 | { theme }: { theme: 'light' | 'dark' }
28 | ): void => {
29 | const tweet = document.querySelector(targetElement);
30 | const source = tweet?.getAttribute('src');
31 | if (source) tweet?.setAttribute('src', source.replace(/theme=([^&]*)/, `theme=${theme}`));
32 | };
33 |
--------------------------------------------------------------------------------
/src/components/vimeo/index.tsx:
--------------------------------------------------------------------------------
1 | export { Vimeo } from './vimeo';
2 | export type { VimeoProps } from './vimeo';
3 |
--------------------------------------------------------------------------------
/src/components/vimeo/vimeo.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { getPadding } from '../../utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type VimeoProps = {
7 | /** Vimeo id */
8 | vimeoId: string;
9 | /** Skip to a time in the video */
10 | skipTo?: {
11 | h?: number;
12 | m: number;
13 | s: number;
14 | };
15 | /** Auto play the video */
16 | autoPlay?: boolean;
17 | };
18 |
19 | export const Vimeo: Component = (props) => {
20 | const props_ = mergeProps(
21 | {
22 | autoPlay: false,
23 | skipTo: { h: 0, m: 0, s: 0 },
24 | },
25 | props
26 | );
27 | return (
28 |
29 |
37 |
54 |
55 |
56 | );
57 | };
58 |
--------------------------------------------------------------------------------
/src/components/whimsical/index.ts:
--------------------------------------------------------------------------------
1 | export { Whimsical } from './whimsical';
2 | export type { WhimsicalProps } from './whimsical';
3 |
--------------------------------------------------------------------------------
/src/components/whimsical/utilities.ts:
--------------------------------------------------------------------------------
1 | export function getPadding(aspectRatio: string): { paddingTop: string } {
2 | const regExp = /^([1-9]\d*):([1-9]\d*)$/;
3 | const [, width, height] = regExp.exec(aspectRatio) ?? ['', '1', '1'];
4 |
5 | return {
6 | paddingTop: `${(100 * Number.parseInt(height, 10)) / Number.parseInt(width, 10)}%`,
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/whimsical/whimsical.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { getPadding } from './utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type WhimsicalProps = {
7 | /**
8 | * Whimsical id. Ex:
9 | * - given a public URL: //whimsical.com/Py4kdjbPzFpRoAPMbUxmaN
10 | * - diagramId will be: Py4kdjbPzFpRoAPMbUxmaN
11 | */
12 | diagramId: string;
13 |
14 | /**
15 | * Aspect ratio of Whimsical diagram
16 | */
17 | aspectRatio?: string;
18 | };
19 |
20 | export const Whimsical: Component = (props) => {
21 | const props_ = mergeProps(
22 | {
23 | aspectRatio: '1:1',
24 | },
25 | props
26 | );
27 | return (
28 |
29 |
37 |
50 |
51 |
52 | );
53 | };
54 |
--------------------------------------------------------------------------------
/src/components/wikipedia/index.ts:
--------------------------------------------------------------------------------
1 | export { Wikipedia } from './wikipedia';
2 | export type { WikipediaProps } from './wikipedia';
3 |
--------------------------------------------------------------------------------
/src/components/wikipedia/wikipedia.tsx:
--------------------------------------------------------------------------------
1 | import { createResource, ErrorBoundary, mergeProps, Suspense } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import type { Component } from 'solid-js';
4 |
5 | export type WikipediaProps = {
6 | /** Wikipedia page link */
7 | wikipediaLink: string;
8 | /** Height for the iFrame */
9 | height?: number | string;
10 | };
11 |
12 | export const Wikipedia: Component = (props) => {
13 | const props_ = mergeProps({ height: 600 }, props);
14 | const getWikipediaHtml = async (wikipediaLink: string): Promise => {
15 | const response = await fetch(`//en.wikipedia.org/api/rest_v1/page/html/${wikipediaLink}`);
16 | const text = await response.text();
17 | return text.replace(/ props_.wikipediaLink, getWikipediaHtml);
21 |
22 | return (
23 |
24 | {String(error)}
}>
25 |
26 |
36 |
37 |
38 |
39 | );
40 | };
41 |
--------------------------------------------------------------------------------
/src/components/wistia/index.ts:
--------------------------------------------------------------------------------
1 | export { Wistia } from './wistia';
2 | export type { WistiaProps } from './wistia';
3 |
--------------------------------------------------------------------------------
/src/components/wistia/utilities.ts:
--------------------------------------------------------------------------------
1 | import { createScriptLoader } from '@solid-primitives/script-loader';
2 |
3 | let isWistiaAdded = false;
4 | const embedUrl = `//fast.wistia.net/assets/external/E-v1.js`;
5 |
6 | export const handleWistiaLoad = (): void => {
7 | if (!isWistiaAdded) createScriptLoader({ src: embedUrl, onload: () => (isWistiaAdded = true) });
8 | };
9 |
--------------------------------------------------------------------------------
/src/components/wistia/wistia.tsx:
--------------------------------------------------------------------------------
1 | import { mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { getPadding } from '../../utilities';
4 | import { handleWistiaLoad } from './utilities';
5 | import type { Component } from 'solid-js';
6 |
7 | export type WistiaProps = {
8 | /** Video ID, extracted from Wistia URL. */
9 | videoId: string;
10 | /** Enable player's "full screen" control. */
11 | allowfullscreen?: boolean;
12 | /** Video player's width, set to 100% (default) for responsive, or exact value for fixed (eg. "640px"). */
13 | width?: string;
14 | /** Video player's height, set to 100% (default) for responsive, or exact value for fixed (eg. "380px"). */
15 | height?: string;
16 | /** Aspect ratio of the video, used to calculate padding offset. */
17 | aspectRatio?: '1:1' | '16:9' | '4:3' | '3:2' | '8:5';
18 | /** Auto play video when component renders. */
19 | autoPlay?: boolean;
20 | };
21 |
22 | export const Wistia: Component = (props) => {
23 | const props_ = mergeProps(
24 | {
25 | allowfullscreen: true,
26 | aspectRatio: '16:9',
27 | width: '100%',
28 | height: '100%',
29 | autoPlay: false,
30 | },
31 | props
32 | );
33 |
34 | return (
35 |
36 |
44 |
59 |
60 |
61 | );
62 | };
63 |
--------------------------------------------------------------------------------
/src/components/youtube/index.ts:
--------------------------------------------------------------------------------
1 | export { YouTube } from './youtube';
2 | export { YouTubeProps } from './youtube';
3 |
--------------------------------------------------------------------------------
/src/components/youtube/youtube.tsx:
--------------------------------------------------------------------------------
1 | import { createMemo, mergeProps } from 'solid-js';
2 | import { GeneralObserver } from '../general-observer';
3 | import { getPadding } from '../../utilities';
4 | import type { Component } from 'solid-js';
5 |
6 | export type YouTubeProps = {
7 | /** YouTube id */
8 | youTubeId?: string;
9 | /** YouTube Playlist id */
10 | youTubePlaylistId?: string;
11 | /** Aspect ratio of YouTube video */
12 | aspectRatio?: '1:1' | '16:9' | '4:3' | '3:2' | '8:5';
13 | /** Skip to a time in the video */
14 | skipTo?: {
15 | h?: number;
16 | m: number;
17 | s: number;
18 | };
19 | /** Auto play the video */
20 | autoPlay?: boolean;
21 | /** No Cookie option */
22 | noCookie?: boolean;
23 | };
24 |
25 | export const YouTube: Component = (props) => {
26 | const props_ = mergeProps(
27 | {
28 | aspectRatio: '16:9',
29 | autoPlay: false,
30 | skipTo: { h: 0, m: 0, s: 0 },
31 | noCookie: false,
32 | } as const,
33 | props
34 | );
35 |
36 | const startTime = createMemo(() => {
37 | const { h, m, s } = props_.skipTo;
38 | return (h ?? 0) * 60 + m * 60 + s;
39 | });
40 |
41 | const source = createMemo(
42 | () =>
43 | `//www.youtube${props_.noCookie ? '-nocookie' : ''}.com/embed/${
44 | props_.youTubeId
45 | ? `${props_.youTubeId}?&autoplay=${props_.autoPlay.toString()}&start=${startTime()}`
46 | : `&videoseries?list=${props_.youTubePlaylistId ?? ''}`
47 | }`
48 | );
49 |
50 | return (
51 |
52 |
60 |
73 |
74 |
75 | );
76 | };
77 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { AirtableBase, AirtableForm } from './components/airtable';
2 | export { Buzzsprout } from './components/buzzsprout';
3 | export { Cinnamon } from './components/cinnamon';
4 | export { CodePen } from './components/codepen';
5 | export { CodeSandbox } from './components/codesandbox';
6 | export { EggheadLesson } from './components/egghead';
7 | export { Figma } from './components/figma';
8 | export { Flickr } from './components/flickr';
9 | export { Gist } from './components/gist';
10 | export { Instagram } from './components/instagram';
11 | export { Lbry } from './components/lbry';
12 | export { LinkedInBadge } from './components/linkedin';
13 | export { ListenNotesEpisode } from './components/listennotes';
14 | export { Pin, PinterestBoard, PinterestFollowButton } from './components/pinterest';
15 | export { SimplecastEpisode } from './components/simplecast';
16 | export { Snack } from './components/snack';
17 | export { SoundCloud } from './components/soundcloud';
18 | export { Spotify } from './components/spotify';
19 | export { Strava } from './components/strava';
20 | export { TikTok } from './components/tiktok';
21 | export { Twitch } from './components/twitch';
22 | export {
23 | Tweet,
24 | TwitterFollowButton,
25 | TwitterHashtagButton,
26 | TwitterList,
27 | TwitterMentionButton,
28 | TwitterTimeline,
29 | } from './components/twitter';
30 | export { Vimeo } from './components/vimeo';
31 | export { Whimsical } from './components/whimsical';
32 | export { Wikipedia } from './components/wikipedia';
33 | export { Wistia } from './components/wistia';
34 | export { YouTube } from './components/youtube';
35 | export type { AirtableBaseProps, AirtableFormProps } from './components/airtable';
36 | export type { BuzzsproutProps } from './components/buzzsprout';
37 | export type { CinnamonProps } from './components/cinnamon';
38 | export type { CodePenProps } from './components/codepen';
39 | export type { CodeSandboxProps } from './components/codesandbox';
40 | export type { EggheadLessonProps } from './components/egghead';
41 | export type { FigmaProps } from './components/figma';
42 | export type { FlickrProps } from './components/flickr';
43 | export type { GistProps } from './components/gist';
44 | export type { InstagramProps } from './components/instagram';
45 | export type { LbryProps } from './components/lbry';
46 | export type { LinkedInBadgeProps } from './components/linkedin';
47 | export type { ListenNotesEpisodeProps } from './components/listennotes';
48 | export type {
49 | PinProps,
50 | PinterestBoardProps,
51 | PinterestFollowButtonProps,
52 | } from './components/pinterest';
53 | export type { SimplecastEpisodeProps } from './components/simplecast';
54 | export type { SnackProps } from './components/snack';
55 | export type { SoundCloudProps } from './components/soundcloud';
56 | export type { SpotifyProps } from './components/spotify';
57 | export type { StravaProps } from './components/strava';
58 | export type { TikTokProps } from './components/tiktok';
59 | export type { TwitchProps } from './components/twitch';
60 | export type {
61 | TweetProps,
62 | TwitterFollowButtonProps,
63 | TwitterHashtagButtonProps,
64 | TwitterListProps,
65 | TwitterMentionButtonProps,
66 | TwitterTimelineProps,
67 | } from './components/twitter';
68 | export type { VimeoProps } from './components/vimeo';
69 | export type { WhimsicalProps } from './components/whimsical';
70 | export type { WikipediaProps } from './components/wikipedia';
71 | export type { WistiaProps } from './components/wistia';
72 | export type { YouTubeProps } from './components/youtube';
73 |
--------------------------------------------------------------------------------
/src/utilities/index.ts:
--------------------------------------------------------------------------------
1 | export const getPadding = (aspectRatio: string): Record<'padding-top', string> => {
2 | const config: Record = {
3 | '1:1': {
4 | 'padding-top': '100%',
5 | },
6 | '16:9': {
7 | 'padding-top': '56.25%',
8 | },
9 | '4:3': {
10 | 'padding-top': '75%',
11 | },
12 | '3:2': {
13 | 'padding-top': '66.66%',
14 | },
15 | '8.5': {
16 | 'padding-top': '62.5%',
17 | },
18 | };
19 | return config[aspectRatio];
20 | };
21 |
22 | export const createStyleSheet = (href: string): void => {
23 | const link = document.createElement(`link`);
24 |
25 | link.type = `text/css`;
26 | link.rel = `stylesheet`;
27 | link.href = href;
28 |
29 | document.querySelectorAll(`head`)[0].append(link);
30 | };
31 |
--------------------------------------------------------------------------------
/src/window.d.ts:
--------------------------------------------------------------------------------
1 | export {};
2 |
3 | declare global {
4 | // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
5 | interface Window {
6 | twttr?: {
7 | ready: () => Promise;
8 | widgets: {
9 | createTweet: (
10 | tweetId: string,
11 | elementId: Element,
12 | options: Record
13 | ) => Promise;
14 | load: (element: Element | NodeListOf | null) => Promise;
15 | };
16 | };
17 | instgrm?: {
18 | Embeds: {
19 | process: () => void;
20 | };
21 | };
22 | LI?: unknown;
23 | LIRenderAll?: () => void;
24 | PinUtils?: {
25 | build: () => void;
26 | };
27 | tiktok: unknown;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "lib": ["DOM", "ESNext"],
5 | "jsx": "preserve",
6 | "jsxImportSource": "solid-js",
7 | "module": "esnext",
8 | "moduleResolution": "node",
9 | "baseUrl": ".",
10 | "types": [],
11 | "declaration": true,
12 | "declarationDir": "./dist",
13 | "esModuleInterop": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noEmit": true,
16 | "strict": true,
17 | "skipLibCheck": true
18 | }
19 | }
20 |
--------------------------------------------------------------------------------