← back to SDCC Stories
public/index.html
145 lines
<!DOCTYPE html>
<html lang="en">
<head>
<script>
// Credential-safe fetch guard (fleet drop-in) — if this page is opened with
// credentials in the URL (a saved bookmark / Chrome-remembered basic-auth:
// https://user:pass@host/…), the browser poisons document.baseURI, so any
// relative or root-relative fetch('/api/…') throws "Request cannot be constructed
// from a URL that includes credentials" and callers silently fall to an empty
// state. Resolve every non-absolute request URL against the credential-free
// location instead of baseURI. Placed first so it wraps window.fetch before any
// app script runs. Ref: creds-in-url-fetch-guard-fleet-pattern.
(function () {
var _fetch = window.fetch.bind(window);
var cleanBase = function () { return location.origin + location.pathname; };
window.fetch = function (input, init) {
try {
if (typeof input === 'string' && !/^[a-z]+:\/\//i.test(input) && input.indexOf('//') !== 0) {
input = new URL(input, cleanBase()).href;
} else if (input instanceof Request && !/^[a-z]+:\/\//i.test(input.url)) {
input = new Request(new URL(input.url, cleanBase()).href, input);
}
} catch (_) { /* fall through to native */ }
return _fetch(input, init);
};
})();
</script>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SDCC Story Engine</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<header>
<div class="header-left">
<h1>SDCC Story Engine</h1>
<span class="subtitle">Borrower Stories → Social Impact</span>
</div>
<div class="header-center">
<div class="global-search-wrap">
<input
type="text"
id="global-search-input"
class="global-search-input"
placeholder="Search candidates, stories, settings… (⌘K)"
autocomplete="off"
onfocus="openGlobalSearch()"
oninput="onGlobalSearchInput(event)"
onkeydown="onGlobalSearchKeyDown(event)"
>
<div id="global-search-results" class="global-search-results" hidden></div>
</div>
</div>
<div class="header-right">
<span id="ig-status" class="badge">Instagram: Checking...</span>
<button class="btn btn-sm" onclick="connectInstagram()">Connect IG</button>
</div>
</header>
<div class="stats-bar" id="stats-bar"></div>
<nav class="tabs">
<button class="tab active" data-tab="candidates" onclick="switchTab('candidates')">Candidates</button>
<button class="tab" data-tab="stories" onclick="switchTab('stories')">Stories</button>
<button class="tab" data-tab="calendar" onclick="switchTab('calendar')">Calendar</button>
<button class="tab" data-tab="heatmap" onclick="switchTab('heatmap')">Heat Map</button>
<button class="tab" data-tab="ideas" onclick="switchTab('ideas')">Content Ideas</button>
<button class="tab" data-tab="settings" onclick="switchTab('settings')">Settings</button>
</nav>
<!-- Candidates Tab -->
<div class="tab-content active" id="tab-candidates">
<div class="controls">
<div class="filter-group">
<label>Tier:</label>
<select id="filter-tier" onchange="loadCandidates()">
<option value="">All</option>
<option value="A">A — Press + Social + Lawmakers</option>
<option value="B">B — Social + Lawmakers</option>
<option value="C">C — Social Only</option>
<option value="D">D — Needs Enrichment</option>
</select>
</div>
<div class="filter-group">
<input type="text" id="filter-search" placeholder="Search name, zip, story..." onkeyup="debounceSearch()">
</div>
<button class="btn btn-action" onclick="loadCandidates()">Search</button>
<button class="btn btn-resource" onclick="refreshData()">Refresh from Sheet</button>
</div>
<div class="candidate-count" id="candidate-count"></div>
<div class="candidate-list" id="candidate-list"></div>
<div class="pagination" id="pagination"></div>
</div>
<!-- Stories Tab -->
<div class="tab-content" id="tab-stories">
<div class="controls">
<select id="story-filter" onchange="loadStories()">
<option value="">All Stories</option>
<option value="draft">Drafts</option>
<option value="scheduled">Scheduled</option>
<option value="posted">Posted</option>
</select>
</div>
<div class="story-list" id="story-list"></div>
</div>
<!-- Calendar Tab -->
<div class="tab-content" id="tab-calendar">
<div class="controls">
<button class="btn btn-action" onclick="autoFillCalendar()">Auto-Fill 7 Days</button>
<span class="hint">Picks top Tier A/B candidates, generates stories, schedules 2x daily (9am + 6pm PT)</span>
</div>
<div class="calendar-grid" id="calendar-grid"></div>
</div>
<!-- Heat Map Tab -->
<div class="tab-content" id="tab-heatmap">
<div class="heatmap-container" id="heatmap-container"></div>
</div>
<!-- Content Ideas Tab -->
<div class="tab-content" id="tab-ideas">
<div class="ideas-grid" id="ideas-grid"></div>
</div>
<!-- Settings Tab -->
<div class="tab-content" id="tab-settings">
<div class="settings-form" id="settings-form"></div>
</div>
<!-- Candidate Detail Modal -->
<div class="modal" id="candidate-modal">
<div class="modal-content">
<button class="modal-close" onclick="closeModal()">×</button>
<div id="candidate-detail"></div>
</div>
</div>
<script src="/js/app.js"></script>
</body>
</html>