Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@
return `<span class="star-count"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>${formatNumber(stars)}</span>`;
}

function platformIcon(platform) {
if (platform === "ios") {
return `<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>`;
}
if (platform === "android") {
return `<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C14.15 1.23 13.1 1 12 1c-1.1 0-2.15.23-3.12.63L7.4.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.3 1.3C6.34 3.07 5 5.38 5 8h14c0-2.62-1.34-4.93-3.47-5.84zM10 6H9V5h1v1zm5 0h-1V5h1v1z"/></svg>`;
}
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>`;
}

function isPaidApp(app) {
return app.price && app.price !== "Free" && app.price !== "free";
}
Expand All @@ -95,6 +105,8 @@

function getButtonLabel(app) {
if (isPaidApp(app)) return app.price;
if (app.links && app.links.length > 0) return "Get";
if (app.category && (app.category.includes("games") || app.category.includes("entertainment"))) return "Get";
if (app.brew || app.downloadUrl || app.installCommand) return "Get";
return "View";
}
Expand Down Expand Up @@ -326,9 +338,23 @@
<div class="app-detail-title">${app.name}</div>
<div class="app-detail-subtitle">${app.subtitle}</div>
Comment thread
osman-koc marked this conversation as resolved.
Outdated
<div class="app-detail-actions">
${app.links && app.links.length > 0 ? `
<div class="get-dropdown-wrapper">
<button class="app-detail-get-btn${isPaidApp(app) ? " buy-btn" : ""}" data-action="get" data-app="${app.id}">
${getButtonLabel(app)}
</button>
<div class="get-dropdown" id="get-dropdown-${app.id}">
${app.links.map(link => `
Comment thread
osman-koc marked this conversation as resolved.
Outdated
<a class="get-dropdown-item" href="${link.url}" target="_blank" rel="noopener">
<span class="get-dropdown-icon">${platformIcon(link.platform)}</span>
<span class="get-dropdown-label">${link.label}</span>
<span class="get-dropdown-arrow">›</span>
</a>`).join("")}
Comment thread
osman-koc marked this conversation as resolved.
</div>
</div>` : `
<button class="app-detail-get-btn${isPaidApp(app) ? " buy-btn" : ""}" data-action="get" data-app="${app.id}">
${getButtonLabel(app)}
</button>
</button>`}
<a href="${app.github}" target="_blank" rel="noopener" class="github-link">
${icons.github} View on GitHub
</a>
Expand Down Expand Up @@ -596,6 +622,36 @@
};
}

function showLinksModal(app) {
const overlay = $("#modalOverlay");
const modal = $("#modal");

modal.innerHTML = `
<button class="modal-close" data-action="close-modal">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
<div class="modal-icon"${iconContainerStyle(app)}>${renderIcon(app)}</div>
<h3>${app.name}</h3>
<div class="modal-platform-links">
${app.links.map(link => `
<a class="modal-platform-link" href="${link.url}" target="_blank" rel="noopener">
<span class="modal-platform-icon">${platformIcon(link.platform)}</span>
<span class="modal-platform-label">${link.label}</span>
<span class="modal-platform-chevron">›</span>
</a>`).join("")}
Comment thread
osman-koc marked this conversation as resolved.
</div>
`;

overlay.style.display = "flex";
requestAnimationFrame(() => overlay.classList.add("visible"));

overlay.onclick = (e) => {
if (e.target === overlay || e.target.closest("[data-action='close-modal']")) {
closeModal();
}
};
}

function closeModal() {
const overlay = $("#modalOverlay");
overlay.classList.remove("visible");
Expand Down Expand Up @@ -638,6 +694,17 @@
if (!app) return;
if (isPaidApp(app)) {
showBuyModal(app);
} else if (app.links && app.links.length > 0) {
if (btn.classList.contains("app-detail-get-btn")) {
const dropdown = document.getElementById(`get-dropdown-${app.id}`);
if (dropdown) {
const isOpen = dropdown.classList.contains("open");
$$(".get-dropdown.open").forEach(d => d.classList.remove("open"));
if (!isOpen) dropdown.classList.add("open");
}
} else {
showLinksModal(app);
}
} else if (app.brew || app.installCommand) {
showBrewModal(app);
} else if (app.homepage) {
Expand Down Expand Up @@ -760,6 +827,7 @@
function bindKeyboard() {
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
$$(".get-dropdown.open").forEach(d => d.classList.remove("open"));
closeModal();
if (currentApp) navigate(currentView);
}
Expand All @@ -768,6 +836,11 @@
$("#searchInput").focus();
}
});
document.addEventListener("click", (e) => {
if (!e.target.closest(".get-dropdown-wrapper")) {
$$(".get-dropdown.open").forEach(d => d.classList.remove("open"));
}
});
}

// Init
Expand Down
164 changes: 158 additions & 6 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,8 @@ body {
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
overflow: hidden;
height: 100vh;
width: 100vw;
width: 100%;
user-select: none;
transition: background 0.3s ease, color 0.3s ease;
overflow-wrap: break-word;
Expand All @@ -109,8 +108,7 @@ body {
.app-store {
display: flex;
height: 100vh;
max-width: 100vw;
overflow: hidden;
max-width: 100%;
}

/* Sidebar */
Expand Down Expand Up @@ -1571,7 +1569,7 @@ body {
@media (max-width: 600px) {
.content-scroll {
padding: 16px 12px 32px;
max-width: 100vw;
max-width: 100%;
box-sizing: border-box;
}

Expand All @@ -1581,7 +1579,6 @@ body {
.app-detail {
min-width: 0;
max-width: 100%;
overflow: hidden;
}

.app-row {
Expand All @@ -1607,6 +1604,10 @@ body {
text-align: center;
}

.app-detail-actions {
justify-content: center;
}

.app-detail-icon {
width: 96px;
height: 96px;
Expand Down Expand Up @@ -1644,3 +1645,154 @@ body {
.content-scroll > * {
animation: fadeIn 0.3s ease both;
}

/* Platform Links (detail page) */
.platform-links {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 16px;
}

.platform-link-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 20px;
border: 1.5px solid var(--border-light);
border-radius: 100px;
color: var(--accent);
text-decoration: none;
font-size: 14px;
font-weight: 600;
font-family: inherit;
cursor: pointer;
background: none;
transition: background var(--transition), border-color var(--transition);
}

.platform-link-btn:hover {
background: var(--get-btn-hover);
}

Comment thread
osman-koc marked this conversation as resolved.
Outdated
/* Modal Platform Links */
.modal-platform-links {
display: flex;
flex-direction: column;
margin-top: 8px;
border: 1px solid var(--border);
border-radius: var(--radius-md);
overflow: hidden;
}

.modal-platform-link {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
text-decoration: none;
color: var(--text-primary);
border-bottom: 1px solid var(--border);
transition: background var(--transition);
}

.modal-platform-link:last-child {
border-bottom: none;
}

.modal-platform-link:hover {
background: var(--row-hover);
}

.modal-platform-icon {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--text-secondary);
}

.modal-platform-label {
flex: 1;
font-size: 15px;
font-weight: 500;
}

.modal-platform-chevron {
color: var(--text-tertiary);
font-size: 18px;
line-height: 1;
}

/* Get Dropdown (detail page) */
.get-dropdown-wrapper {
position: relative;
display: inline-flex;
flex-direction: column;
align-items: flex-start;
}

.get-dropdown {
position: absolute;
top: calc(100% + 8px);
left: 0;
min-width: 200px;
background: var(--bg-secondary);
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
opacity: 0;
transform: translateY(-8px) scale(0.97);
transition: opacity 0.18s ease, transform 0.18s ease;
pointer-events: none;
z-index: 50;
overflow: hidden;
}

.get-dropdown.open {
opacity: 1;
transform: translateY(0) scale(1);
pointer-events: auto;
}

.get-dropdown-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
text-decoration: none;
color: var(--text-primary);
border-bottom: 1px solid var(--border);
transition: background var(--transition);
}

.get-dropdown-item:last-child {
border-bottom: none;
}

.get-dropdown-item:hover {
background: var(--row-hover);
}

.get-dropdown-icon {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--text-secondary);
}

.get-dropdown-label {
flex: 1;
font-size: 14px;
font-weight: 500;
}

.get-dropdown-arrow {
color: var(--text-tertiary);
font-size: 18px;
line-height: 1;
}
Loading