···11+export * from './action-buttons';
12export * from './atproto-login';
33+export * from './embed';
24export * from './post';
35export * from './star-rating';
46export * from './social-icons';
···1214export * from './link-card';
1315export * from './animated-emoji-picker';
1416export * from './atproto-handle-popup';
1515-export * from './bluesky-post-creator';
1717+export * from './microblogging-post-creator';
16181719export function numberToHumanReadable(number: number) {
1820 if (number < 1000) {
···11+export type {
22+ ReplyButtonProps,
33+ RepostButtonProps,
44+ LikeButtonProps,
55+ BookmarkButtonProps,
66+ ActionButtonsProps
77+} from './types';
88+99+export { default as ActionButtons } from './ActionButtons.svelte';
1010+export { default as ReplyButton } from './ReplyButton.svelte';
1111+export { default as RepostButton } from './RepostButton.svelte';
1212+export { default as LikeButton } from './LikeButton.svelte';
1313+export { default as BookmarkButton } from './BookmarkButton.svelte';
···11-export { default as BlueskyPostCreator } from './BlueskyPostCreator.svelte';
22-export { editorJsonToBlueskyPost } from './facets';
33-export type { BlueskyPostContent, BlueskyFacet } from './facets';
···1515 import('emoji-picker-element').then(({ Database }) => {
1616 emojiDatabase.db = new Database();
17171818- // go through all groups and check if the emoji is supported (will be cached)
1919- // so that things appear faster when we select a group
2020- for (const group of allGroups) {
2121- emojiDatabase.db.getEmojiByGroup(group.id).then((emojis) => {
2222- for (const emoji of emojis) {
2323- isEmojiSupported(emoji.unicode);
2424- }
2525- });
2626- }
1818+ // only pre-cache the first group, others get cached on demand when selected
1919+ emojiDatabase.db.getEmojiByGroup(allGroups[0].id).then((emojis) => {
2020+ for (const emoji of emojis) {
2121+ isEmojiSupported(emoji.unicode);
2222+ }
2323+ });
2724 });
2825 console.log('emojis loaded');
2926 }
···11+export { default as MicrobloggingPostCreator } from './MicrobloggingPostCreator.svelte';
22+export type { MicrobloggingPostContent } from './MicrobloggingPostCreator.svelte';
33+export {
44+ createBlueskyMentionSearch,
55+ editorJsonToBlueskyPost,
66+ type BlueskyPostContent,
77+ type BlueskyFacet
88+} from './bluesky';
···11-## Usage
22-33-```svelte
44-<script lang="ts">
55- import { BlueskyPostCreator, type BlueskyPostContent } from '@foxui/social';
66-77- let content: BlueskyPostContent = $state({ text: '', facets: [] });
88-</script>
99-1010-<BlueskyPostCreator
1111- bind:content
1212- placeholder="What's on your mind?"
1313- maxLength={300}
1414-/>
1515-```
1616-1717-## Features
1818-1919-- **@mentions** - Type `@` followed by at least 2 characters to search for Bluesky handles. Select from the popup to insert a mention with the user's DID.
2020-- **Links** - URLs are automatically detected and linked.
2121-- **#hashtags** - Type `#tag` and hashtags are automatically detected in the output facets.
2222-- **Character count** - Shows remaining characters with color indicators (amber < 20, red when over limit).
2323-2424-## Output
2525-2626-The `content` bindable returns a `BlueskyPostContent` object:
2727-2828-```typescript
2929-{
3030- text: string; // Plain text of the post
3131- facets: BlueskyFacet[]; // Byte-indexed facets for mentions, links, and tags
3232-}
3333-```
3434-3535-Each facet has the Bluesky AT Protocol format with `index.byteStart`, `index.byteEnd`, and `features` array containing the facet type (`#mention`, `#link`, or `#tag`).
···11-import Docs from './Documentation.md';
22-import Example from './Example.svelte';
33-import Card from './Card.svelte';
44-import api from './api';
55-66-export default {
77- slug: 'bluesky-post-creator',
88- title: 'Bluesky Post Creator',
99- docs: Docs,
1010- example: Example,
1111- card: Card,
1212- api
1313-};
···11+The `BlueskyPost` component renders a Bluesky post directly from the raw API response (`PostView`). It handles converting the data, rich text facets, embeds, and NSFW labels automatically.
22+33+Fetch posts using the [Bluesky API](https://docs.bsky.app/docs/api/app-bsky-feed-get-author-feed) and pass each post's `post` and `reason` fields directly to the component.
44+55+Use `blueskyPostToPostData` if you need to convert the data yourself for use with the generic `Post` component.
···11+## Usage
22+33+```svelte
44+<script lang="ts">
55+ import {
66+ MicrobloggingPostCreator,
77+ createBlueskyMentionSearch,
88+ type MicrobloggingPostContent
99+ } from '@foxui/social';
1010+1111+ let content: MicrobloggingPostContent = $state({ text: '', json: { type: 'doc' } });
1212+</script>
1313+1414+<MicrobloggingPostCreator
1515+ bind:content
1616+ searchMentions={createBlueskyMentionSearch()}
1717+ maxLength={300}
1818+/>
1919+```
2020+2121+## Features
2222+2323+- **@mentions** - Provide a `searchMentions` function to enable mention support. Type `@` followed by at least 2 characters to trigger the search popup.
2424+- **Links** - URLs are automatically detected and linked.
2525+- **#hashtags** - Hashtags are visually highlighted in the editor.
2626+- **Embeds** - When a link is added and no embed exists, the `embed` prop is automatically set to `{ type: 'link', url, text }`. Provide an `embedPreview` snippet to render it.
2727+- **Character count** - Shows remaining characters with color indicators (amber < 20, red when over limit).
2828+2929+## Bluesky Integration
3030+3131+Use the provided helpers for Bluesky:
3232+3333+```svelte
3434+<script lang="ts">
3535+ import {
3636+ MicrobloggingPostCreator,
3737+ createBlueskyMentionSearch,
3838+ editorJsonToBlueskyPost,
3939+ type MicrobloggingPostContent
4040+ } from '@foxui/social';
4141+4242+ let content: MicrobloggingPostContent = $state({ text: '', json: { type: 'doc' } });
4343+4444+ // Convert to Bluesky format when posting
4545+ function post() {
4646+ const blueskyContent = editorJsonToBlueskyPost(content.json);
4747+ // blueskyContent.text + blueskyContent.facets
4848+ }
4949+</script>
5050+5151+<MicrobloggingPostCreator
5252+ bind:content
5353+ searchMentions={createBlueskyMentionSearch()}
5454+/>
5555+```
5656+5757+## Embeds
5858+5959+Bind the `embed` prop and provide an `embedPreview` snippet to show embed previews:
6060+6161+```svelte
6262+<script lang="ts">
6363+ import { MicrobloggingPostCreator } from '@foxui/social';
6464+6565+ let embed = $state();
6666+</script>
6767+6868+<MicrobloggingPostCreator bind:embed>
6969+ {#snippet embedPreview({ embed, removeEmbed })}
7070+ <div class="flex items-center gap-2 rounded-xl border p-3">
7171+ <span class="flex-1 truncate text-sm">{embed.url}</span>
7272+ <button onclick={removeEmbed}>Remove</button>
7373+ </div>
7474+ {/snippet}
7575+</MicrobloggingPostCreator>
7676+```
···11+import Docs from './Documentation.md';
22+import Example from './Example.svelte';
33+import Card from './Card.svelte';
44+import api from './api';
55+66+export default {
77+ slug: 'microblogging-post-creator',
88+ title: 'Microblogging Post Creator',
99+ docs: Docs,
1010+ example: Example,
1111+ card: Card,
1212+ api
1313+};
···2020npm install @foxui/core
2121```
22222323-## 3. Set theme variables in your `app.css`
2323+## 3. Set up your `app.css`
24242525-You can change the colors to your liking.
2525+Add the following to your `app.css` to import the theme (which includes the base/accent color system and all color classes):
26262727```css
2828-@source "../node_modules/@foxui";
2929-3028@custom-variant dark (&:is(.dark *));
31293232-@theme {
3333- --color-base-50: var(--color-zinc-50);
3434- --color-base-100: var(--color-zinc-100);
3535- --color-base-200: var(--color-zinc-200);
3636- --color-base-300: var(--color-zinc-300);
3737- --color-base-400: var(--color-zinc-400);
3838- --color-base-500: var(--color-zinc-500);
3939- --color-base-600: var(--color-zinc-600);
4040- --color-base-700: var(--color-zinc-700);
4141- --color-base-800: var(--color-zinc-800);
4242- --color-base-900: var(--color-zinc-900);
4343- --color-base-950: var(--color-zinc-950);
4444-4545- --color-accent-50: var(--color-emerald-50);
4646- --color-accent-100: var(--color-emerald-100);
4747- --color-accent-200: var(--color-emerald-200);
4848- --color-accent-300: var(--color-emerald-300);
4949- --color-accent-400: var(--color-emerald-400);
5050- --color-accent-500: var(--color-emerald-500);
5151- --color-accent-600: var(--color-emerald-600);
5252- --color-accent-700: var(--color-emerald-700);
5353- --color-accent-800: var(--color-emerald-800);
5454- --color-accent-900: var(--color-emerald-900);
5555- --color-accent-950: var(--color-emerald-950);
5656-}
3030+@import '@foxui/core/theme.css';
5731```
58325933## 4. Use a component