From 89ab27540d143c5dae99274447d53a846d12d05c Mon Sep 17 00:00:00 2001 From: Meik Date: Sat, 22 Nov 2025 13:28:42 +0100 Subject: [PATCH] minor changes --- web/app.js | 117 ++++++++++++++++++++++++++++++++++++++++++++------ web/style.css | 65 ++++++++++++---------------- 2 files changed, 131 insertions(+), 51 deletions(-) diff --git a/web/app.js b/web/app.js index b006c93..cc3a96f 100644 --- a/web/app.js +++ b/web/app.js @@ -242,6 +242,7 @@ const REFRESH_SETTINGS_KEY = 'trackerRefreshSettings'; const SORT_SETTINGS_KEY = 'trackerSortSettings'; const SORT_SETTINGS_LEGACY_KEY = 'trackerSortMode'; const FACEBOOK_TRACKING_PARAMS = ['__cft__', '__tn__', '__eep__', 'mibextid', 'set', 'comment_id', 'hoisted_section_header_type']; +const FACEBOOK_PROFILE_SEGMENT_BLOCKLIST = new Set(['reel', 'reels', 'watch', 'video.php', 'videos', 'photo.php', 'photos', 'story.php', 'permalink.php', 'share', 'posts']); const VALID_SORT_MODES = new Set(['created', 'deadline', 'smart', 'lastCheck', 'lastChange']); const DEFAULT_SORT_SETTINGS = { mode: 'created', direction: 'desc' }; const BOOKMARKS_BASE_URL = 'https://www.facebook.com/search/top'; @@ -444,6 +445,99 @@ function formatUrlForDisplay(url) { } } +function deriveFacebookProfileUrl(rawValue) { + if (typeof rawValue !== 'string') { + return null; + } + + const trimmed = rawValue.trim(); + if (!trimmed) { + return null; + } + + let parsed; + try { + parsed = new URL(trimmed); + } catch (error) { + try { + parsed = new URL(trimmed, window.location.origin); + } catch (innerError) { + try { + parsed = new URL(trimmed, 'https://www.facebook.com'); + } catch (fallbackError) { + return null; + } + } + } + + const hostname = parsed.hostname.toLowerCase(); + if (!hostname.endsWith('facebook.com')) { + return null; + } + + const origin = `${parsed.protocol}//${parsed.hostname}`; + const normalizedPath = parsed.pathname.replace(/\/+$/, '') || '/'; + const segments = normalizedPath.split('/').filter(Boolean); + const firstSegment = segments[0] || ''; + const lowerFirst = firstSegment.toLowerCase(); + const idParam = parsed.searchParams.get('id'); + + if (lowerFirst === 'groups' && segments[1]) { + return `${origin}/groups/${segments[1]}`; + } + + if (lowerFirst === 'profile.php' && idParam) { + return `${origin}/profile.php?id=${encodeURIComponent(idParam)}`; + } + + if (idParam && (lowerFirst === 'story.php' || lowerFirst === 'permalink.php')) { + return `${origin}/profile.php?id=${encodeURIComponent(idParam)}`; + } + + if (lowerFirst === 'people' && segments[1] && segments[2]) { + return `${origin}/people/${segments[1]}/${segments[2]}`; + } + + if (firstSegment && !FACEBOOK_PROFILE_SEGMENT_BLOCKLIST.has(lowerFirst)) { + return `${origin}/${firstSegment}`; + } + + if (idParam) { + return `${origin}/profile.php?id=${encodeURIComponent(idParam)}`; + } + + return null; +} + +function getProfileLinkForPost(post) { + if (!post || typeof post !== 'object') { + return null; + } + + const candidates = []; + + if (typeof post.url === 'string') { + candidates.push(post.url); + } + + if (Array.isArray(post.alternate_urls)) { + for (const alt of post.alternate_urls) { + if (typeof alt === 'string') { + candidates.push(alt); + } + } + } + + for (const candidate of candidates) { + const profileUrl = deriveFacebookProfileUrl(candidate); + if (profileUrl) { + return profileUrl; + } + } + + return null; +} + function toTimestamp(value, fallback = null) { if (!value) { return fallback; @@ -3454,14 +3548,6 @@ function createPostCard(post, status, meta = {}) { const tabTotalCount = typeof meta.tabTotalCount === 'number' ? meta.tabTotalCount : posts.length; const searchActive = !!meta.searchActive; - const counterBadge = displayIndex !== null - ? ` - - ` - : ''; - const profileRowsHtml = status.profileStatuses.map((profileStatus) => { const classes = ['profile-line', `profile-line--${profileStatus.status}`]; const isCurrentProfile = parseInt(profileStatus.profile_number, 10) === status.profileNumber; @@ -3555,6 +3641,10 @@ function createPostCard(post, status, meta = {}) { const creatorDisplay = creatorName || 'Unbekannt'; const titleText = (post.title && post.title.trim()) ? post.title.trim() : creatorDisplay; + const profileLink = getProfileLinkForPost(post); + const creatorContent = profileLink + ? `${escapeHtml(creatorDisplay)}` + : escapeHtml(creatorDisplay); const deadlineText = formatDeadline(post.deadline_at); const hasDeadline = Boolean(post.deadline_at); @@ -3598,7 +3688,6 @@ function createPostCard(post, status, meta = {}) { return `
- ${counterBadge}
${escapeHtml(titleText)}
+
+ ${status.checkedCount}/${status.targetCount} ${status.isComplete ? '✓' : ''} +
Benötigte Profile:
-
- ${status.checkedCount}/${status.targetCount} ${status.isComplete ? '✓' : ''} -
@@ -3640,9 +3729,8 @@ function createPostCard(post, status, meta = {}) {
Erstellt: ${escapeHtml(createdDate)}
Letzte Änderung: ${escapeHtml(lastChangeDate)}
-
Erstellt von: ${escapeHtml(creatorDisplay)}
+
Erstellt von: ${creatorContent}
- ${directLinkHtml}
Deadline: ${escapeHtml(deadlineText)} @@ -3655,6 +3743,7 @@ function createPostCard(post, status, meta = {}) { ` : ''}
+ ${directLinkHtml}
${profileRowsHtml} diff --git a/web/style.css b/web/style.css index 4bde367..daa7114 100644 --- a/web/style.css +++ b/web/style.css @@ -577,26 +577,6 @@ h1 { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } -.post-counter { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 26px; - height: 26px; - margin-right: 10px; - border-radius: 999px; - background: #f3f4f6; - color: #1f2937; - font-weight: 600; - font-size: 13px; -} - -.post-counter__value::before { - content: '#'; - margin-right: 2px; - color: #6b7280; -} - .post-card.complete { opacity: 0.7; border-left: 4px solid #059669; @@ -637,9 +617,11 @@ h1 { .post-header-right { display: flex; - flex-direction: column; - align-items: flex-end; - gap: 8px; + flex-direction: row; + align-items: center; + justify-content: flex-end; + flex-wrap: wrap; + gap: 10px; } .post-title-with-checkbox { @@ -663,18 +645,18 @@ h1 { .post-status { display: flex; align-items: center; - gap: 8px; - padding: 6px 12px; - background: #f0f2f5; - border-radius: 6px; - font-size: 14px; + gap: 6px; + padding: 0; + background: transparent; + border-radius: 0; + font-size: 13px; font-weight: 600; white-space: nowrap; } .post-status.complete { - background: #d1fae5; - color: #065f46; + background: transparent; + color: #059669; } @@ -956,6 +938,7 @@ h1 { flex-wrap: wrap; gap: 8px; font-size: 13px; + width: 100%; } .post-link__label { @@ -966,13 +949,27 @@ h1 { .post-link__anchor { color: #2563eb; text-decoration: none; - word-break: break-all; + word-break: normal; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; + min-width: 0; } .post-link__anchor:hover { text-decoration: underline; } +.post-creator__link { + color: #2563eb; + text-decoration: none; +} + +.post-creator__link:hover { + text-decoration: underline; +} + .post-profiles { display: flex; flex-direction: column; @@ -1720,12 +1717,6 @@ h1 { padding-left: 20px; } - .post-counter { - margin-bottom: 4px; - min-width: 24px; - height: 24px; - } - .header-controls { flex-direction: column; align-items: flex-start;