closed sections by default, yyyy-mm-dd hh:mm timestamp, infos section with stored answers, needs updated with coupon/homepage done

This commit is contained in:
Oliver
2026-06-09 19:41:24 -03:00
parent f2a96d8cff
commit 09c0605bf6
+101 -46
View File
@@ -99,15 +99,18 @@
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
margin-bottom: 0;
cursor: pointer;
user-select: none;
padding: 6px 0;
}
.section-header:hover { color: var(--accent); }
.section-header h2 {
font-size: 15px;
font-weight: 600;
color: var(--text);
}
.section-header:hover h2 { color: var(--accent); }
.section-header .count {
font-size: 12px;
color: var(--text-muted);
@@ -121,12 +124,17 @@
}
.section-toggle.collapsed { transform: rotate(-90deg); }
.section-body {
transition: max-height .25s ease, opacity .15s ease;
transition: max-height .25s ease, opacity .15s ease, margin .15s ease;
overflow: hidden;
max-height: 0;
opacity: 0;
margin: 0;
}
.section-body.open {
max-height: 20000px;
opacity: 1;
margin-top: 12px;
}
.section-body.hidden { max-height: 0; opacity: 0; padding: 0; }
/* ── Goals Grid ──────────────────────── */
.goals-grid {
@@ -460,6 +468,39 @@
}
.highlight { color: var(--accent); }
/* ── Infos ───────────────────────────── */
.infos-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-card);
padding: 20px 24px;
}
.infos-list { list-style: none; }
.infos-list li {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 7px 0;
border-bottom: 1px solid rgba(30,30,42,.4);
font-size: 13px;
color: var(--text);
line-height: 1.6;
}
.infos-list li:last-child { border-bottom: none; }
.infos-list li .info-label {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .04em;
color: var(--accent);
white-space: nowrap;
flex-shrink: 0;
min-width: 100px;
}
.infos-list li .info-value {
color: var(--text);
}
@media (max-width: 900px) {
.campaign-grid { grid-template-columns: 1fr; }
.comms-grid { grid-template-columns: 1fr; }
@@ -491,7 +532,7 @@
<div class="section">
<div class="section-header" onclick="toggleSection('goals-section', this)">
<h2>🎯 Q2/2026 Goals</h2>
<span class="section-toggle"></span>
<span class="section-toggle collapsed"></span>
</div>
<div class="section-body" id="goals-section">
<div class="goals-grid" id="goals-grid"></div>
@@ -503,19 +544,19 @@
<div class="section-header" onclick="toggleSection('campaigns-section', this)">
<h2>📡 Campaigns</h2>
<span class="section-count count">overview</span>
<span class="section-toggle"></span>
<span class="section-toggle collapsed"></span>
</div>
<div class="section-body" id="campaigns-section">
<div class="campaign-grid" id="campaign-grid"></div>
</div>
</div>
<!-- ════════ NEEDS (CHECKBOXES) ════════ -->
<!-- ════════ NEEDS ════════ -->
<div class="section">
<div class="section-header" onclick="toggleSection('needs-section', this)">
<h2>📦 Items Needed From You</h2>
<span class="section-count count">click to check off</span>
<span class="section-toggle"></span>
<span class="section-toggle collapsed"></span>
</div>
<div class="section-body" id="needs-section">
<div class="needs-card">
@@ -529,18 +570,32 @@
<div class="section-header" onclick="toggleSection('comms-section', this)">
<h2>✉ Communications</h2>
<span class="section-count count">important only</span>
<span class="section-toggle"></span>
<span class="section-toggle collapsed"></span>
</div>
<div class="section-body" id="comms-section">
<div class="comms-grid" id="comms-grid"></div>
</div>
</div>
<!-- ════════ INFOS ════════ -->
<div class="section">
<div class="section-header" onclick="toggleSection('infos-section', this)">
<h2>📋 Infos</h2>
<span class="section-count count">look here for answers</span>
<span class="section-toggle collapsed"></span>
</div>
<div class="section-body" id="infos-section">
<div class="infos-card">
<ul class="infos-list" id="infos-list"></ul>
</div>
</div>
</div>
<!-- ════════ ROUTINE ════════ -->
<div class="section">
<div class="section-header" onclick="toggleSection('routine-section', this)">
<h2>⏰ Daily Routine</h2>
<span class="section-toggle"></span>
<span class="section-toggle collapsed"></span>
</div>
<div class="section-body" id="routine-section">
<div class="grid-2">
@@ -641,22 +696,31 @@
}
];
/* Top 5 most important needs */
/* Top 5 needs — 2 done after Oliver's last update */
const NEEDS = [
{ id: "n1", text: "Business emails for top 20 YouTube creators — blocking cold email outreach", done: false },
{ id: "n2", text: "Influencer partnership budget (free plans? cash? affiliate %?)", done: false },
{ id: "n2", text: "Coupon codes ready: creator950 ($9.50), friends950 ($9.50) — unlimited, includes OpenRouter credits", done: true },
{ id: "n3", text: "Product demo video (3 min screen recording)", done: false },
{ id: "n4", text: "Social media account access (X/Twitter + LinkedIn posting)", done: false },
{ id: "n5", text: "'Why I built Derez.ai' notes for blog post", done: false },
{ id: "n5", text: "'Why I built Derez.ai' story — available on homepage", done: true },
];
/* Filtered comms — spam/sales/ads/work-for-you removed */
/* ── Infos (answers Oliver asked for, stored here not chat) ── */
const infos = [
{ label: 'Coupon Codes', value: 'creator950 ($9.50 off), friends950 ($9.50 off) — unlimited use, OpenRouter credits still apply' },
{ label: 'Cold Email', value: 'Signed as Mark — Customer Success Agent. Templates reviewed via Telegram before send.' },
{ label: 'Influencer Offer', value: 'Free 3-month agent + 10% recurring affiliate commission. Pitch: "Deploy AI agents in 5 min — no DevOps."' },
{ label: 'Site Status', value: 'derez.ai live. Prelaunch. 89 CRM contacts (59 YT creators on Hold).' },
{ label: 'Timezone', value: 'America/Asuncion (PYST, UTC-3/UTC-4). Daily brief 09:00.' },
];
/* ── Filtered comms — spam/sales/ads/work-for-you removed ── */
function isSpam(email) {
const lower = (email.subj + ' ' + email.from + ' ' + (email.detail || '')).toLowerCase();
const spamPatterns = [
'spam', 'advertisement', 'advert', 'work for you', 'work from home',
'make money', 'earn', 'investment opportunity', 'click here',
'buy now', 'limited offer', 'discount', 'free money', 'congratulations',
'buy now', 'limited offer', 'free money', 'congratulations',
'you\'ve won', 'marketing offer', 'promotion', 'partner offer',
'guest post', 'seo services', 'link building', 'content writing services',
];
@@ -664,10 +728,10 @@
}
const rawInbox = [
{ id: 'i1', time: 'Jun 09 14:44', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error — cold email bounced', alert: true, spam: false },
{ id: 'i2', time: 'Jun 08 21:04', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error', alert: false, spam: false },
{ id: 'i3', time: 'Jun 10 08:12', from: 'seo@boostmyrank.xyz', subj: 'Guest post opportunity for your site', detail: 'Wants to publish sponsored content', spam: true },
{ id: 'i4', time: 'Jun 09 19:33', from: 'hannah@freelance.io', subj: 'I can help with your content marketing', detail: 'Offering writing services', spam: true },
{ id: 'i1', time: '14:44', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error — cold email bounced', alert: true, spam: false },
{ id: 'i2', time: '21:04', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error', alert: false, spam: false },
{ id: 'i3', time: '08:12', from: 'seo@boostmyrank.xyz', subj: 'Guest post opportunity for your site', detail: 'Wants to publish sponsored content', spam: true },
{ id: 'i4', time: '19:33', from: 'hannah@freelance.io', subj: 'I can help with your content marketing', detail: 'Offering writing services', spam: true },
];
const rawSent = [
@@ -675,29 +739,6 @@
{ time: 'Jun 08', to: 'oliver@odoo4projects.com', subj: 'managing your agents without SSH', spam: false },
];
const strategyCards = [
{
icon: '📢', title: 'Influencer Outreach',
body: 'Target 60 YouTube creators in AI/ML/DevOps. Offer free 3-month agent + 10% recurring affiliate commission. Pitch: "Deploy AI agents in 5 minutes — no DevOps needed."',
goal: 'Goal: 20 onboarded, 3+ social mentions'
},
{
icon: '👨‍👩‍👧‍👦', title: 'Cold Email',
body: 'Templates & coupons ready (friends950, creator950). Signed as Mark. All drafts reviewed via Telegram before sending.',
goal: 'Goal: 100 sent, 10+ replies'
},
{
icon: '🔗', title: 'LinkedIn Presence',
body: 'Zero presence. Need page, connections, and content strategy before outreach.',
goal: 'Goal: Page live, 100 connections'
},
{
icon: '📈', title: 'SEO & Analytics',
body: 'Plausible analytics live with 7 custom events. Weekly cron monitors insights. Need Search Console + directory listings.',
goal: 'Goal: 10K visitors/mo, top 5 for "AI agent hosting"'
}
];
const comms = {
inbox: {
total: rawInbox.filter(i => !i.spam).length,
@@ -713,16 +754,23 @@
};
/* ════════ RENDER ════════ */
function fmtDate() {
return new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
function fmtTimestamp(date) {
const d = date || new Date();
const y = d.getFullYear();
const mo = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
const h = String(d.getHours()).padStart(2, '0');
const mi = String(d.getMinutes()).padStart(2, '0');
return `${y}-${mo}-${day} ${h}:${mi}`;
}
function pct(cur, target) { return target > 0 ? Math.min(100, Math.round(cur / target * 100)) : 0; }
function barClass(p) { return p >= 80 ? 'green' : p >= 40 ? 'blue' : p >= 20 ? 'yellow' : 'red'; }
function toggleSection(id, header) {
const el = document.getElementById(id);
const toggle = header.querySelector('.section-toggle');
el.classList.toggle('hidden');
el.classList.toggle('open');
toggle.classList.toggle('collapsed');
}
@@ -752,7 +800,7 @@
}).join('');
}
/* ── Interactive checkboxes ── */
/* ── Needs (checkboxes) ── */
function getNeeds() {
try {
const saved = localStorage.getItem("derez-needs");
@@ -823,6 +871,12 @@
</div>`;
}
function renderInfos() {
document.getElementById('infos-list').innerHTML = infos.map(i =>
`<li><span class="info-label">${i.label}</span><span class="info-value">${i.value}</span></li>`
).join('');
}
async function fetchLiveData() {
try {
const res = await fetch('data/operations.json?t=' + Date.now());
@@ -836,11 +890,12 @@
}
/* ── Init ── */
document.getElementById('brief-date').textContent = fmtDate();
document.getElementById('brief-date').textContent = fmtTimestamp();
renderGoals();
renderCampaigns();
renderNeeds(getNeeds());
renderCommunications();
renderInfos();
fetchLiveData();
</script>
</body>