@comergehq/studio 0.1.24 → 0.1.26

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comergehq/studio",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Comerge studio",
5
5
  "main": "src/index.ts",
6
6
  "module": "dist/index.mjs",
@@ -41,7 +41,7 @@ export function ChatMessageBubble({ message, renderContent, isLast, retrying, on
41
41
 
42
42
  const bodyColor =
43
43
  metaStatus === 'success' ? theme.colors.success : metaStatus === 'error' ? theme.colors.danger : undefined;
44
- const showRetry = Boolean(onRetry) && isLast && metaStatus === 'error';
44
+ const showRetry = Boolean(onRetry) && isLast && metaStatus === 'error' && message.author === 'human';
45
45
  const retryLabel = retrying ? 'Retrying...' : 'Retry';
46
46
 
47
47
  return (
@@ -49,7 +49,7 @@ export function ChatPage({
49
49
  const insets = useSafeAreaInsets();
50
50
  const [composerHeight, setComposerHeight] = React.useState(0);
51
51
  const [composerTopHeight, setComposerTopHeight] = React.useState(0);
52
- const footerBottomPadding = Platform.OS === 'ios' ? insets.bottom : insets.bottom + 10;
52
+ const footerBottomPadding = Platform.OS === 'ios' ? insets.bottom - 24 : insets.bottom + 10;
53
53
  const totalComposerHeight = composerHeight + composerTopHeight;
54
54
  const overlayBottom = totalComposerHeight + footerBottomPadding + theme.spacing.lg;
55
55
  const bottomInset = totalComposerHeight + footerBottomPadding + theme.spacing.xl;
@@ -64,7 +64,7 @@ export function ReviewMergeRequestCard({
64
64
  padding: 16,
65
65
  backgroundColor: withAlpha(theme.colors.surfaceRaised, 0.5),
66
66
  borderWidth: 1,
67
- borderColor: withAlpha('#3700B3', 0.2),
67
+ borderColor: withAlpha('#007A75', 0.2),
68
68
  } as any,
69
69
  ]}
70
70
  >
@@ -32,7 +32,7 @@ function baseColor(role: NonNullable<EdgeGlowFrameProps['role']>, theme: ReturnT
32
32
  return theme.colors.warning;
33
33
  case 'accent':
34
34
  default:
35
- return '#A855F7';
35
+ return theme.colors.primary;
36
36
  }
37
37
  }
38
38
 
@@ -19,7 +19,7 @@ const STATUS_BG: Record<AppStatus, string> = {
19
19
  ready: '#10B981', // emerald-500
20
20
  creating: '#3B82F6', // blue-500
21
21
  editing: '#F59E0B', // amber-500
22
- forking: '#8B5CF6', // violet-500
22
+ forking: '#00CBC0', // brand teal
23
23
  merging: '#06B6D4', // cyan-500
24
24
  error: '#F43F5E', // rose-500
25
25
  archived: '#71717A', // zinc-500
@@ -1,8 +1,9 @@
1
- import { Platform, Pressable, Text, View, type ViewStyle } from 'react-native';
1
+ import { Dimensions, Keyboard, Modal, Platform, Pressable, Text, View, type ViewStyle } from 'react-native';
2
2
 
3
3
  import Markdown from 'react-native-markdown-display';
4
4
 
5
5
  import { useTheme } from '../../theme';
6
+ import { impact } from '../draw/optionalHaptics';
6
7
  import { useEffect, useRef, useState } from 'react';
7
8
 
8
9
  export type MarkdownTextVariant = 'chat' | 'mergeRequest';
@@ -54,14 +55,13 @@ export function MarkdownText({ markdown, variant = 'chat', bodyColor, style }: M
54
55
  const theme = useTheme();
55
56
  const isDark = theme.scheme === 'dark';
56
57
  const [showCopied, setShowCopied] = useState(false);
57
- const [tooltipPosition, setTooltipPosition] = useState<{ x: number; y: number } | null>(null);
58
+ const [tooltipAnchor, setTooltipAnchor] = useState<{ x: number; y: number } | null>(null);
58
59
  const [tooltipWidth, setTooltipWidth] = useState(0);
59
60
  const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
60
- const containerRef = useRef<View>(null);
61
61
 
62
62
  const baseBodyColor = variant === 'mergeRequest' ? theme.colors.textMuted : theme.colors.text;
63
63
  const linkColor =
64
- variant === 'mergeRequest' ? (isDark ? theme.colors.primary : '#3700B3') : theme.colors.link;
64
+ variant === 'mergeRequest' ? (isDark ? theme.colors.primary : '#007A75') : theme.colors.link;
65
65
  const linkWeight = variant === 'mergeRequest' ? theme.typography.fontWeight.semibold : undefined;
66
66
 
67
67
  const codeBgColor = isDark ? '#27272A' : '#E4E4E7';
@@ -69,6 +69,18 @@ export function MarkdownText({ markdown, variant = 'chat', bodyColor, style }: M
69
69
 
70
70
  const paragraphBottom = variant === 'mergeRequest' ? 8 : 6;
71
71
  const baseLineHeight = variant === 'mergeRequest' ? 22 : 20;
72
+ const screen = Dimensions.get('window');
73
+ const tooltipPadding = theme.spacing.sm;
74
+ const tooltipYOffset = theme.spacing.lg + 32;
75
+ const minTooltipY = theme.spacing.xl;
76
+
77
+ const tooltipTop = tooltipAnchor ? Math.max(minTooltipY, tooltipAnchor.y - tooltipYOffset) : 0;
78
+ const tooltipLeft = tooltipAnchor
79
+ ? Math.min(
80
+ Math.max(tooltipAnchor.x, tooltipPadding),
81
+ Math.max(tooltipPadding, screen.width - tooltipPadding - Math.max(tooltipWidth, 1))
82
+ )
83
+ : 0;
72
84
 
73
85
  useEffect(() => {
74
86
  return () => {
@@ -81,16 +93,11 @@ export function MarkdownText({ markdown, variant = 'chat', bodyColor, style }: M
81
93
  const handleLongPress = (event: {
82
94
  nativeEvent: { locationX: number; locationY: number; pageX: number; pageY: number };
83
95
  }) => {
84
- const { locationX, locationY, pageX, pageY } = event.nativeEvent;
85
-
86
- if (containerRef.current?.measureInWindow) {
87
- containerRef.current.measureInWindow((x, y) => {
88
- setTooltipPosition({ x: pageX - x, y: pageY - y });
89
- });
90
- } else {
91
- setTooltipPosition({ x: locationX, y: locationY });
92
- }
96
+ const { pageX, pageY } = event.nativeEvent;
97
+ setTooltipAnchor({ x: pageX, y: pageY });
98
+ setTooltipWidth(0);
93
99
  copyMarkdownToClipboard(markdown);
100
+ void impact('light');
94
101
  setShowCopied(true);
95
102
 
96
103
  if (hideTimerRef.current) {
@@ -103,8 +110,8 @@ export function MarkdownText({ markdown, variant = 'chat', bodyColor, style }: M
103
110
  };
104
111
 
105
112
  return (
106
- <Pressable style={style} onLongPress={handleLongPress}>
107
- <View ref={containerRef} style={{ position: 'relative' }}>
113
+ <Pressable style={style} onPress={Keyboard.dismiss} onLongPress={handleLongPress}>
114
+ <View style={{ position: 'relative' }}>
108
115
  <Markdown
109
116
  style={{
110
117
  body: { color: bodyColor ?? baseBodyColor, fontSize: 14, lineHeight: baseLineHeight },
@@ -137,31 +144,34 @@ export function MarkdownText({ markdown, variant = 'chat', bodyColor, style }: M
137
144
  >
138
145
  {markdown}
139
146
  </Markdown>
140
- {showCopied && tooltipPosition ? (
141
- <View
142
- pointerEvents="none"
143
- style={{
144
- position: 'absolute',
145
- left: tooltipPosition.x,
146
- top: tooltipPosition.y - theme.spacing.lg - 32,
147
- backgroundColor: theme.colors.success,
148
- borderRadius: theme.radii.pill,
149
- paddingHorizontal: theme.spacing.sm,
150
- paddingVertical: theme.spacing.xs,
151
- transform: [{ translateX: tooltipWidth ? -tooltipWidth / 2 : 0 }],
152
- }}
153
- onLayout={(event) => setTooltipWidth(event.nativeEvent.layout.width)}
154
- >
155
- <Text
156
- style={{
157
- color: theme.colors.onSuccess,
158
- fontSize: theme.typography.fontSize.xs,
159
- fontWeight: theme.typography.fontWeight.medium,
160
- }}
161
- >
162
- Copied
163
- </Text>
164
- </View>
147
+ {showCopied && tooltipAnchor ? (
148
+ <Modal transparent visible statusBarTranslucent>
149
+ <View pointerEvents="none" style={{ flex: 1 }}>
150
+ <View
151
+ pointerEvents="none"
152
+ style={{
153
+ position: 'absolute',
154
+ left: tooltipLeft,
155
+ top: tooltipTop,
156
+ backgroundColor: theme.colors.success,
157
+ borderRadius: theme.radii.pill,
158
+ paddingHorizontal: theme.spacing.sm,
159
+ paddingVertical: theme.spacing.xs,
160
+ }}
161
+ onLayout={(event) => setTooltipWidth(event.nativeEvent.layout.width)}
162
+ >
163
+ <Text
164
+ style={{
165
+ color: theme.colors.onSuccess,
166
+ fontSize: theme.typography.fontSize.xs,
167
+ fontWeight: theme.typography.fontWeight.medium,
168
+ }}
169
+ >
170
+ Copied
171
+ </Text>
172
+ </View>
173
+ </View>
174
+ </Modal>
165
175
  ) : null}
166
176
  </View>
167
177
  </Pressable>
@@ -27,7 +27,7 @@ export function PreviewMetaSection({ app, isOwner, creator, downloadsCount }: Pr
27
27
  creatorName={creator?.name ?? null}
28
28
  tag={
29
29
  isOwner || app.forkedFromAppId ? (
30
- <View style={{ paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999, backgroundColor: '#3700B3' }}>
30
+ <View style={{ paddingHorizontal: 8, paddingVertical: 2, borderRadius: 999, backgroundColor: '#007A75' }}>
31
31
  <Text variant="caption" style={{ color: '#fff', fontWeight: theme.typography.fontWeight.semibold }}>
32
32
  {app.forkedFromAppId ? 'Remix' : 'Owner'}
33
33
  </Text>
@@ -14,7 +14,7 @@ export const lightTheme = {
14
14
  border: '#E4E4E7',
15
15
  borderStrong: '#D4D4D8',
16
16
 
17
- primary: '#6200EE',
17
+ primary: '#00CBC0',
18
18
  onPrimary: '#FFFFFF',
19
19
 
20
20
  neutral: '#ECECEE',
@@ -32,7 +32,7 @@ export const lightTheme = {
32
32
  onWarning: '#09090B',
33
33
  warningSubtle: 'rgba(250, 204, 21, 0.14)',
34
34
 
35
- link: '#6200EE',
35
+ link: '#00CBC0',
36
36
 
37
37
  backdrop: 'rgba(0, 0, 0, 0.35)',
38
38
 
@@ -41,8 +41,8 @@ export const lightTheme = {
41
41
  floatingSurface: 'rgba(255, 255, 255, 0.6)',
42
42
  floatingContent: '#000000',
43
43
 
44
- accentRingFrom: 'rgba(98, 0, 238, 0.20)',
45
- accentRingTo: 'rgba(98, 0, 238, 0.90)',
44
+ accentRingFrom: 'rgba(0, 203, 192, 0.20)',
45
+ accentRingTo: 'rgba(0, 203, 192, 0.90)',
46
46
  dangerRingFrom: 'rgba(244, 63, 94, 0.35)',
47
47
  dangerRingTo: 'rgba(244, 63, 94, 1.0)',
48
48
  },
@@ -69,7 +69,7 @@ export const darkTheme = {
69
69
  border: '#404049',
70
70
  borderStrong: '#52525B',
71
71
 
72
- primary: '#6200EE',
72
+ primary: '#00CBC0',
73
73
  onPrimary: '#FFFFFF',
74
74
 
75
75
  neutral: '#0B080F',
@@ -87,7 +87,7 @@ export const darkTheme = {
87
87
  onWarning: '#0B080F',
88
88
  warningSubtle: 'rgba(251, 191, 36, 0.18)',
89
89
 
90
- link: '#6200EE',
90
+ link: '#00CBC0',
91
91
 
92
92
  backdrop: 'rgba(0, 0, 0, 0.55)',
93
93
 
@@ -96,8 +96,8 @@ export const darkTheme = {
96
96
  floatingSurface: 'rgba(0, 0, 0, 0.6)',
97
97
  floatingContent: '#FFFFFF',
98
98
 
99
- accentRingFrom: 'rgba(98, 0, 238, 0.20)',
100
- accentRingTo: 'rgba(98, 0, 238, 0.90)',
99
+ accentRingFrom: 'rgba(0, 203, 192, 0.20)',
100
+ accentRingTo: 'rgba(0, 203, 192, 0.90)',
101
101
  dangerRingFrom: 'rgba(244, 63, 94, 0.35)',
102
102
  dangerRingTo: 'rgba(244, 63, 94, 1.0)',
103
103
  },