···15import { UpdatedBlentosCardDefitition } from './SpecialCards/UpdatedBlentos';
16import { TextCardDefinition } from './TextCard';
17import type { CardDefinition } from './types';
18-import { VideoCardDefinition } from './VideoCard';
19import { YoutubeCardDefinition } from './YoutubeVideoCard';
20import { BlueskyProfileCardDefinition } from './BlueskyProfileCard';
21import { GithubProfileCardDefitition } from './GitHubProfileCard';
···35import { SpotifyCardDefinition } from './SpotifyCard';
36import { ButtonCardDefinition } from './ButtonCard';
37import { GuestbookCardDefinition } from './GuestbookCard';
038// import { Model3DCardDefinition } from './Model3DCard';
3940export const AllCardDefinitions = [
41 GuestbookCardDefinition,
42 ButtonCardDefinition,
43 ImageCardDefinition,
44- VideoCardDefinition,
45 TextCardDefinition,
46 LinkCardDefinition,
47 BigSocialCardDefinition,
···51 LatestBlueskyPostCardDefinition,
52 LivestreamCardDefitition,
53 LivestreamEmbedCardDefitition,
54- EmbedCardDefinition,
55 MapCardDefinition,
56 ATProtoCollectionsCardDefinition,
57 SectionCardDefinition,
···73 TimerCardDefinition,
74 ClockCardDefinition,
75 CountdownCardDefinition,
76- SpotifyCardDefinition
77 // Model3DCardDefinition
078] as const;
7980export const CardDefinitionsByType = AllCardDefinitions.reduce(
···15import { UpdatedBlentosCardDefitition } from './SpecialCards/UpdatedBlentos';
16import { TextCardDefinition } from './TextCard';
17import type { CardDefinition } from './types';
018import { YoutubeCardDefinition } from './YoutubeVideoCard';
19import { BlueskyProfileCardDefinition } from './BlueskyProfileCard';
20import { GithubProfileCardDefitition } from './GitHubProfileCard';
···34import { SpotifyCardDefinition } from './SpotifyCard';
35import { ButtonCardDefinition } from './ButtonCard';
36import { GuestbookCardDefinition } from './GuestbookCard';
37+import { FriendsCardDefinition } from './FriendsCard';
38// import { Model3DCardDefinition } from './Model3DCard';
3940export const AllCardDefinitions = [
41 GuestbookCardDefinition,
42 ButtonCardDefinition,
43 ImageCardDefinition,
044 TextCardDefinition,
45 LinkCardDefinition,
46 BigSocialCardDefinition,
···50 LatestBlueskyPostCardDefinition,
51 LivestreamCardDefitition,
52 LivestreamEmbedCardDefitition,
53+ // EmbedCardDefinition,
54 MapCardDefinition,
55 ATProtoCollectionsCardDefinition,
56 SectionCardDefinition,
···72 TimerCardDefinition,
73 ClockCardDefinition,
74 CountdownCardDefinition,
75+ SpotifyCardDefinition,
76 // Model3DCardDefinition
77+ FriendsCardDefinition
78] as const;
7980export const CardDefinitionsByType = AllCardDefinitions.reduce(
-7
src/lib/cards/types.ts
···13 onclose: () => void;
14};
1516-export type SidebarComponentProps = {
17- onclick: () => void;
18-};
19-20export type ContentComponentProps = {
21 item: Item;
22 isEditing?: boolean;
···32 creationModalComponent?: Component<CreationModalComponentProps>;
3334 upload?: (item: Item) => Promise<Item>; // optionally upload some other data needed for this card
35-36- // has to be set for a card to appear in the sidebar
37- sidebarButtonText?: string;
3839 // if this component exists, a settings button with a popover will be shown containing this component
40 settingsComponent?: Component<SettingsComponentProps>;
···13 onclose: () => void;
14};
15000016export type ContentComponentProps = {
17 item: Item;
18 isEditing?: boolean;
···28 creationModalComponent?: Component<CreationModalComponentProps>;
2930 upload?: (item: Item) => Promise<Item>; // optionally upload some other data needed for this card
0003132 // if this component exists, a settings button with a popover will be shown containing this component
33 settingsComponent?: Component<SettingsComponentProps>;
···51 if (fromMobile) {
52 // Mobile → Desktop: reflow items to use the full grid width.
53 // Sort by mobile position so items are placed in reading order.
54- const sorted = items.toSorted(
55- (a, b) => a.mobileY - b.mobileY || a.mobileX - b.mobileX
56- );
5758 // Place each item into the first available spot on the desktop grid
59 const placed: Item[] = [];
···66 } else {
67 // Desktop → Mobile: proportional positions
68 for (const item of items) {
69- item.mobileX = clamp(
70- Math.floor((item.x * 2) / 2) * 2,
71- 0,
72- COLUMNS - item.mobileW
73- );
74 item.mobileY = Math.max(0, Math.round(item.y * 2));
75 }
76 fixAllCollisions(items, true);
···51 if (fromMobile) {
52 // Mobile → Desktop: reflow items to use the full grid width.
53 // Sort by mobile position so items are placed in reading order.
54+ const sorted = items.toSorted((a, b) => a.mobileY - b.mobileY || a.mobileX - b.mobileX);
005556 // Place each item into the first available spot on the desktop grid
57 const placed: Item[] = [];
···64 } else {
65 // Desktop → Mobile: proportional positions
66 for (const item of items) {
67+ item.mobileX = clamp(Math.floor((item.x * 2) / 2) * 2, 0, COLUMNS - item.mobileW);
000068 item.mobileY = Math.max(0, Math.round(item.y * 2));
69 }
70 fixAllCollisions(items, true);