@comergehq/studio 0.1.2 → 0.1.3
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.
- package/dist/index.js +255 -245
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +213 -203
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -5
- package/src/components/chat/ChatComposer.tsx +277 -0
- package/src/components/chat/ChatHeader.tsx +31 -0
- package/src/components/chat/ChatMessageBubble.tsx +69 -0
- package/src/components/chat/ChatMessageList.tsx +137 -0
- package/src/components/chat/ChatPage.tsx +69 -0
- package/src/components/chat/ForkNoticeBanner.tsx +66 -0
- package/src/components/chat/MultilineTextInput.tsx +46 -0
- package/src/components/chat/ScrollToBottomButton.tsx +78 -0
- package/src/components/chat/TypingIndicator.tsx +54 -0
- package/src/components/chat/index.ts +28 -0
- package/src/components/comments/AppCommentsSheet.tsx +213 -0
- package/src/components/comments/CommentRow.tsx +63 -0
- package/src/components/comments/formatTimeAgo.ts +3 -0
- package/src/components/comments/index.ts +3 -0
- package/src/components/comments/useAppComments.ts +74 -0
- package/src/components/comments/useAppDetails.ts +35 -0
- package/src/components/comments/useIosKeyboardSnapFix.ts +24 -0
- package/src/components/dialogs/ConfirmMergeRequestDialog.tsx +156 -0
- package/src/components/dialogs/index.ts +4 -0
- package/src/components/draw/DrawColorPicker.tsx +77 -0
- package/src/components/draw/DrawModeOverlay.tsx +144 -0
- package/src/components/draw/DrawSurface.tsx +127 -0
- package/src/components/draw/DrawToolbar.tsx +253 -0
- package/src/components/draw/index.ts +15 -0
- package/src/components/draw/optionalHaptics.ts +15 -0
- package/src/components/draw/strokes.ts +21 -0
- package/src/components/draw/types.ts +9 -0
- package/src/components/floating-draggable-button/FloatingDraggableButton.tsx +323 -0
- package/src/components/floating-draggable-button/constants.ts +17 -0
- package/src/components/floating-draggable-button/index.ts +4 -0
- package/src/components/floating-draggable-button/types.ts +63 -0
- package/src/components/icons/MergeIcon.tsx +14 -0
- package/src/components/icons/StudioIcons.tsx +66 -0
- package/src/components/index.ts +17 -0
- package/src/components/merge-requests/MergeRequestStatusCard.tsx +179 -0
- package/src/components/merge-requests/ReviewMergeRequestActionButton.tsx +62 -0
- package/src/components/merge-requests/ReviewMergeRequestCard.tsx +192 -0
- package/src/components/merge-requests/ReviewMergeRequestCarousel.tsx +132 -0
- package/src/components/merge-requests/index.ts +7 -0
- package/src/components/merge-requests/mergeRequestStatusDisplay.ts +23 -0
- package/src/components/merge-requests/toIsoString.ts +9 -0
- package/src/components/merge-requests/useControlledExpansion.ts +16 -0
- package/src/components/models/index.ts +9 -0
- package/src/components/models/types.ts +43 -0
- package/src/components/overlays/EdgeGlowFrame.tsx +105 -0
- package/src/components/overlays/index.ts +4 -0
- package/src/components/preview/PreviewHeroCard.tsx +58 -0
- package/src/components/preview/PreviewImage.tsx +22 -0
- package/src/components/preview/PreviewMetaRow.tsx +70 -0
- package/src/components/preview/PreviewPage.tsx +36 -0
- package/src/components/preview/PreviewPlaceholder.tsx +72 -0
- package/src/components/preview/PreviewStatusBadge.tsx +63 -0
- package/src/components/preview/StatsBar.tsx +109 -0
- package/src/components/preview/index.ts +22 -0
- package/src/components/primitives/Avatar.tsx +68 -0
- package/src/components/primitives/Button.tsx +102 -0
- package/src/components/primitives/Card.tsx +30 -0
- package/src/components/primitives/Divider.tsx +17 -0
- package/src/components/primitives/Icon.tsx +40 -0
- package/src/components/primitives/MarkdownText.tsx +72 -0
- package/src/components/primitives/Modal.tsx +53 -0
- package/src/components/primitives/Surface.tsx +42 -0
- package/src/components/primitives/Text.tsx +83 -0
- package/src/components/primitives/index.ts +35 -0
- package/src/components/primitives/types.ts +30 -0
- package/src/components/studio-sheet/StudioBottomSheet.tsx +114 -0
- package/src/components/studio-sheet/StudioSheetBackground.tsx +63 -0
- package/src/components/studio-sheet/StudioSheetHeader.tsx +35 -0
- package/src/components/studio-sheet/StudioSheetHeaderIconButton.tsx +109 -0
- package/src/components/studio-sheet/StudioSheetPager.tsx +66 -0
- package/src/components/studio-sheet/index.ts +18 -0
- package/src/components/studio-sheet/types.ts +5 -0
- package/src/components/utils/color.ts +25 -0
- package/src/components/utils/formatTimeAgo.ts +19 -0
- package/src/core/logger.ts +42 -0
- package/src/core/services/http/baseUrl.ts +3 -0
- package/src/core/services/http/index.ts +128 -0
- package/src/core/services/http/public.ts +14 -0
- package/src/core/services/supabase/auth.ts +41 -0
- package/src/core/services/supabase/client.ts +43 -0
- package/src/core/services/supabase/index.ts +7 -0
- package/src/data/agent/remote.ts +30 -0
- package/src/data/agent/repository.ts +34 -0
- package/src/data/agent/types.ts +28 -0
- package/src/data/apps/bundles/remote.ts +47 -0
- package/src/data/apps/bundles/repository.ts +35 -0
- package/src/data/apps/bundles/types.ts +27 -0
- package/src/data/apps/images/remote.ts +61 -0
- package/src/data/apps/images/repository.ts +47 -0
- package/src/data/apps/remote.ts +97 -0
- package/src/data/apps/repository.ts +185 -0
- package/src/data/apps/types.ts +206 -0
- package/src/data/attachment/remote.ts +32 -0
- package/src/data/attachment/repository.ts +40 -0
- package/src/data/attachment/types.ts +42 -0
- package/src/data/base-remote.ts +3 -0
- package/src/data/base-repository.ts +11 -0
- package/src/data/comments/likes/remote.ts +87 -0
- package/src/data/comments/likes/repository.ts +61 -0
- package/src/data/comments/likes/types.ts +47 -0
- package/src/data/comments/remote.ts +71 -0
- package/src/data/comments/repository.ts +53 -0
- package/src/data/comments/types.ts +60 -0
- package/src/data/github/remote.ts +23 -0
- package/src/data/github/repository.ts +35 -0
- package/src/data/github/types.ts +23 -0
- package/src/data/home/remote.ts +24 -0
- package/src/data/home/repository.ts +28 -0
- package/src/data/home/types.ts +70 -0
- package/src/data/index.ts +3 -0
- package/src/data/likes/remote.ts +57 -0
- package/src/data/likes/repository.ts +47 -0
- package/src/data/likes/types.ts +46 -0
- package/src/data/me/remote.ts +28 -0
- package/src/data/me/repository.ts +30 -0
- package/src/data/me/types.ts +14 -0
- package/src/data/merge-requests/remote.ts +76 -0
- package/src/data/merge-requests/repository.ts +66 -0
- package/src/data/merge-requests/types.ts +33 -0
- package/src/data/messages/remote.ts +21 -0
- package/src/data/messages/repository.ts +104 -0
- package/src/data/messages/types.ts +20 -0
- package/src/data/public/studio-config/remote.ts +19 -0
- package/src/data/public/studio-config/repository.ts +23 -0
- package/src/data/public/studio-config/types.ts +6 -0
- package/src/data/ratings/remote.ts +76 -0
- package/src/data/ratings/repository.ts +63 -0
- package/src/data/ratings/types.ts +57 -0
- package/src/data/threads/remote.ts +40 -0
- package/src/data/threads/repository.ts +41 -0
- package/src/data/threads/types.ts +25 -0
- package/src/data/types.ts +8 -0
- package/src/data/users/remote.ts +31 -0
- package/src/data/users/repository.ts +45 -0
- package/src/data/users/types.ts +15 -0
- package/src/index.ts +6 -0
- package/src/studio/ComergeStudio.tsx +246 -0
- package/src/studio/bootstrap/StudioBootstrap.tsx +45 -0
- package/src/studio/bootstrap/useStudioBootstrap.ts +51 -0
- package/src/studio/hooks/useApp.ts +83 -0
- package/src/studio/hooks/useAppStats.ts +111 -0
- package/src/studio/hooks/useAttachmentUpload.ts +59 -0
- package/src/studio/hooks/useBundleManager.ts +389 -0
- package/src/studio/hooks/useMergeRequests.ts +173 -0
- package/src/studio/hooks/useStudioActions.ts +96 -0
- package/src/studio/hooks/useThreadMessages.ts +85 -0
- package/src/studio/lib/chat.ts +34 -0
- package/src/studio/ui/ChatPanel.tsx +154 -0
- package/src/studio/ui/ConfirmMergeFlow.tsx +55 -0
- package/src/studio/ui/PreviewPanel.tsx +131 -0
- package/src/studio/ui/RuntimeRenderer.tsx +40 -0
- package/src/studio/ui/StudioOverlay.tsx +257 -0
- package/src/studio/ui/preview-panel/PressableCardRow.tsx +49 -0
- package/src/studio/ui/preview-panel/PreviewCollaborateSection.tsx +174 -0
- package/src/studio/ui/preview-panel/PreviewCustomizeSection.tsx +160 -0
- package/src/studio/ui/preview-panel/PreviewHeroSection.tsx +56 -0
- package/src/studio/ui/preview-panel/PreviewMetaSection.tsx +67 -0
- package/src/studio/ui/preview-panel/PreviewPanelHeader.tsx +48 -0
- package/src/studio/ui/preview-panel/SectionTitle.tsx +31 -0
- package/src/studio/ui/preview-panel/usePreviewPanelData.ts +132 -0
- package/src/studio/ui/preview-panel/utils.ts +29 -0
- package/src/theme/index.ts +5 -0
- package/src/theme/tokens.ts +118 -0
- package/src/theme/types.ts +90 -0
- package/src/theme/useTheme.ts +11 -0
- package/dist/assets/images/merge.svg +0 -3
- package/dist/merge-72UG27QV.svg +0 -3
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { App } from '../../../data/apps/types';
|
|
5
|
+
import { PreviewMetaRow } from '../../../components/preview/PreviewMetaRow';
|
|
6
|
+
import { Text } from '../../../components/primitives/Text';
|
|
7
|
+
import { IconPlay } from '../../../components/icons/StudioIcons';
|
|
8
|
+
import { withAlpha } from '../../../components/utils/color';
|
|
9
|
+
import { useTheme } from '../../../theme';
|
|
10
|
+
import { formatCount } from './utils';
|
|
11
|
+
|
|
12
|
+
export type PreviewMetaSectionProps = {
|
|
13
|
+
app: App;
|
|
14
|
+
isOwner: boolean;
|
|
15
|
+
creator: { name: string | null; avatar: string | null } | null;
|
|
16
|
+
downloadsCount?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function PreviewMetaSection({ app, isOwner, creator, downloadsCount }: PreviewMetaSectionProps) {
|
|
20
|
+
const theme = useTheme();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<PreviewMetaRow
|
|
24
|
+
title={app.name}
|
|
25
|
+
subtitle={app.description}
|
|
26
|
+
avatarUri={creator?.avatar ?? null}
|
|
27
|
+
creatorName={creator?.name ?? null}
|
|
28
|
+
tag={
|
|
29
|
+
isOwner || app.forkedFromAppId ? (
|
|
30
|
+
<View style={{ paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999, backgroundColor: '#3700B3' }}>
|
|
31
|
+
<Text variant="caption" style={{ color: '#fff', fontWeight: theme.typography.fontWeight.semibold }}>
|
|
32
|
+
{app.forkedFromAppId ? 'Remix' : 'Owner'}
|
|
33
|
+
</Text>
|
|
34
|
+
</View>
|
|
35
|
+
) : null
|
|
36
|
+
}
|
|
37
|
+
rightMetric={
|
|
38
|
+
<View
|
|
39
|
+
style={{
|
|
40
|
+
flexDirection: 'row',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
paddingHorizontal: 6,
|
|
43
|
+
paddingVertical: 2,
|
|
44
|
+
borderRadius: 6,
|
|
45
|
+
backgroundColor: withAlpha(theme.colors.neutral, 0.3),
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<Text
|
|
49
|
+
style={{
|
|
50
|
+
marginRight: 2,
|
|
51
|
+
color: theme.colors.textMuted,
|
|
52
|
+
fontSize: 14,
|
|
53
|
+
lineHeight: 18,
|
|
54
|
+
fontWeight: theme.typography.fontWeight.bold,
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
{formatCount(downloadsCount ?? app.insights?.totalDownloads ?? 0)}
|
|
58
|
+
</Text>
|
|
59
|
+
<IconPlay size={14} colorToken="textMuted" fill={theme.colors.textMuted} />
|
|
60
|
+
</View>
|
|
61
|
+
}
|
|
62
|
+
style={{ marginBottom: 16 }}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { StudioSheetHeader } from '../../../components/studio-sheet/StudioSheetHeader';
|
|
5
|
+
import { StudioSheetHeaderIconButton } from '../../../components/studio-sheet/StudioSheetHeaderIconButton';
|
|
6
|
+
import { IconChat, IconClose, IconHome } from '../../../components/icons/StudioIcons';
|
|
7
|
+
|
|
8
|
+
export type PreviewPanelHeaderProps = {
|
|
9
|
+
isOwner: boolean;
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
onNavigateHome?: () => void;
|
|
12
|
+
onGoToChat: () => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function PreviewPanelHeader({ isOwner, onClose, onNavigateHome, onGoToChat }: PreviewPanelHeaderProps) {
|
|
16
|
+
return (
|
|
17
|
+
<StudioSheetHeader
|
|
18
|
+
left={
|
|
19
|
+
onNavigateHome ? (
|
|
20
|
+
<StudioSheetHeaderIconButton onPress={onNavigateHome} accessibilityLabel="Home" appearance="glass" intent="primary">
|
|
21
|
+
<IconHome size={20} colorToken="onPrimary" />
|
|
22
|
+
</StudioSheetHeaderIconButton>
|
|
23
|
+
) : null
|
|
24
|
+
}
|
|
25
|
+
center={null}
|
|
26
|
+
right={
|
|
27
|
+
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
28
|
+
{isOwner ? (
|
|
29
|
+
<StudioSheetHeaderIconButton
|
|
30
|
+
onPress={onGoToChat}
|
|
31
|
+
accessibilityLabel="Chat"
|
|
32
|
+
intent="primary"
|
|
33
|
+
appearance="glass"
|
|
34
|
+
style={{ marginRight: 8 }}
|
|
35
|
+
>
|
|
36
|
+
<IconChat size={20} colorToken="onPrimary" />
|
|
37
|
+
</StudioSheetHeaderIconButton>
|
|
38
|
+
) : null}
|
|
39
|
+
<StudioSheetHeaderIconButton onPress={onClose} accessibilityLabel="Close" appearance="glass" intent="primary">
|
|
40
|
+
<IconClose size={20} colorToken="onPrimary" />
|
|
41
|
+
</StudioSheetHeaderIconButton>
|
|
42
|
+
</View>
|
|
43
|
+
}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Text } from '../../../components/primitives/Text';
|
|
4
|
+
import { useTheme } from '../../../theme';
|
|
5
|
+
|
|
6
|
+
export type SectionTitleProps = {
|
|
7
|
+
children: string;
|
|
8
|
+
marginTop?: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function SectionTitle({ children, marginTop }: SectionTitleProps) {
|
|
12
|
+
const theme = useTheme();
|
|
13
|
+
return (
|
|
14
|
+
<Text
|
|
15
|
+
style={{
|
|
16
|
+
color: theme.colors.textMuted,
|
|
17
|
+
fontSize: 12,
|
|
18
|
+
lineHeight: 16,
|
|
19
|
+
textTransform: 'uppercase',
|
|
20
|
+
letterSpacing: 0.8,
|
|
21
|
+
marginTop: marginTop ?? theme.spacing.sm,
|
|
22
|
+
marginBottom: theme.spacing.sm,
|
|
23
|
+
fontWeight: theme.typography.fontWeight.bold,
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</Text>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { App } from '../../../data/apps/types';
|
|
4
|
+
import type { MergeRequest } from '../../../data/merge-requests/types';
|
|
5
|
+
import { appImagesRepository } from '../../../data/apps/images/repository';
|
|
6
|
+
import { appsRepository } from '../../../data/apps/repository';
|
|
7
|
+
import { usersRepository } from '../../../data/users/repository';
|
|
8
|
+
import { log } from '../../../core/logger';
|
|
9
|
+
import { useAppStats } from '../../hooks/useAppStats';
|
|
10
|
+
|
|
11
|
+
type InsightsSummary = { likes: number; comments: number; forks: number; downloads: number };
|
|
12
|
+
|
|
13
|
+
const LIKE_DEBUG_PREFIX = '[COMERGE_LIKE_DEBUG]';
|
|
14
|
+
|
|
15
|
+
export function usePreviewPanelData(params: {
|
|
16
|
+
app: App | null;
|
|
17
|
+
isOwner: boolean;
|
|
18
|
+
outgoingMergeRequests: MergeRequest[];
|
|
19
|
+
onOpenComments?: () => void;
|
|
20
|
+
commentCountOverride?: number;
|
|
21
|
+
}) {
|
|
22
|
+
const { app, isOwner, outgoingMergeRequests, onOpenComments, commentCountOverride } = params;
|
|
23
|
+
|
|
24
|
+
const [imageUrl, setImageUrl] = React.useState<string | null>(null);
|
|
25
|
+
const [imageLoaded, setImageLoaded] = React.useState(false);
|
|
26
|
+
const [insights, setInsights] = React.useState<InsightsSummary>({ likes: 0, comments: 0, forks: 0, downloads: 0 });
|
|
27
|
+
const [creator, setCreator] = React.useState<{ name: string | null; avatar: string | null } | null>(null);
|
|
28
|
+
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (!app?.id) return;
|
|
31
|
+
let cancelled = false;
|
|
32
|
+
(async () => {
|
|
33
|
+
try {
|
|
34
|
+
const res = await appImagesRepository.getSignedUrl(app.id);
|
|
35
|
+
if (!cancelled) setImageUrl(res.url);
|
|
36
|
+
} catch {
|
|
37
|
+
if (!cancelled) setImageUrl(null);
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
return () => {
|
|
41
|
+
cancelled = true;
|
|
42
|
+
};
|
|
43
|
+
}, [app?.id]);
|
|
44
|
+
|
|
45
|
+
React.useEffect(() => {
|
|
46
|
+
if (!app?.createdBy) return;
|
|
47
|
+
let cancelled = false;
|
|
48
|
+
(async () => {
|
|
49
|
+
try {
|
|
50
|
+
const stats = await usersRepository.getStats(app.createdBy);
|
|
51
|
+
if (cancelled) return;
|
|
52
|
+
setCreator({ name: stats.name, avatar: stats.avatar });
|
|
53
|
+
} catch {
|
|
54
|
+
if (!cancelled) setCreator(null);
|
|
55
|
+
}
|
|
56
|
+
})();
|
|
57
|
+
return () => {
|
|
58
|
+
cancelled = true;
|
|
59
|
+
};
|
|
60
|
+
}, [app?.createdBy]);
|
|
61
|
+
|
|
62
|
+
React.useEffect(() => {
|
|
63
|
+
setImageLoaded(false);
|
|
64
|
+
}, [app?.id]);
|
|
65
|
+
|
|
66
|
+
React.useEffect(() => {
|
|
67
|
+
if (!app?.id) return;
|
|
68
|
+
let cancelled = false;
|
|
69
|
+
(async () => {
|
|
70
|
+
try {
|
|
71
|
+
const full = await appsRepository.getInsights(app.id);
|
|
72
|
+
if (cancelled) return;
|
|
73
|
+
log.debug(
|
|
74
|
+
`${LIKE_DEBUG_PREFIX} usePreviewPanelData.getInsights appId=${app.id} insights.likes.total=${full.likes.total} app.isLiked=${String(
|
|
75
|
+
app.isLiked
|
|
76
|
+
)}`
|
|
77
|
+
);
|
|
78
|
+
setInsights({
|
|
79
|
+
likes: full.likes.total,
|
|
80
|
+
comments: full.comments.total,
|
|
81
|
+
forks: full.forks.total,
|
|
82
|
+
downloads: full.downloads.total,
|
|
83
|
+
});
|
|
84
|
+
} catch {
|
|
85
|
+
// Leave zeros
|
|
86
|
+
}
|
|
87
|
+
})();
|
|
88
|
+
return () => {
|
|
89
|
+
cancelled = true;
|
|
90
|
+
};
|
|
91
|
+
}, [app?.id]);
|
|
92
|
+
|
|
93
|
+
React.useEffect(() => {
|
|
94
|
+
if (!app?.id) return;
|
|
95
|
+
log.debug(
|
|
96
|
+
`${LIKE_DEBUG_PREFIX} usePreviewPanelData.appChanged appId=${app.id} app.isLiked=${String(app.isLiked)}`
|
|
97
|
+
);
|
|
98
|
+
}, [app?.id, app?.isLiked]);
|
|
99
|
+
|
|
100
|
+
const stats = useAppStats({
|
|
101
|
+
appId: app?.id ?? '',
|
|
102
|
+
initialLikes: insights.likes,
|
|
103
|
+
initialForks: insights.forks,
|
|
104
|
+
initialComments: commentCountOverride ?? insights.comments,
|
|
105
|
+
initialIsLiked: Boolean(app?.isLiked),
|
|
106
|
+
onOpenComments,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const canSubmitMergeRequest = React.useMemo(() => {
|
|
110
|
+
if (!isOwner) return false;
|
|
111
|
+
if (!app) return false;
|
|
112
|
+
if (!app.forkedFromAppId) return false;
|
|
113
|
+
if (outgoingMergeRequests.some((mr) => mr.status === 'open')) return false;
|
|
114
|
+
if (app.headCommitId && app.forkedFromCommitId && app.headCommitId !== app.forkedFromCommitId) return true;
|
|
115
|
+
return false;
|
|
116
|
+
}, [app, isOwner, outgoingMergeRequests]);
|
|
117
|
+
|
|
118
|
+
const showProcessing = app ? app.status !== 'ready' : false;
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
imageUrl,
|
|
122
|
+
imageLoaded,
|
|
123
|
+
setImageLoaded,
|
|
124
|
+
creator,
|
|
125
|
+
insights,
|
|
126
|
+
stats,
|
|
127
|
+
showProcessing,
|
|
128
|
+
canSubmitMergeRequest,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { App } from '../../../data/apps/types';
|
|
2
|
+
|
|
3
|
+
export function formatCount(n: number): string {
|
|
4
|
+
if (n < 10_000) return n.toLocaleString();
|
|
5
|
+
if (n < 1_000_000) return `${Math.floor(n / 1_000)}k`;
|
|
6
|
+
return `${Math.floor(n / 1_000_000)}m`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function statusDescription(status: App['status'], statusError: string | null): string {
|
|
10
|
+
switch (status) {
|
|
11
|
+
case 'editing':
|
|
12
|
+
return 'Changes are being applied';
|
|
13
|
+
case 'creating':
|
|
14
|
+
return 'Your app is being created';
|
|
15
|
+
case 'forking':
|
|
16
|
+
return 'Creating your copy';
|
|
17
|
+
case 'merging':
|
|
18
|
+
return 'Merging changes from contributor';
|
|
19
|
+
case 'archived':
|
|
20
|
+
return 'This app has been archived';
|
|
21
|
+
case 'error':
|
|
22
|
+
return statusError ?? 'Something went wrong';
|
|
23
|
+
case 'ready':
|
|
24
|
+
default:
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { Theme } from './types';
|
|
2
|
+
|
|
3
|
+
export const lightTheme = {
|
|
4
|
+
scheme: 'light',
|
|
5
|
+
colors: {
|
|
6
|
+
text: '#09090B',
|
|
7
|
+
textMuted: '#898994',
|
|
8
|
+
textSubtle: 'rgba(137, 137, 148, 0.70)',
|
|
9
|
+
|
|
10
|
+
background: '#FFFFFF',
|
|
11
|
+
surface: '#F6F6F6',
|
|
12
|
+
surfaceRaised: '#FFFFFF',
|
|
13
|
+
|
|
14
|
+
border: '#E4E4E7',
|
|
15
|
+
borderStrong: '#D4D4D8',
|
|
16
|
+
|
|
17
|
+
primary: '#6200EE',
|
|
18
|
+
onPrimary: '#FFFFFF',
|
|
19
|
+
|
|
20
|
+
neutral: '#ECECEE',
|
|
21
|
+
onNeutral: '#09090B',
|
|
22
|
+
|
|
23
|
+
danger: '#F43F5E',
|
|
24
|
+
onDanger: '#FFFFFF',
|
|
25
|
+
dangerSubtle: 'rgba(244, 63, 94, 0.12)',
|
|
26
|
+
|
|
27
|
+
success: '#10B981',
|
|
28
|
+
onSuccess: '#FFFFFF',
|
|
29
|
+
successSubtle: 'rgba(16, 185, 129, 0.12)',
|
|
30
|
+
|
|
31
|
+
warning: '#FACC15',
|
|
32
|
+
onWarning: '#09090B',
|
|
33
|
+
warningSubtle: 'rgba(250, 204, 21, 0.14)',
|
|
34
|
+
|
|
35
|
+
link: '#6200EE',
|
|
36
|
+
|
|
37
|
+
backdrop: 'rgba(0, 0, 0, 0.35)',
|
|
38
|
+
|
|
39
|
+
handleIndicator: '#71717A',
|
|
40
|
+
|
|
41
|
+
floatingSurface: 'rgba(255, 255, 255, 0.6)',
|
|
42
|
+
floatingContent: '#000000',
|
|
43
|
+
|
|
44
|
+
accentRingFrom: 'rgba(98, 0, 238, 0.20)',
|
|
45
|
+
accentRingTo: 'rgba(98, 0, 238, 0.90)',
|
|
46
|
+
dangerRingFrom: 'rgba(244, 63, 94, 0.35)',
|
|
47
|
+
dangerRingTo: 'rgba(244, 63, 94, 1.0)',
|
|
48
|
+
},
|
|
49
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 24 },
|
|
50
|
+
radii: { sm: 8, md: 12, lg: 16, xl: 24, pill: 999 },
|
|
51
|
+
typography: {
|
|
52
|
+
fontSize: { xs: 12, sm: 13, md: 15, lg: 17, xl: 20 },
|
|
53
|
+
lineHeight: { xs: 16, sm: 18, md: 20, lg: 22, xl: 26 },
|
|
54
|
+
fontWeight: { regular: '400', medium: '500', semibold: '600', bold: '700' },
|
|
55
|
+
},
|
|
56
|
+
} as const satisfies Theme;
|
|
57
|
+
|
|
58
|
+
export const darkTheme = {
|
|
59
|
+
scheme: 'dark',
|
|
60
|
+
colors: {
|
|
61
|
+
text: '#FFFFFF',
|
|
62
|
+
textMuted: '#A1A1AA',
|
|
63
|
+
textSubtle: 'rgba(161, 161, 170, 0.70)',
|
|
64
|
+
|
|
65
|
+
background: '#0B080F',
|
|
66
|
+
surface: '#18181B',
|
|
67
|
+
surfaceRaised: '#0B080F',
|
|
68
|
+
|
|
69
|
+
border: '#404049',
|
|
70
|
+
borderStrong: '#52525B',
|
|
71
|
+
|
|
72
|
+
primary: '#6200EE',
|
|
73
|
+
onPrimary: '#FFFFFF',
|
|
74
|
+
|
|
75
|
+
neutral: '#0B080F',
|
|
76
|
+
onNeutral: '#FFFFFF',
|
|
77
|
+
|
|
78
|
+
danger: '#F43F5E',
|
|
79
|
+
onDanger: '#FFFFFF',
|
|
80
|
+
dangerSubtle: 'rgba(244, 63, 94, 0.18)',
|
|
81
|
+
|
|
82
|
+
success: '#10B981',
|
|
83
|
+
onSuccess: '#0B080F',
|
|
84
|
+
successSubtle: 'rgba(16, 185, 129, 0.16)',
|
|
85
|
+
|
|
86
|
+
warning: '#FBBF24',
|
|
87
|
+
onWarning: '#0B080F',
|
|
88
|
+
warningSubtle: 'rgba(251, 191, 36, 0.18)',
|
|
89
|
+
|
|
90
|
+
link: '#6200EE',
|
|
91
|
+
|
|
92
|
+
backdrop: 'rgba(0, 0, 0, 0.55)',
|
|
93
|
+
|
|
94
|
+
handleIndicator: '#A1A1AA',
|
|
95
|
+
|
|
96
|
+
floatingSurface: 'rgba(0, 0, 0, 0.6)',
|
|
97
|
+
floatingContent: '#FFFFFF',
|
|
98
|
+
|
|
99
|
+
accentRingFrom: 'rgba(98, 0, 238, 0.20)',
|
|
100
|
+
accentRingTo: 'rgba(98, 0, 238, 0.90)',
|
|
101
|
+
dangerRingFrom: 'rgba(244, 63, 94, 0.35)',
|
|
102
|
+
dangerRingTo: 'rgba(244, 63, 94, 1.0)',
|
|
103
|
+
},
|
|
104
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 24 },
|
|
105
|
+
radii: { sm: 8, md: 12, lg: 16, xl: 24, pill: 999 },
|
|
106
|
+
typography: {
|
|
107
|
+
fontSize: { xs: 12, sm: 13, md: 15, lg: 17, xl: 20 },
|
|
108
|
+
lineHeight: { xs: 16, sm: 18, md: 20, lg: 22, xl: 26 },
|
|
109
|
+
fontWeight: { regular: '400', medium: '500', semibold: '600', bold: '700' },
|
|
110
|
+
},
|
|
111
|
+
} as const satisfies Theme;
|
|
112
|
+
|
|
113
|
+
export const themes = {
|
|
114
|
+
light: lightTheme,
|
|
115
|
+
dark: darkTheme,
|
|
116
|
+
} as const;
|
|
117
|
+
|
|
118
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export type ThemeScheme = 'light' | 'dark';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export type ThemeColors = {
|
|
5
|
+
text: string;
|
|
6
|
+
textMuted: string;
|
|
7
|
+
textSubtle: string;
|
|
8
|
+
|
|
9
|
+
background: string;
|
|
10
|
+
surface: string;
|
|
11
|
+
surfaceRaised: string;
|
|
12
|
+
|
|
13
|
+
border: string;
|
|
14
|
+
borderStrong: string;
|
|
15
|
+
|
|
16
|
+
primary: string;
|
|
17
|
+
onPrimary: string;
|
|
18
|
+
|
|
19
|
+
neutral: string;
|
|
20
|
+
onNeutral: string;
|
|
21
|
+
|
|
22
|
+
danger: string;
|
|
23
|
+
onDanger: string;
|
|
24
|
+
dangerSubtle: string;
|
|
25
|
+
|
|
26
|
+
success: string;
|
|
27
|
+
onSuccess: string;
|
|
28
|
+
successSubtle: string;
|
|
29
|
+
|
|
30
|
+
warning: string;
|
|
31
|
+
onWarning: string;
|
|
32
|
+
warningSubtle: string;
|
|
33
|
+
|
|
34
|
+
link: string;
|
|
35
|
+
|
|
36
|
+
backdrop: string;
|
|
37
|
+
|
|
38
|
+
handleIndicator: string;
|
|
39
|
+
|
|
40
|
+
floatingSurface: string;
|
|
41
|
+
floatingContent: string;
|
|
42
|
+
|
|
43
|
+
accentRingFrom: string;
|
|
44
|
+
accentRingTo: string;
|
|
45
|
+
dangerRingFrom: string;
|
|
46
|
+
dangerRingTo: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type Theme = {
|
|
50
|
+
scheme: ThemeScheme;
|
|
51
|
+
colors: ThemeColors;
|
|
52
|
+
spacing: {
|
|
53
|
+
xs: number;
|
|
54
|
+
sm: number;
|
|
55
|
+
md: number;
|
|
56
|
+
lg: number;
|
|
57
|
+
xl: number;
|
|
58
|
+
};
|
|
59
|
+
radii: {
|
|
60
|
+
sm: number;
|
|
61
|
+
md: number;
|
|
62
|
+
lg: number;
|
|
63
|
+
xl: number;
|
|
64
|
+
pill: number;
|
|
65
|
+
};
|
|
66
|
+
typography: {
|
|
67
|
+
fontSize: {
|
|
68
|
+
xs: number;
|
|
69
|
+
sm: number;
|
|
70
|
+
md: number;
|
|
71
|
+
lg: number;
|
|
72
|
+
xl: number;
|
|
73
|
+
};
|
|
74
|
+
lineHeight: {
|
|
75
|
+
xs: number;
|
|
76
|
+
sm: number;
|
|
77
|
+
md: number;
|
|
78
|
+
lg: number;
|
|
79
|
+
xl: number;
|
|
80
|
+
};
|
|
81
|
+
fontWeight: {
|
|
82
|
+
regular: '400' | '500';
|
|
83
|
+
medium: '500' | '600';
|
|
84
|
+
semibold: '600' | '700';
|
|
85
|
+
bold: '700';
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useColorScheme } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { themes } from './tokens';
|
|
4
|
+
import type { Theme, ThemeScheme } from './types';
|
|
5
|
+
|
|
6
|
+
export function useTheme(): Theme {
|
|
7
|
+
const scheme = (useColorScheme() ?? 'light') as ThemeScheme;
|
|
8
|
+
return themes[scheme] ?? themes.light;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
<svg width="486" height="486" viewBox="0 0 486 486" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<path d="M237.025 0H243.664C254.876 95.0361 275.236 175.597 304.743 241.684C334.249 307.478 367.002 357.774 403 392.572L389.722 486C361.691 458.22 338.233 429.417 319.349 399.59C300.464 369.764 284.531 335.843 271.548 297.829C258.565 259.522 246.615 214.343 235.697 162.292L237.91 161.415C228.468 214.928 217.993 261.569 206.485 301.338C194.978 341.107 179.634 375.904 160.455 405.731C141.571 435.265 115.752 462.022 83 486L96.278 392.572C124.014 369.179 147.62 336.72 167.094 295.197C186.864 253.381 202.65 206.886 214.452 155.713C226.255 104.247 233.779 52.343 237.025 0Z" fill="currentColor"/>
|
|
3
|
-
</svg>
|
package/dist/merge-72UG27QV.svg
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
<svg width="486" height="486" viewBox="0 0 486 486" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<path d="M237.025 0H243.664C254.876 95.0361 275.236 175.597 304.743 241.684C334.249 307.478 367.002 357.774 403 392.572L389.722 486C361.691 458.22 338.233 429.417 319.349 399.59C300.464 369.764 284.531 335.843 271.548 297.829C258.565 259.522 246.615 214.343 235.697 162.292L237.91 161.415C228.468 214.928 217.993 261.569 206.485 301.338C194.978 341.107 179.634 375.904 160.455 405.731C141.571 435.265 115.752 462.022 83 486L96.278 392.572C124.014 369.179 147.62 336.72 167.094 295.197C186.864 253.381 202.65 206.886 214.452 155.713C226.255 104.247 233.779 52.343 237.025 0Z" fill="currentColor"/>
|
|
3
|
-
</svg>
|