Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

CommitRow.tsx

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

CommitRow.tsxBlame108 lines · 1 contributor
9989d86Claude1import React, { useCallback } from 'react';
2import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
3import { colors } from '../theme/colors';
4import type { CommitEntry } from '../api/repos';
5
6interface CommitRowProps {
7 commit: CommitEntry;
8 onPress?: (commit: CommitEntry) => void;
9}
10
11function formatRelative(dateStr: string): string {
12 const diff = Date.now() - new Date(dateStr).getTime();
13 const mins = Math.floor(diff / 60000);
14 if (mins < 1) return 'just now';
15 if (mins < 60) return `${mins}m ago`;
16 const hrs = Math.floor(mins / 60);
17 if (hrs < 24) return `${hrs}h ago`;
18 const days = Math.floor(hrs / 24);
19 if (days < 30) return `${days}d ago`;
20 const months = Math.floor(days / 30);
21 if (months < 12) return `${months}mo ago`;
22 return `${Math.floor(months / 12)}y ago`;
23}
24
25function shortMessage(msg: string): string {
26 const firstLine = msg.split('\n')[0] ?? msg;
27 if (firstLine.length <= 72) return firstLine;
28 return firstLine.slice(0, 69) + '...';
29}
30
31export function CommitRow({ commit, onPress }: CommitRowProps): React.ReactElement {
32 const handlePress = useCallback(() => onPress?.(commit), [commit, onPress]);
33
34 return (
35 <TouchableOpacity
36 style={styles.row}
37 onPress={handlePress}
38 activeOpacity={onPress !== undefined ? 0.75 : 1}
39 >
40 <View style={styles.content}>
41 <Text style={styles.message} numberOfLines={2}>
42 {shortMessage(commit.message)}
43 </Text>
44 <View style={styles.meta}>
45 <Text style={styles.author}>{commit.authorName}</Text>
46 <Text style={styles.dot}>·</Text>
47 <Text style={styles.metaText}>{formatRelative(commit.authorDate)}</Text>
48 </View>
49 </View>
50 <View style={styles.shaContainer}>
51 <Text style={styles.sha}>{commit.sha.slice(0, 7)}</Text>
52 </View>
53 </TouchableOpacity>
54 );
55}
56
57const styles = StyleSheet.create({
58 row: {
59 flexDirection: 'row',
60 alignItems: 'center',
61 backgroundColor: colors.bgSecondary,
62 borderBottomWidth: 1,
63 borderBottomColor: colors.border,
64 paddingVertical: 12,
65 paddingHorizontal: 16,
66 gap: 12,
67 },
68 content: {
69 flex: 1,
70 gap: 4,
71 },
72 message: {
73 fontSize: 14,
74 color: colors.text,
75 lineHeight: 20,
76 },
77 meta: {
78 flexDirection: 'row',
79 alignItems: 'center',
80 gap: 5,
81 },
82 author: {
83 fontSize: 12,
84 fontWeight: '500',
85 color: colors.textMuted,
86 },
87 dot: {
88 fontSize: 12,
89 color: colors.textMuted,
90 },
91 metaText: {
92 fontSize: 12,
93 color: colors.textMuted,
94 },
95 shaContainer: {
96 paddingHorizontal: 8,
97 paddingVertical: 3,
98 backgroundColor: colors.bgTertiary,
99 borderRadius: 4,
100 borderWidth: 1,
101 borderColor: colors.border,
102 },
103 sha: {
104 fontSize: 12,
105 fontFamily: 'monospace',
106 color: colors.textLink,
107 },
108});