style: fix prettier formatting issues

Swadhin Biswas committed 6 months ago
89ff316
1 parent 1656a88
commit 89ff316
7 files changed
+564 -128
▼scripts/setup-branch-protection.sh
+98-0
1
+#!/bin/bash
2
+
3
+# Branch Protection Setup Script for Linuxy
4
+# Usage: ./scripts/setup-branch-protection.sh [GITHUB_TOKEN]
5
+
6
+set -e
7
+
8
+REPO="swadhinbiswas/linuxy"
9
+BRANCH="main"
10
+GITHUB_TOKEN="${1:-$GITHUB_TOKEN}"
11
+
12
+if [ -z "$GITHUB_TOKEN" ]; then
13
+ echo "Error: GitHub token required"
14
+ echo "Usage: $0 <GITHUB_TOKEN>"
15
+ echo "Or set GITHUB_TOKEN environment variable"
16
+ exit 1
17
+fi
18
+
19
+echo "Setting up branch protection for $REPO/$BRANCH..."
20
+
21
+# API Base URL
22
+API="https://api.github.com"
23
+
24
+# 1. Get branch protection endpoint
25
+PROTECTION_URL="$API/repos/$REPO/branches/$BRANCH/protection"
26
+
27
+# 2. Require pull request + required reviews
28
+echo "✓ Configuring PR requirements..."
29
+curl -s -X PUT "$PROTECTION_URL/required_pull_request_reviews" \
30
+ -H "Authorization: token $GITHUB_TOKEN" \
31
+ -H "Accept: application/vnd.github+json" \
32
+ -H "Content-Type: application/json" \
33
+ -d '{
34
+ "dismiss_stale_reviews": true,
35
+ "require_code_owner_reviews": true,
36
+ "required_approving_review_count": 1
37
+ }'
38
+
39
+# 3. Require status checks
40
+echo "✓ Configuring status checks..."
41
+curl -s -X PUT "$PROTECTION_URL/required_status_checks" \
42
+ -H "Authorization: token $GITHUB_TOKEN" \
43
+ -H "Accept: application/vnd.github+json" \
44
+ -H "Content-Type: application/json" \
45
+ -d '{
46
+ "strict": true,
47
+ "contexts": [
48
+ "Frontend Lint & Build",
49
+ "Rust Check & Test",
50
+ "Security Audit",
51
+ "Verify CSP Configuration",
52
+ "Integration Tests"
53
+ ]
54
+ }'
55
+
56
+# 4. Require conversation resolution
57
+echo "✓ Configuring conversation resolution..."
58
+curl -s -X PUT "$PROTECTION_URL" \
59
+ -H "Authorization: token $GITHUB_TOKEN" \
60
+ -H "Accept: application/vnd.github+json" \
61
+ -H "Content-Type: application/json" \
62
+ -d '{
63
+ "required_status_checks": null,
64
+ "enforce_admins": true,
65
+ "required_pull_request_reviews": null,
66
+ "restrictions": null,
67
+ "allow_force_pushes": false,
68
+ "allow_deletions": false,
69
+ "require_conversation_resolution": true
70
+ }'
71
+
72
+# 5. Include administrators
73
+echo "✓ Setting admin enforcement..."
74
+curl -s -X PUT "$PROTECTION_URL/enforce_admins" \
75
+ -H "Authorization: token $GITHUB_TOKEN" \
76
+ -H "Accept: application/vnd.github+json" \
77
+ -H "Content-Type: application/json" \
78
+ -d '{
79
+ "enabled": true
80
+ }'
81
+
82
+# 6. Configure branch restrictions (optional - requires team/org)
83
+echo "✓ Configuring push restrictions..."
84
+curl -s -X DELETE "$PROTECTION_URL/restrictions" \
85
+ -H "Authorization: token $GITHUB_TOKEN" \
86
+ -H "Accept: application/vnd.github+json" || true
87
+
88
+echo ""
89
+echo "✅ Branch protection configured for main!"
90
+echo ""
91
+echo "Required Status Checks (to be auto-detected after first run):"
92
+echo " - Frontend Lint & Build"
93
+echo " - Rust Check & Test"
94
+echo " - Security Audit"
95
+echo " - Verify CSP Configuration"
96
+echo " - Integration Tests"
97
+echo ""
98
+echo "Note: Status checks will be auto-detected after CI runs once."
0
99
▼scripts/setup-develop-branch.sh
+70-0
1
+#!/bin/bash
2
+
3
+# Branch Protection Setup Script for Linuxy - Develop Branch
4
+# Usage: ./scripts/setup-develop-branch.sh [GITHUB_TOKEN]
5
+
6
+set -e
7
+
8
+REPO="swadhinbiswas/linuxy"
9
+BRANCH="develop"
10
+GITHUB_TOKEN="${1:-$GITHUB_TOKEN}"
11
+
12
+if [ -z "$GITHUB_TOKEN" ]; then
13
+ echo "Error: GitHub token required"
14
+ echo "Usage: $0 <GITHUB_TOKEN>"
15
+ echo "Or set GITHUB_TOKEN environment variable"
16
+ exit 1
17
+fi
18
+
19
+echo "Setting up branch protection for $REPO/$BRANCH..."
20
+
21
+# Check if branch exists
22
+BRANCH_EXISTS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
23
+ "$API/repos/$REPO/branches/$BRANCH" | jq -r '.name // empty')
24
+
25
+if [ -z "$BRANCH_EXISTS" ]; then
26
+ echo "Branch 'develop' doesn't exist. Creating it from main..."
27
+ # Create develop branch from main
28
+ MAIN_SHA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
29
+ "$API/repos/$REPO/branches/main" | jq -r '.commit.sha')
30
+
31
+ curl -s -X POST "$API/repos/$REPO/git/refs/refs/heads/$BRANCH" \
32
+ -H "Authorization: token $GITHUB_TOKEN" \
33
+ -H "Accept: application/vnd.github+json" \
34
+ -d "{\"sha\": \"$MAIN_SHA\", \"ref\": \"refs/heads/$BRANCH\"}"
35
+
36
+ echo "✓ Created develop branch"
37
+fi
38
+
39
+# API Base URL
40
+API="https://api.github.com"
41
+PROTECTION_URL="$API/repos/$REPO/branches/$BRANCH/protection"
42
+
43
+echo "✓ Configuring protection for develop..."
44
+
45
+# Basic protection for develop
46
+curl -s -X PUT "$PROTECTION_URL" \
47
+ -H "Authorization: token $GITHUB_TOKEN" \
48
+ -H "Accept: application/vnd.github+json" \
49
+ -H "Content-Type: application/json" \
50
+ -d '{
51
+ "required_status_checks": {
52
+ "strict": false,
53
+ "contexts": [
54
+ "Frontend Lint & Build",
55
+ "Rust Check & Test"
56
+ ]
57
+ },
58
+ "enforce_admins": true,
59
+ "required_pull_request_reviews": {
60
+ "dismiss_stale_reviews": false,
61
+ "required_approving_review_count": 1
62
+ },
63
+ "restrictions": null,
64
+ "allow_force_pushes": false,
65
+ "allow_deletions": false,
66
+ "require_conversation_resolution": false
67
+ }'
68
+
69
+echo ""
70
+echo "✅ Branch protection configured for develop!"
0
71
▼src/components/AppGrid.tsx
+125-31
1
1
import React from "react";
2
2
import { Play, Trash2, ShieldAlert, ShieldCheck, RefreshCw } from "lucide-react";
3
3
import { AppInfo } from "../App";
4
-import { convertFileSrc } from '@tauri-apps/api/tauri';
4
+import { convertFileSrc } from "@tauri-apps/api/tauri";
5
5
6
6
interface AppGridProps {
7
7
apps: AppInfo[];
12
12
updatesEnabled: boolean;
13
13
}
14
14
15
-const AppGrid: React.FC<AppGridProps> = ({ apps, onLaunch, onRemove, onToggleSandbox, onUpdate, updatesEnabled }) => {
15
+const AppGrid: React.FC<AppGridProps> = ({
16
+ apps,
17
+ onLaunch,
18
+ onRemove,
19
+ onToggleSandbox,
20
+ onUpdate,
21
+ updatesEnabled,
22
+}) => {
16
23
const formatBytes = (bytes: number) => {
17
24
if (bytes === 0) return "0 B";
18
25
const k = 1024;
26
33
};
27
34
28
35
if (apps.length === 0) {
29
- return <div style={{ color: "var(--text-muted)", marginTop: "20px" }}>No AppImages installed yet. Drag and drop one to install!</div>;
36
+ return (
37
+ <div style={{ color: "var(--text-muted)", marginTop: "20px" }}>
38
+ No AppImages installed yet. Drag and drop one to install!
39
+ </div>
40
+ );
30
41
}
31
42
32
43
return (
33
- <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))", gap: "20px", marginTop: "20px" }}>
44
+ <div
45
+ style={{
46
+ display: "grid",
47
+ gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))",
48
+ gap: "20px",
49
+ marginTop: "20px",
50
+ }}
51
+ >
34
52
{apps.map((app) => (
35
- <div key={app.path} style={{
36
- background: "var(--bg-card)",
37
- borderRadius: "8px",
38
- padding: "15px",
39
- display: "flex",
40
- flexDirection: "column",
41
- alignItems: "center",
42
- position: "relative",
43
- border: "1px solid var(--border-color)",
44
- transition: "background-color 0.3s, border-color 0.3s"
45
- }}>
46
-
47
- <button
53
+ <div
54
+ key={app.path}
55
+ style={{
56
+ background: "var(--bg-card)",
57
+ borderRadius: "8px",
58
+ padding: "15px",
59
+ display: "flex",
60
+ flexDirection: "column",
61
+ alignItems: "center",
62
+ position: "relative",
63
+ border: "1px solid var(--border-color)",
64
+ transition: "background-color 0.3s, border-color 0.3s",
65
+ }}
66
+ >
67
+ <button
48
68
title={app.sandboxed ? "Sandboxed via Firejail" : "Not sandboxed"}
49
69
onClick={() => onToggleSandbox(app.desktop_path, !app.sandboxed)}
50
- style={{ position: "absolute", top: 10, right: 10, background: "transparent", border: "none", cursor: "pointer", color: app.sandboxed ? "var(--accent-color)" : "var(--text-muted)" }}
70
+ style={{
71
+ position: "absolute",
72
+ top: 10,
73
+ right: 10,
74
+ background: "transparent",
75
+ border: "none",
76
+ cursor: "pointer",
77
+ color: app.sandboxed ? "var(--accent-color)" : "var(--text-muted)",
78
+ }}
51
79
>
52
80
{app.sandboxed ? <ShieldCheck size={20} /> : <ShieldAlert size={20} />}
53
81
</button>
54
82
55
83
{app.icon ? (
56
- <img src={convertFileSrc(app.icon)} alt={app.name} style={{ width: "64px", height: "64px", marginBottom: "15px", objectFit: "contain" }} />
84
+ <img
85
+ src={convertFileSrc(app.icon)}
86
+ alt={app.name}
87
+ style={{ width: "64px", height: "64px", marginBottom: "15px", objectFit: "contain" }}
88
+ />
57
89
) : (
58
- <div style={{ width: "64px", height: "64px", background: "var(--border-color)", borderRadius: "12px", marginBottom: "15px" }}></div>
90
+ <div
91
+ style={{
92
+ width: "64px",
93
+ height: "64px",
94
+ background: "var(--border-color)",
95
+ borderRadius: "12px",
96
+ marginBottom: "15px",
97
+ }}
98
+ ></div>
59
99
)}
60
- <div style={{ fontWeight: "bold", textAlign: "center", marginBottom: "5px", wordBreak: "break-all", color: "var(--text-primary)" }}>{app.name}</div>
61
-
100
+ <div
101
+ style={{
102
+ fontWeight: "bold",
103
+ textAlign: "center",
104
+ marginBottom: "5px",
105
+ wordBreak: "break-all",
106
+ color: "var(--text-primary)",
107
+ }}
108
+ >
109
+ {app.name}
110
+ </div>
111
+
62
112
<div style={{ fontSize: "11px", color: "var(--text-muted)", marginBottom: "10px" }}>
63
113
{formatBytes(app.size_bytes)} • {formatDate(app.installed_at)}
64
114
</div>
65
-
66
- <div style={{ display: "flex", flexWrap: "wrap", gap: "10px", marginTop: "auto", paddingTop: "15px", justifyContent: "center" }}>
67
- <button
115
+
116
+ <div
117
+ style={{
118
+ display: "flex",
119
+ flexWrap: "wrap",
120
+ gap: "10px",
121
+ marginTop: "auto",
122
+ paddingTop: "15px",
123
+ justifyContent: "center",
124
+ }}
125
+ >
126
+ <button
68
127
onClick={() => onLaunch(app.path)}
69
- style={{ background: "var(--accent-color)", color: "#fff", border: "none", padding: "8px", borderRadius: "4px", cursor: "pointer", display: "flex", alignItems: "center" }}>
128
+ style={{
129
+ background: "var(--accent-color)",
130
+ color: "#fff",
131
+ border: "none",
132
+ padding: "8px",
133
+ borderRadius: "4px",
134
+ cursor: "pointer",
135
+ display: "flex",
136
+ alignItems: "center",
137
+ }}
138
+ >
70
139
<Play size={16} /> <span style={{ marginLeft: "5px", fontSize: "12px" }}>Launch</span>
71
140
</button>
72
- <button
141
+ <button
73
142
onClick={() => onUpdate(app.path)}
74
143
disabled={!updatesEnabled}
75
- style={{ background: "var(--info-color)", color: "#fff", border: "none", padding: "8px", borderRadius: "4px", cursor: updatesEnabled ? "pointer" : "not-allowed", display: "flex", alignItems: "center", opacity: updatesEnabled ? 1 : 0.55 }}
76
- title={updatesEnabled ? "Check for updates" : "Install appimageupdatetool to enable updates"}>
144
+ style={{
145
+ background: "var(--info-color)",
146
+ color: "#fff",
147
+ border: "none",
148
+ padding: "8px",
149
+ borderRadius: "4px",
150
+ cursor: updatesEnabled ? "pointer" : "not-allowed",
151
+ display: "flex",
152
+ alignItems: "center",
153
+ opacity: updatesEnabled ? 1 : 0.55,
154
+ }}
155
+ title={
156
+ updatesEnabled
157
+ ? "Check for updates"
158
+ : "Install appimageupdatetool to enable updates"
159
+ }
160
+ >
77
161
<RefreshCw size={16} />
78
162
</button>
79
- <button
163
+ <button
80
164
onClick={() => onRemove(app)}
81
- style={{ background: "var(--danger-color)", color: "#fff", border: "none", padding: "8px", borderRadius: "4px", cursor: "pointer", display: "flex", alignItems: "center" }}>
165
+ style={{
166
+ background: "var(--danger-color)",
167
+ color: "#fff",
168
+ border: "none",
169
+ padding: "8px",
170
+ borderRadius: "4px",
171
+ cursor: "pointer",
172
+ display: "flex",
173
+ alignItems: "center",
174
+ }}
175
+ >
82
176
<Trash2 size={16} />
83
177
</button>
84
178
</div>
85
179
▼src/components/DropZone.tsx
+3-3
11
11
try {
12
12
const selected = await open({
13
13
multiple: false,
14
- filters: [{ name: "AppImage", extensions: ["AppImage", "appimage"] }]
14
+ filters: [{ name: "AppImage", extensions: ["AppImage", "appimage"] }],
15
15
});
16
16
if (typeof selected === "string") {
17
17
onInstall(selected);
22
22
};
23
23
24
24
return (
25
- <div
25
+ <div
26
26
style={{
27
27
border: "2px dashed var(--border-color)",
28
28
borderRadius: "8px",
32
32
marginBottom: "20px",
33
33
background: "var(--bg-input)",
34
34
color: "var(--text-secondary)",
35
- transition: "background-color 0.3s, border-color 0.3s"
35
+ transition: "background-color 0.3s, border-color 0.3s",
36
36
}}
37
37
onClick={handleSelectFile}
38
38
>
39
39
▼src/components/Sidebar.tsx
+39-24
9
9
10
10
const Sidebar: React.FC<SidebarProps> = ({ currentView, onViewChange, onRefresh }) => {
11
11
return (
12
- <div style={{
13
- width: "250px",
14
- background: "var(--bg-sidebar)",
15
- display: "flex",
16
- flexDirection: "column",
17
- padding: "20px 0",
18
- borderRight: "1px solid var(--border-color)",
19
- transition: "background-color 0.3s, border-color 0.3s"
20
- }}>
21
- <div style={{
22
- padding: "0 20px",
23
- marginBottom: "30px",
24
- fontSize: "24px",
25
- fontWeight: "bold",
26
- color: "var(--text-primary)"
27
- }}>linuxy</div>
28
-
29
- <button
30
- style={{ ...btnStyle, background: currentView === "library" ? "rgba(255, 255, 255, 0.1)" : "transparent" }}
12
+ <div
13
+ style={{
14
+ width: "250px",
15
+ background: "var(--bg-sidebar)",
16
+ display: "flex",
17
+ flexDirection: "column",
18
+ padding: "20px 0",
19
+ borderRight: "1px solid var(--border-color)",
20
+ transition: "background-color 0.3s, border-color 0.3s",
21
+ }}
22
+ >
23
+ <div
24
+ style={{
25
+ padding: "0 20px",
26
+ marginBottom: "30px",
27
+ fontSize: "24px",
28
+ fontWeight: "bold",
29
+ color: "var(--text-primary)",
30
+ }}
31
+ >
32
+ linuxy
33
+ </div>
34
+
35
+ <button
36
+ style={{
37
+ ...btnStyle,
38
+ background: currentView === "library" ? "rgba(255, 255, 255, 0.1)" : "transparent",
39
+ }}
31
40
onClick={() => onViewChange("library")}
32
41
>
33
42
<LayoutGrid size={18} style={{ marginRight: 10 }} /> Library
34
43
</button>
35
44
36
- <button
37
- style={{ ...btnStyle, background: currentView === "discover" ? "rgba(255, 255, 255, 0.1)" : "transparent" }}
45
+ <button
46
+ style={{
47
+ ...btnStyle,
48
+ background: currentView === "discover" ? "rgba(255, 255, 255, 0.1)" : "transparent",
49
+ }}
38
50
onClick={() => onViewChange("discover")}
39
51
>
40
52
<Compass size={18} style={{ marginRight: 10 }} /> Discover
41
53
</button>
42
54
43
- <button
44
- style={{ ...btnStyle, background: currentView === "settings" ? "rgba(255, 255, 255, 0.1)" : "transparent" }}
55
+ <button
56
+ style={{
57
+ ...btnStyle,
58
+ background: currentView === "settings" ? "rgba(255, 255, 255, 0.1)" : "transparent",
59
+ }}
45
60
onClick={() => onViewChange("settings")}
46
61
>
47
62
<Settings size={18} style={{ marginRight: 10 }} /> Settings
66
81
textAlign: "left",
67
82
fontSize: "16px",
68
83
width: "100%",
69
- transition: "background 0.2s"
84
+ transition: "background 0.2s",
70
85
};
71
86
72
87
export default Sidebar;
73
88
▼src/components/Storefront.tsx
+226-69
33
33
const data = await response.json();
34
34
setApps(data.items || []);
35
35
} else {
36
- const response = await fetch("https://api.github.com/search/repositories?q=topic:appimage&sort=stars&order=desc&per_page=100");
36
+ const response = await fetch(
37
+ "https://api.github.com/search/repositories?q=topic:appimage&sort=stars&order=desc&per_page=100"
38
+ );
37
39
if (!response.ok) throw new Error("Failed to fetch GitHub data");
38
40
const data = await response.json();
39
41
const githubApps = data.items.map((item: any) => ({
43
45
links: [{ type: "GitHub", url: item.html_url }],
44
46
github_url: item.html_url,
45
47
stargazers_count: item.stargazers_count,
46
- icons: [item.owner.avatar_url]
48
+ icons: [item.owner.avatar_url],
47
49
}));
48
50
setApps(githubApps);
49
51
}
55
57
}
56
58
};
57
59
58
- const filteredApps = apps.filter(app =>
59
- app.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
60
- (app.description && app.description.toLowerCase().includes(searchTerm.toLowerCase()))
60
+ const filteredApps = apps.filter(
61
+ (app) =>
62
+ app.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
63
+ (app.description && app.description.toLowerCase().includes(searchTerm.toLowerCase()))
61
64
);
62
65
63
66
return (
64
67
<div style={{ paddingBottom: "40px" }}>
65
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
68
+ <div
69
+ style={{
70
+ display: "flex",
71
+ justifyContent: "space-between",
72
+ alignItems: "center",
73
+ marginBottom: "20px",
74
+ }}
75
+ >
66
76
<div>
67
77
<h2 style={{ color: "var(--text-primary)" }}>Discover AppImages</h2>
68
78
<p style={{ color: "var(--text-secondary)" }}>
69
- {source === "appimagehub" ? "Browsing AppImageHub Catalog" : "Browsing Popular GitHub AppImage Projects"}
79
+ {source === "appimagehub"
80
+ ? "Browsing AppImageHub Catalog"
81
+ : "Browsing Popular GitHub AppImage Projects"}
70
82
</p>
71
83
</div>
72
- <div style={{ display: "flex", gap: "10px", background: "var(--bg-input)", padding: "5px", borderRadius: "8px", border: "1px solid var(--border-color)" }}>
73
- <button
84
+ <div
85
+ style={{
86
+ display: "flex",
87
+ gap: "10px",
88
+ background: "var(--bg-input)",
89
+ padding: "5px",
90
+ borderRadius: "8px",
91
+ border: "1px solid var(--border-color)",
92
+ }}
93
+ >
94
+ <button
74
95
onClick={() => setSource("appimagehub")}
75
- style={{
76
- display: "flex", alignItems: "center", gap: "8px", padding: "8px 12px", border: "none", borderRadius: "6px", cursor: "pointer",
77
- background: source === "appimagehub" ? "var(--bg-card)" : "transparent", color: "var(--text-primary)",
78
- boxShadow: source === "appimagehub" ? "0 2px 4px rgba(0,0,0,0.2)" : "none"
79
- }}>
96
+ style={{
97
+ display: "flex",
98
+ alignItems: "center",
99
+ gap: "8px",
100
+ padding: "8px 12px",
101
+ border: "none",
102
+ borderRadius: "6px",
103
+ cursor: "pointer",
104
+ background: source === "appimagehub" ? "var(--bg-card)" : "transparent",
105
+ color: "var(--text-primary)",
106
+ boxShadow: source === "appimagehub" ? "0 2px 4px rgba(0,0,0,0.2)" : "none",
107
+ }}
108
+ >
80
109
<Globe size={16} /> Hub
81
110
</button>
82
- <button
111
+ <button
83
112
onClick={() => setSource("github")}
84
- style={{
85
- display: "flex", alignItems: "center", gap: "8px", padding: "8px 12px", border: "none", borderRadius: "6px", cursor: "pointer",
86
- background: source === "github" ? "var(--bg-card)" : "transparent", color: "var(--text-primary)",
87
- boxShadow: source === "github" ? "0 2px 4px rgba(0,0,0,0.2)" : "none"
88
- }}>
113
+ style={{
114
+ display: "flex",
115
+ alignItems: "center",
116
+ gap: "8px",
117
+ padding: "8px 12px",
118
+ border: "none",
119
+ borderRadius: "6px",
120
+ cursor: "pointer",
121
+ background: source === "github" ? "var(--bg-card)" : "transparent",
122
+ color: "var(--text-primary)",
123
+ boxShadow: source === "github" ? "0 2px 4px rgba(0,0,0,0.2)" : "none",
124
+ }}
125
+ >
89
126
<Github size={16} /> GitHub
90
127
</button>
91
128
</div>
92
129
</div>
93
130
94
131
<div style={{ position: "relative", marginBottom: "20px", maxWidth: "400px" }}>
95
- <Search size={18} style={{ position: "absolute", left: "10px", top: "10px", color: "var(--text-muted)" }} />
96
- <input
97
- type="text"
98
- placeholder="Search catalog..."
132
+ <Search
133
+ size={18}
134
+ style={{ position: "absolute", left: "10px", top: "10px", color: "var(--text-muted)" }}
135
+ />
136
+ <input
137
+ type="text"
138
+ placeholder="Search catalog..."
99
139
value={searchTerm}
100
140
onChange={(e) => setSearchTerm(e.target.value)}
101
- style={{
102
- width: "100%", padding: "10px 10px 10px 35px", background: "var(--bg-input)", border: "1px solid var(--border-color)", borderRadius: "6px", color: "var(--text-primary)", fontSize: "16px"
141
+ style={{
142
+ width: "100%",
143
+ padding: "10px 10px 10px 35px",
144
+ background: "var(--bg-input)",
145
+ border: "1px solid var(--border-color)",
146
+ borderRadius: "6px",
147
+ color: "var(--text-primary)",
148
+ fontSize: "16px",
103
149
}}
104
150
/>
105
151
</div>
106
152
107
- {loading && <div style={{ textAlign: "center", padding: "40px", color: "var(--text-secondary)" }}>Loading {source === "github" ? "GitHub projects" : "Hub catalog"}...</div>}
108
- {error && <div style={{ color: "var(--danger-color)", padding: "20px", background: "rgba(255,0,0,0.1)", borderRadius: "8px" }}>{error}</div>}
153
+ {loading && (
154
+ <div style={{ textAlign: "center", padding: "40px", color: "var(--text-secondary)" }}>
155
+ Loading {source === "github" ? "GitHub projects" : "Hub catalog"}...
156
+ </div>
157
+ )}
158
+ {error && (
159
+ <div
160
+ style={{
161
+ color: "var(--danger-color)",
162
+ padding: "20px",
163
+ background: "rgba(255,0,0,0.1)",
164
+ borderRadius: "8px",
165
+ }}
166
+ >
167
+ {error}
168
+ </div>
169
+ )}
109
170
110
- <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: "20px" }}>
171
+ <div
172
+ style={{
173
+ display: "grid",
174
+ gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))",
175
+ gap: "20px",
176
+ }}
177
+ >
111
178
{filteredApps.map((app, idx) => {
112
- const githubLink = app.links?.find(l => l.type.toLowerCase() === "github" || l.type.toLowerCase() === "homepage");
113
- const downloadLink = app.links?.find(l => l.type.toLowerCase() === "download") || githubLink;
114
-
179
+ const githubLink = app.links?.find(
180
+ (l) => l.type.toLowerCase() === "github" || l.type.toLowerCase() === "homepage"
181
+ );
182
+ const downloadLink =
183
+ app.links?.find((l) => l.type.toLowerCase() === "download") || githubLink;
184
+
115
185
return (
116
- <div key={idx} style={{
117
- background: "var(--bg-card)",
118
- borderRadius: "8px",
119
- padding: "20px",
120
- display: "flex",
121
- flexDirection: "column",
122
- border: "1px solid var(--border-color)",
123
- transition: "background-color 0.3s, border-color 0.3s"
124
- }}>
186
+ <div
187
+ key={idx}
188
+ style={{
189
+ background: "var(--bg-card)",
190
+ borderRadius: "8px",
191
+ padding: "20px",
192
+ display: "flex",
193
+ flexDirection: "column",
194
+ border: "1px solid var(--border-color)",
195
+ transition: "background-color 0.3s, border-color 0.3s",
196
+ }}
197
+ >
125
198
<div style={{ display: "flex", alignItems: "center", marginBottom: "15px" }}>
126
199
{app.icons && app.icons.length > 0 ? (
127
- <img
128
- src={app.icons[0].startsWith("http") ? app.icons[0] : `https://appimage.github.io/database/${app.icons[0]}`}
129
- alt={app.name}
130
- style={{ width: "56px", height: "56px", marginRight: "15px", objectFit: "contain", borderRadius: "8px" }}
200
+ <img
201
+ src={
202
+ app.icons[0].startsWith("http")
203
+ ? app.icons[0]
204
+ : `https://appimage.github.io/database/${app.icons[0]}`
205
+ }
206
+ alt={app.name}
207
+ style={{
208
+ width: "56px",
209
+ height: "56px",
210
+ marginRight: "15px",
211
+ objectFit: "contain",
212
+ borderRadius: "8px",
213
+ }}
131
214
/>
132
215
) : (
133
- <div style={{ width: "56px", height: "56px", background: "var(--border-color)", borderRadius: "8px", marginRight: "15px", display: "flex", alignItems: "center", justifyContent: "center" }}>
216
+ <div
217
+ style={{
218
+ width: "56px",
219
+ height: "56px",
220
+ background: "var(--border-color)",
221
+ borderRadius: "8px",
222
+ marginRight: "15px",
223
+ display: "flex",
224
+ alignItems: "center",
225
+ justifyContent: "center",
226
+ }}
227
+ >
134
228
<Globe size={24} color="var(--text-muted)" />
135
229
</div>
136
230
)}
137
231
<div style={{ overflow: "hidden" }}>
138
- <div style={{ fontWeight: "bold", fontSize: "18px", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", color: "var(--text-primary)" }}>{app.name}</div>
139
- <div style={{ fontSize: "13px", color: "var(--text-secondary)", display: "flex", alignItems: "center", gap: "5px" }}>
140
- {source === "github" && <Github size={12} />} {app.authors?.[0]?.name || "Unknown"}
141
- {app.stargazers_count !== undefined && <span style={{ color: "#e3b341" }}>★ {app.stargazers_count}</span>}
232
+ <div
233
+ style={{
234
+ fontWeight: "bold",
235
+ fontSize: "18px",
236
+ whiteSpace: "nowrap",
237
+ overflow: "hidden",
238
+ textOverflow: "ellipsis",
239
+ color: "var(--text-primary)",
240
+ }}
241
+ >
242
+ {app.name}
243
+ </div>
244
+ <div
245
+ style={{
246
+ fontSize: "13px",
247
+ color: "var(--text-secondary)",
248
+ display: "flex",
249
+ alignItems: "center",
250
+ gap: "5px",
251
+ }}
252
+ >
253
+ {source === "github" && <Github size={12} />}{" "}
254
+ {app.authors?.[0]?.name || "Unknown"}
255
+ {app.stargazers_count !== undefined && (
256
+ <span style={{ color: "#e3b341" }}>★ {app.stargazers_count}</span>
257
+ )}
142
258
</div>
143
259
</div>
144
260
</div>
145
-
146
- <div style={{ fontSize: "14px", color: "var(--text-secondary)", marginBottom: "20px", flex: 1, overflow: "hidden", display: "-webkit-box", WebkitLineClamp: 3, WebkitBoxOrient: "vertical", lineHeight: "1.5" }}>
261
+
262
+ <div
263
+ style={{
264
+ fontSize: "14px",
265
+ color: "var(--text-secondary)",
266
+ marginBottom: "20px",
267
+ flex: 1,
268
+ overflow: "hidden",
269
+ display: "-webkit-box",
270
+ WebkitLineClamp: 3,
271
+ WebkitBoxOrient: "vertical",
272
+ lineHeight: "1.5",
273
+ }}
274
+ >
147
275
{app.description || "No description available for this project."}
148
276
</div>
149
-
277
+
150
278
<div style={{ display: "flex", gap: "10px" }}>
151
- <button
279
+ <button
152
280
disabled={!downloadLink && source !== "github"}
153
281
onClick={async () => {
154
282
try {
157
285
const parts = app.github_url.split("/");
158
286
const owner = parts[parts.length - 2];
159
287
const repo = parts[parts.length - 1];
160
-
288
+
161
289
// Fetch releases
162
- const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases/latest`);
290
+ const res = await fetch(
291
+ `https://api.github.com/repos/${owner}/${repo}/releases/latest`
292
+ );
163
293
const release = await res.json();
164
- const asset = release.assets?.find((a: any) => a.name.toLowerCase().endsWith(".appimage"));
165
-
294
+ const asset = release.assets?.find((a: any) =>
295
+ a.name.toLowerCase().endsWith(".appimage")
296
+ );
297
+
166
298
if (asset) {
167
- await invoke("download_and_install", { url: asset.browser_download_url, name: app.name });
299
+ await invoke("download_and_install", {
300
+ url: asset.browser_download_url,
301
+ name: app.name,
302
+ });
168
303
} else {
169
304
// Fallback to browser if no asset found
170
305
await invoke("open_url", { url: `${app.github_url}/releases` });
171
306
}
172
307
} else if (downloadLink) {
173
- await invoke("download_and_install", { url: downloadLink.url, name: app.name });
308
+ await invoke("download_and_install", {
309
+ url: downloadLink.url,
310
+ name: app.name,
311
+ });
174
312
}
175
313
} catch (e) {
176
314
setError(String(e));
177
315
}
178
316
}}
179
- style={{
180
- flex: 1, background: "#4caf50", color: "#fff", border: "none", padding: "10px", borderRadius: "6px", cursor: "pointer",
181
- display: "flex", alignItems: "center", justifyContent: "center", fontWeight: "bold", gap: "8px"
182
- }}>
317
+ style={{
318
+ flex: 1,
319
+ background: "#4caf50",
320
+ color: "#fff",
321
+ border: "none",
322
+ padding: "10px",
323
+ borderRadius: "6px",
324
+ cursor: "pointer",
325
+ display: "flex",
326
+ alignItems: "center",
327
+ justifyContent: "center",
328
+ fontWeight: "bold",
329
+ gap: "8px",
330
+ }}
331
+ >
183
332
<Download size={16} /> Install
184
333
</button>
185
334
{app.github_url && (
186
- <button
335
+ <button
187
336
onClick={() => invoke("open_url", { url: app.github_url })}
188
- style={{
189
- background: "var(--bg-input)", color: "var(--text-primary)", border: "1px solid var(--border-color)", width: "40px", borderRadius: "6px", cursor: "pointer",
190
- display: "flex", alignItems: "center", justifyContent: "center"
191
- }}>
337
+ style={{
338
+ background: "var(--bg-input)",
339
+ color: "var(--text-primary)",
340
+ border: "1px solid var(--border-color)",
341
+ width: "40px",
342
+ borderRadius: "6px",
343
+ cursor: "pointer",
344
+ display: "flex",
345
+ alignItems: "center",
346
+ justifyContent: "center",
347
+ }}
348
+ >
192
349
<Github size={18} />
193
350
</button>
194
351
)}
195
352
▼src/styles/main.css
+3-1
40
40
background-color: var(--bg-main);
41
41
color: var(--text-primary);
42
42
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
43
- transition: background-color 0.3s, color 0.3s;
43
+ transition:
44
+ background-color 0.3s,
45
+ color 0.3s;
44
46
}
45
47
46
48
#root {
47
49