File size: 6,296 Bytes
fb8c550
 
 
527a85d
fb8c550
 
 
349f22c
6c03381
fb8c550
 
 
 
 
349f22c
fb8c550
 
 
 
 
 
 
 
 
 
527a85d
fb8c550
 
 
 
 
 
0e1d7f2
fb8c550
 
527a85d
 
 
fb8c550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
906f65b
fb8c550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6fdc858
fb8c550
 
 
 
 
 
 
 
906f65b
fb8c550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
'use client';

import Link from 'next/link';
import { MagnifyingGlass as Search, Dna, SquaresFour as Layout, Stack as Layers, GitFork, Globe, GitBranch, ShareNetwork as Share2, TestTube as FlaskConical, Flask as Beaker, BookOpen, ArrowRight, Brain, LinkSimple as LinkIcon, Atom, Pill as Pills } from '@phosphor-icons/react';
import { motion } from 'framer-motion';
import { fadeUp, stagger, cardHover } from '@/lib/animations';
import { useState } from 'react';
import type { Icon } from '@phosphor-icons/react';
import { PageHeader } from '@/components/ui';

type Topic = {
  id: string;
  title: string;
  description: string;
  icon: Icon;
};

const groups: { title: string; items: Topic[] }[] = [
  {
    title: 'Sequence Analysis',
    items: [
      { id: 'blast',     title: 'BLAST Search',            description: 'Find similar sequences and understand E-values, bit scores, and identity.',   icon: Search },
      { id: 'alignment', title: 'Sequence Alignment',      description: 'Pairwise and multiple alignment — scoring matrices, gap penalties, and output.', icon: Layout },
      { id: 'domains',   title: 'Domain Analysis',         description: 'Protein domains, Pfam, InterPro, and domain architecture.',                     icon: Layers },
      { id: 'phylo',     title: 'Phylogenetic Trees',      description: 'Tree-building methods, bootstrap values, and branch lengths.',                  icon: GitFork },
      { id: 'sequencing', title: 'Sequencing',              description: 'Sanger and NGS reads, quality scores, assembly, and variant calling.',           icon: Dna },
    ],
  },
  {
    title: 'Structure & Networks',
    items: [
      { id: 'structure',   title: 'Protein Structure',     description: 'PDB format, AlphaFold, pLDDT scores, and structure visualization.',            icon: Dna },
      { id: 'function',    title: 'Function Prediction',   description: 'GO terms, Gene Ontology namespaces, EC numbers, and DeepFRI-style prediction.',  icon: Brain },
      { id: 'pathways',    title: 'Pathway Analysis',      description: 'Reactome vs KEGG, pathway mapping, and enrichment analysis.',                  icon: GitBranch },
      { id: 'interactions', title: 'Protein Interactions', description: 'STRING database, interaction networks, and confidence scores.',                icon: Globe },
      { id: 'docking',     title: 'Molecular Docking',     description: 'Binding poses, scoring functions, and interaction fingerprints.',              icon: LinkIcon },
      { id: 'md',          title: 'Molecular Dynamics',    description: 'Force fields, trajectories, RMSD/RMSF, and simulation protocols.',              icon: Atom },
      { id: 'admet',       title: 'ADMET Prediction',      description: 'Lipinski rules, solubility, metabolism, and drug-likeness filters.',           icon: Pills },
    ],
  },
  {
    title: 'Utilities',
    items: [
      { id: 'primers', title: 'Primer Design',        description: 'PCR basics, Primer3, melting temperature, and GC content.',           icon: FlaskConical },
      { id: 'tools',   title: 'Format Converter',     description: 'Sequence format conversion and validation utilities.',                 icon: Beaker },
      { id: 'glossary', title: 'Glossary',            description: 'A–Z of bioinformatics terms with plain-English definitions.',          icon: BookOpen },
    ],
  },
];

function TopicCard({ topic }: { topic: Topic }) {
  const Icon = topic.icon;
  return (
    <motion.div variants={fadeUp} whileHover={cardHover}>
      <Link
        href={`/learn/${topic.id}`}
        className="relative block p-5 rounded-2xl glass-card hover:bg-surface-1 transition h-full"
      >
        <div className="flex items-start gap-4">
          <div className="p-3 rounded-xl bg-accent-cyan/10 flex-shrink-0">
            <Icon className="w-5 h-5 text-accent-cyan" />
          </div>
          <div className="flex-1 min-w-0">
            <h3 className="font-semibold text-text-primary">{topic.title}</h3>
            <p className="text-sm text-text-muted mt-1 leading-relaxed">{topic.description}</p>
            <div className="flex items-center gap-1 mt-3 text-xs text-accent-cyan font-medium">
              Learn more <ArrowRight className="w-3 h-3" />
            </div>
          </div>
        </div>
      </Link>
    </motion.div>
  );
}

export default function LearnPage() {
  const [query, setQuery] = useState('');

  const filtered = query.trim()
    ? groups.map(g => ({
        ...g,
        items: g.items.filter(t =>
          t.title.toLowerCase().includes(query.toLowerCase()) ||
          t.description.toLowerCase().includes(query.toLowerCase())
        ),
      })).filter(g => g.items.length > 0)
    : groups;

  return (
    <div>
      <PageHeader title="Documentation & Learning" subtitle="Learn the concepts behind every tool in Synteny." />

      <motion.div variants={fadeUp} className="relative mb-10 max-w-xl">
        <Search className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-text-muted" />
        <input
          type="text"
          value={query}
          onChange={e => setQuery(e.target.value)}
          placeholder="Search topics..."
          className="w-full pl-11 pr-4 py-3 rounded-2xl border border-glass-border bg-surface-1 text-text-primary text-sm placeholder:text-text-muted/50 outline-none focus:border-accent-cyan/30 transition"
        />
      </motion.div>

      {filtered.map(group => (
        <div key={group.title} className="mb-10">
          <motion.h2 variants={fadeUp} className="text-sm font-semibold text-text-muted uppercase tracking-wider mb-4">
            {group.title}
          </motion.h2>
          <motion.div
            variants={stagger}
            initial="hidden"
            whileInView="show"
            viewport={{ once: true, margin: '-40px' }}
            className="grid md:grid-cols-2 gap-4"
          >
            {group.items.map(topic => (
              <TopicCard key={topic.id} topic={topic} />
            ))}
          </motion.div>
        </div>
      ))}

      {filtered.length === 0 && (
        <motion.p variants={fadeUp} className="text-text-muted text-sm text-center py-12">
          No topics found for &ldquo;{query}&rdquo;.
        </motion.p>
      )}
    </div>
  );
}