Files
anwar-pi-website/articles.html
ahmed 9cfffa4c66
Deploy GitHub Pages / deploy (push) Canceled after 0s
Build searchable article library
2026-10-03 02:37:44 +03:00

309 lines
23 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="referrer" content="strict-origin-when-cross-origin" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-src 'none'; worker-src 'none'" />
<meta name="description" content="جميع مقالات وأدلة أنور بي آي، مع تصفية حسب الفئة ونوع الوصول." />
<title>المكتبة — أنور بي آي</title>
<style>
:root {
--bg: oklch(16% 0.03 225);
--surface: oklch(22% 0.04 220);
--fg: oklch(96% 0.015 210);
--muted: oklch(74% 0.03 215);
--border: oklch(36% 0.05 215);
--accent: oklch(78% 0.17 190);
--accent-soft: color-mix(in oklch, var(--accent) 14%, transparent);
--fg-soft: color-mix(in oklch, var(--fg) 6%, transparent);
--font-display: "SF Arabic", "Noto Sans Arabic", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-body: "SF Arabic", "Noto Sans Arabic", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
--container: 1180px;
--gutter: 32px;
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--bg); color: var(--fg); font: 16px/1.7 var(--font-body); text-rendering: optimizeLegibility; }
a { color: inherit; text-decoration: none; }
button { color: inherit; font: inherit; cursor: pointer; }
h1, h2, h3 { margin: 0; font-family: var(--font-display); text-wrap: balance; }
p { text-wrap: pretty; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }
.topnav { position: sticky; top: 0; z-index: 20; background: color-mix(in oklch, var(--bg) 92%, transparent); backdrop-filter: blur(14px); border-bottom: 1px solid var(--border); }
.topnav-inner { min-height: 70px; display: flex; align-items: center; justify-content: space-between; gap: 28px; }
.logo { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; font-size: 23px; font-weight: 700; }
.logo-mark { width: 30px; height: 34px; object-fit: contain; border-radius: 4px; }
.topnav nav { display: flex; align-items: center; gap: 28px; }
.topnav nav a { min-height: 44px; display: inline-flex; align-items: center; color: var(--muted); border-bottom: 1px solid transparent; }
.topnav nav a:hover, .topnav nav a[aria-current="page"] { color: var(--fg); border-color: var(--accent); }
.nav-action { min-height: 44px; display: inline-flex; align-items: center; padding-inline: 16px; border: 1px solid var(--border); }
.nav-action:hover { border-color: var(--fg); background: var(--fg-soft); }
.hero { padding-block: clamp(56px, 8vw, 96px); border-bottom: 1px solid var(--border); }
.hero-grid { display: grid; grid-template-columns: minmax(0, .9fr) minmax(360px, 1.1fr); gap: clamp(36px, 7vw, 88px); align-items: end; }
.eyebrow { margin: 0 0 18px; color: var(--accent); font: 11px/1.5 var(--font-mono); letter-spacing: .06em; }
h1 { max-width: 10ch; font-size: clamp(48px, 7vw, 88px); line-height: 1.06; letter-spacing: -.025em; }
.lead { max-width: 56ch; margin: 24px 0 0; color: var(--muted); font-size: clamp(18px, 2vw, 22px); }
.weekly { display: block; padding: clamp(24px, 4vw, 40px); background: var(--surface); border: 1px solid var(--border); border-top-color: var(--accent); }
.weekly:hover { border-color: var(--fg); background: color-mix(in oklch, var(--surface) 88%, var(--fg)); }
.weekly-meta { display: flex; justify-content: space-between; gap: 16px; color: var(--muted); font: 11px/1.5 var(--font-mono); }
.weekly h2 { margin-top: 42px; font-size: clamp(28px, 4vw, 44px); line-height: 1.18; }
.weekly p { margin: 14px 0 30px; color: var(--muted); }
.weekly-link { min-height: 44px; display: inline-flex; align-items: center; font-weight: 700; border-bottom: 1px solid var(--fg); }
.library { padding-block: clamp(52px, 8vw, 88px); }
.library-tools { display: grid; grid-template-columns: minmax(0, 1fr) 240px; gap: 16px; margin-bottom: 22px; }
.control { width: 100%; min-height: 48px; padding: 11px 14px; border: 1px solid var(--border); background: var(--surface); color: var(--fg); font: inherit; }
.control::placeholder { color: var(--muted); }
.control:hover { border-color: var(--fg); }
.control:focus { outline: 3px solid var(--accent-soft); border-color: var(--accent); }
.filter-panel { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; margin-bottom: 44px; padding-block: 22px; border-block: 1px solid var(--border); }
.filter-group { min-width: 0; }
.filter-label { display: block; margin-bottom: 10px; color: var(--muted); font: 11px/1.5 var(--font-mono); }
.filters { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 3px; scrollbar-width: none; }
.filters::-webkit-scrollbar { display: none; }
.filter { flex: none; min-height: 44px; padding: 9px 15px; border: 1px solid var(--border); background: transparent; color: var(--muted); }
.filter:hover { color: var(--fg); border-color: var(--fg); }
.filter[aria-pressed="true"] { background: var(--fg); color: var(--surface); border-color: var(--fg); }
.results-head { display: flex; align-items: end; justify-content: space-between; gap: 20px; margin-bottom: 24px; }
h2 { font-size: clamp(30px, 4vw, 46px); line-height: 1.15; }
.count { color: var(--muted); font: 12px/1.5 var(--font-mono); }
.posts { border-top: 1px solid var(--fg); }
.post { display: grid; grid-template-columns: 138px minmax(0, 1fr) 168px; gap: 28px; align-items: start; padding-block: 28px; border-bottom: 1px solid var(--border); }
.post[hidden] { display: none; }
.post-meta { color: var(--muted); font: 12px/1.8 var(--font-mono); }
.post-meta span { display: block; }
.post h3 { font-size: clamp(22px, 2.5vw, 30px); line-height: 1.3; }
.post p { max-width: 62ch; margin: 9px 0 0; color: var(--muted); }
.post-side { justify-self: stretch; display: grid; gap: 12px; }
.access { justify-self: end; display: inline-flex; align-items: center; min-height: 34px; padding: 5px 11px; border: 1px solid var(--border); color: var(--muted); font: 11px/1.5 var(--font-mono); }
.access.free { border-color: var(--fg); color: var(--fg); }
.engagement { display: flex; justify-content: flex-end; gap: 12px; color: var(--muted); font: 11px/1.5 var(--font-mono); }
.like { min-height: 44px; padding: 0 10px; border: 1px solid transparent; background: transparent; color: var(--muted); }
.like:hover, .like[aria-pressed="true"] { color: var(--fg); border-color: var(--border); }
.post-link { display: inline-flex; align-items: center; min-height: 44px; margin-top: 14px; font-weight: 700; border-bottom: 1px solid transparent; }
.post-link:hover { color: var(--accent); border-color: var(--accent); }
.soon { color: var(--muted); cursor: default; }
.empty { display: none; padding: 42px 0; color: var(--muted); }
.empty.show { display: block; }
.pagefoot { padding-block: 48px; border-top: 1px solid var(--border); color: var(--muted); font-size: 13px; }
.footer-row { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
@media (max-width: 920px) {
:root { --gutter: 22px; }
.topnav-inner { flex-wrap: wrap; gap: 0 16px; padding-top: 10px; }
.logo, .nav-action { margin-bottom: 10px; }
.topnav nav { order: 3; flex: 0 0 calc(100% + (var(--gutter) * 2)); gap: 6px; margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); overflow-x: auto; border-top: 1px solid var(--border); scrollbar-width: none; }
.topnav nav::-webkit-scrollbar { display: none; }
.topnav nav a { flex: none; min-height: 52px; padding-inline: 12px; white-space: nowrap; }
.hero-grid, .filter-panel { grid-template-columns: 1fr; gap: 20px; }
.weekly { margin-top: 8px; }
.post { grid-template-columns: 112px minmax(0, 1fr); }
.post-side { justify-self: start; grid-column: 2; }
.access { justify-self: start; }
.engagement { justify-content: flex-start; }
}
@media (max-width: 620px) {
:root { --gutter: 18px; }
.nav-action { padding-inline: 12px; }
h1 { font-size: clamp(42px, 13vw, 58px); }
.library-tools { grid-template-columns: 1fr; }
.results-head { align-items: start; flex-direction: column; }
.post { grid-template-columns: 1fr; gap: 12px; }
.post-side { grid-column: 1; }
.post-link { width: 100%; border-top: 1px solid var(--border); padding-top: 12px; }
}
@media (prefers-reduced-motion: reduce) {
* { scroll-behavior: auto !important; transition-duration: .01ms !important; }
}
</style>
<link rel="stylesheet" href="assets/anwarpi.css?v=5" />
<script src="assets/anwarpi.js?v=4" defer></script>
</head>
<body>
<header class="topnav" data-od-id="topnav">
<div class="container topnav-inner">
<a class="logo" href="arabic-ai-learning-catalog-v2.html" data-od-id="brand"><img class="logo-mark" src="assets/anwarpi-logo.jpg" alt="" width="1200" height="1352" />أنور بي آي</a>
<nav aria-label="التنقل الرئيسي">
<a href="articles.html" aria-current="page" data-od-id="nav-library">المكتبة</a>
<a href="arabic-ai-learning-catalog-v2.html#topics">المسارات</a>
<a href="subscription.html">العضوية</a>
<a href="about.html">عن الفريق</a>
</nav>
<a class="nav-action" href="login.html">تسجيل الدخول</a>
</div>
</header>
<main id="content">
<section class="hero" data-od-id="library-hero">
<div class="container hero-grid">
<div>
<p class="eyebrow">مكتبة أنور بي آي</p>
<h1 data-od-id="library-title">كل المقالات. بلا ضياع.</h1>
<p class="lead">ابحث، اختر مسارك، ورتّب النتائج حسب الأحدث أو التفاعل المسجل على جهازك.</p>
</div>
<a class="weekly" href="article-agent-guide.html" data-od-id="weekly-post">
<div class="weekly-meta"><span>مقال هذا الأسبوع</span><span>مجاني · ١٢ دقيقة</span></div>
<h2>لا تبدأ باسم النموذج؛ ابدأ بطبيعة المهمة</h2>
<p>مصفوفة قرار عملية توازن بين الدقة، السياق، السرعة، والكلفة.</p>
<span class="weekly-link">اقرأ المقال ←</span>
</a>
</div>
</section>
<section class="library" data-od-id="article-library">
<div class="container">
<div class="library-tools" data-od-id="library-search-sort">
<label><span class="filter-label">ابحث في العناوين والوصف</span><input class="control" id="postSearch" type="search" autocomplete="off" placeholder="مثال: الوكلاء، RAG، اختيار النموذج" /></label>
<label><span class="filter-label">الترتيب</span><select class="control" id="postSort"><option value="latest">الأحدث أولاً</option><option value="views">الأكثر مشاهدة على هذا الجهاز</option><option value="likes">الأكثر إعجاباً على هذا الجهاز</option></select></label>
</div>
<div class="filter-panel" data-od-id="library-filters">
<div class="filter-group" role="group" aria-label="تصفية حسب المسار">
<span class="filter-label">المسار / الفئة</span>
<div class="filters">
<button class="filter" type="button" data-filter-kind="topic" data-filter-value="all" aria-pressed="true">الكل</button>
<button class="filter" type="button" data-filter-kind="topic" data-filter-value="agents" aria-pressed="false">الوكلاء</button>
<button class="filter" type="button" data-filter-kind="topic" data-filter-value="models" aria-pressed="false">النماذج</button>
<button class="filter" type="button" data-filter-kind="topic" data-filter-value="automation" aria-pressed="false">الأتمتة</button>
<button class="filter" type="button" data-filter-kind="topic" data-filter-value="foundations" aria-pressed="false">الأساسيات</button>
</div>
</div>
<div class="filter-group" role="group" aria-label="تصفية حسب نوع الوصول">
<span class="filter-label">نوع الوصول</span>
<div class="filters">
<button class="filter" type="button" data-filter-kind="access" data-filter-value="all" aria-pressed="true">الكل</button>
<button class="filter" type="button" data-filter-kind="access" data-filter-value="free" aria-pressed="false">مجاني</button>
<button class="filter" type="button" data-filter-kind="access" data-filter-value="vip" aria-pressed="false">VIP</button>
</div>
</div>
</div>
<div class="results-head">
<h2 data-od-id="posts-heading">جميع المواد</h2>
<span class="count" id="resultCount" aria-live="polite">٦ مواد</span>
</div>
<div class="posts" id="postList">
<article class="post" data-topic="agents" data-access="vip" data-order="6" data-id="agent-loop" data-od-id="post-agent-loop">
<div class="post-meta"><span>الوكلاء</span><span>١٨ دقيقة</span></div>
<div><h3>البنية التي تمنع وكيلك من الدوران في حلقة</h3><p>حدود واضحة بين التخطيط والتنفيذ والتحقق، مع نموذج بسيط لسجل الحالة.</p><a class="post-link" href="post-locked.html">شاهد المعاينة ←</a></div>
<div class="post-side"><span class="access">VIP · معاينة</span><div class="engagement"><span data-views>٠ مشاهدة</span><button class="like" type="button" data-like aria-pressed="false">إعجاب · <span>٠</span></button></div></div>
</article>
<article class="post" data-topic="models" data-access="free" data-order="5" data-id="model-selection" data-od-id="post-model-selection">
<div class="post-meta"><span>النماذج</span><span>١٢ دقيقة</span></div>
<div><h3>لا تبدأ باسم النموذج؛ ابدأ بطبيعة المهمة</h3><p>مصفوفة قرار عملية توازن بين الدقة، السياق، السرعة، والكلفة.</p><a class="post-link" href="article-agent-guide.html">ابدأ القراءة ←</a></div>
<div class="post-side"><span class="access free">مجاني · كامل</span><div class="engagement"><span data-views>٠ مشاهدة</span><button class="like" type="button" data-like aria-pressed="false">إعجاب · <span>٠</span></button></div></div>
</article>
<article class="post" data-topic="automation" data-access="vip" data-order="4" data-id="automation-observability" data-od-id="post-automation-observability">
<div class="post-meta"><span>الأتمتة</span><span>٢٤ دقيقة</span></div>
<div><h3>كيف تكتشف فشل سير العمل قبل المستخدم؟</h3><p>إشارات قليلة تكفي لمراقبة التكلفة، التأخير، ونقاط الانقطاع.</p><span class="post-link soon" aria-label="هذه المادة ستتوفر قريباً">قريباً</span></div>
<div class="post-side"><span class="access">VIP</span><div class="engagement"><span data-views>٠ مشاهدة</span><button class="like" type="button" data-like aria-pressed="false">إعجاب · <span>٠</span></button></div></div>
</article>
<article class="post" data-topic="foundations" data-access="free" data-order="3" data-id="prompt-context" data-od-id="post-prompt-context">
<div class="post-meta"><span>الأساسيات</span><span>٩ دقائق</span></div>
<div><h3>لماذا لا يصلح تحسين الصياغة بياناتك الرديئة؟</h3><p>افصل بين التعليمات، المعرفة، وذاكرة المحادثة لتحصل على نتيجة مستقرة.</p><span class="post-link soon" aria-label="هذه المادة ستتوفر قريباً">قريباً</span></div>
<div class="post-side"><span class="access free">مجاني</span><div class="engagement"><span data-views>٠ مشاهدة</span><button class="like" type="button" data-like aria-pressed="false">إعجاب · <span>٠</span></button></div></div>
</article>
<article class="post" data-topic="agents" data-access="vip" data-order="2" data-id="tool-safety" data-od-id="post-tool-safety">
<div class="post-meta"><span>الوكلاء</span><span>١٥ دقيقة</span></div>
<div><h3>قبل أن تمنح الوكيل صلاحية التنفيذ</h3><p>حدود الصلاحيات، التأكيد البشري، وسجل تدقيق يمكنك الرجوع إليه.</p><span class="post-link soon" aria-label="هذه المادة ستتوفر قريباً">قريباً</span></div>
<div class="post-side"><span class="access">VIP</span><div class="engagement"><span data-views>٠ مشاهدة</span><button class="like" type="button" data-like aria-pressed="false">إعجاب · <span>٠</span></button></div></div>
</article>
<article class="post" data-topic="models" data-access="vip" data-order="1" data-id="rag-evaluation" data-od-id="post-rag-evaluation">
<div class="post-meta"><span>النماذج</span><span>٤ أجزاء</span></div>
<div><h3>اختبر الاسترجاع والإجابة كلّاً على حدة</h3><p>منهج تقييم يفصل فشل المصدر عن فشل النموذج ويقودك إلى إصلاح صحيح.</p><span class="post-link soon" aria-label="هذه المادة ستتوفر قريباً">قريباً</span></div>
<div class="post-side"><span class="access">VIP</span><div class="engagement"><span data-views>٠ مشاهدة</span><button class="like" type="button" data-like aria-pressed="false">إعجاب · <span>٠</span></button></div></div>
</article>
</div>
<p class="empty" id="emptyState">لا توجد مواد تطابق البحث والفلاتر الحالية.</p>
</div>
</section>
</main>
<footer class="pagefoot" data-od-id="footer">
<div class="container footer-row"><span>© أنور بي آي ٢٠٢٦ · تعلّم بوضوح</span><a href="privacy.html">الخصوصية</a></div>
</footer>
<script>
(() => {
const params = new URLSearchParams(location.search);
const allowedTopics = ['all', 'agents', 'models', 'automation', 'foundations'];
const state = { topic: allowedTopics.includes(params.get('topic')) ? params.get('topic') : 'all', access: 'all', query: '', sort: 'latest' };
const buttons = [...document.querySelectorAll('[data-filter-kind]')];
const posts = [...document.querySelectorAll('.post')];
const list = document.getElementById('postList');
const count = document.getElementById('resultCount');
const empty = document.getElementById('emptyState');
const search = document.getElementById('postSearch');
const sort = document.getElementById('postSort');
const formatNumber = value => new Intl.NumberFormat('ar').format(value);
const readMetric = (post, metric) => Number(localStorage.getItem(`anwarpi:${metric}:${post.dataset.id}`) || 0);
function normalize(value) {
return value.toLocaleLowerCase('ar').normalize('NFKD').replace(/[\u064B-\u065F\u0670]/g, '').replace(/[إأآ]/g, 'ا').replace(/ى/g, 'ي');
}
function paintMetrics(post) {
const views = readMetric(post, 'views');
const liked = localStorage.getItem(`anwarpi:liked:${post.dataset.id}`) === '1';
post.querySelector('[data-views]').textContent = `${formatNumber(views)} مشاهدة`;
const like = post.querySelector('[data-like]');
like.setAttribute('aria-pressed', String(liked));
like.querySelector('span').textContent = formatNumber(liked ? 1 : 0);
}
function applyFilters() {
const ordered = [...posts].sort((a, b) => {
if (state.sort === 'views') return readMetric(b, 'views') - readMetric(a, 'views') || Number(b.dataset.order) - Number(a.dataset.order);
if (state.sort === 'likes') return Number(localStorage.getItem(`anwarpi:liked:${b.dataset.id}`) === '1') - Number(localStorage.getItem(`anwarpi:liked:${a.dataset.id}`) === '1') || Number(b.dataset.order) - Number(a.dataset.order);
return Number(b.dataset.order) - Number(a.dataset.order);
});
ordered.forEach(post => list.appendChild(post));
let visible = 0;
posts.forEach(post => {
const topicMatch = state.topic === 'all' || post.dataset.topic === state.topic;
const accessMatch = state.access === 'all' || post.dataset.access === state.access;
const queryMatch = !state.query || normalize(post.textContent).includes(normalize(state.query));
post.hidden = !(topicMatch && accessMatch && queryMatch);
if (!post.hidden) visible += 1;
});
count.textContent = `${formatNumber(visible)} ${visible === 1 ? 'مادة' : 'مواد'}`;
empty.classList.toggle('show', visible === 0);
}
buttons.forEach(button => button.addEventListener('click', () => {
const kind = button.dataset.filterKind;
state[kind] = button.dataset.filterValue;
buttons.filter(item => item.dataset.filterKind === kind).forEach(item => {
item.setAttribute('aria-pressed', String(item === button));
});
applyFilters();
}));
search.addEventListener('input', () => { state.query = search.value.trim(); applyFilters(); });
sort.addEventListener('change', () => { state.sort = sort.value; applyFilters(); });
posts.forEach(post => {
paintMetrics(post);
post.querySelector('[data-like]').addEventListener('click', () => {
const key = `anwarpi:liked:${post.dataset.id}`;
localStorage.setItem(key, localStorage.getItem(key) === '1' ? '0' : '1');
paintMetrics(post);
applyFilters();
});
post.querySelectorAll('a.post-link').forEach(link => link.addEventListener('click', () => {
localStorage.setItem(`anwarpi:views:${post.dataset.id}`, String(readMetric(post, 'views') + 1));
}));
});
buttons.filter(button => button.dataset.filterKind === 'topic').forEach(button => button.setAttribute('aria-pressed', String(button.dataset.filterValue === state.topic)));
applyFilters();
})();
</script>
</body>
</html>