← Back Home
Quote generator
Posted by: Brian
PHP

1781532156_quotegenerator.php



<?php
// quote_generator.php — TenaCode Short Project

$quotes = [
  ["text" => "The only way to do great work is to love what you do.", "author" => "Steve Jobs"],
  ["text" => "In the middle of every difficulty lies opportunity.", "author" => "Albert Einstein"],
  ["text" => "It does not matter how slowly you go as long as you do not stop.", "author" => "Confucius"],
  ["text" => "Code is like humor. When you have to explain it, it's bad.", "author" => "Cory House"],
  ["text" => "First, solve the problem. Then, write the code.", "author" => "John Johnson"],
  ["text" => "Experience is the name everyone gives to their mistakes.", "author" => "Oscar Wilde"],
  ["text" => "Programs must be written for people to read, and only incidentally for machines to execute.", "author" => "Harold Abelson"],
  ["text" => "Simplicity is the soul of efficiency.", "author" => "Austin Freeman"],
  ["text" => "The best error message is the one that never shows up.", "author" => "Thomas Fuchs"],
  ["text" => "Make it work, make it right, make it fast.", "author" => "Kent Beck"],
  ["text" => "Any fool can write code that a computer can understand. Good programmers write code that humans can understand.", "author" => "Martin Fowler"],
  ["text" => "Talk is cheap. Show me the code.", "author" => "Linus Torvalds"],
  ["text" => "The greatest glory in living lies not in never falling, but in rising every time we fall.", "author" => "Nelson Mandela"],
  ["text" => "The future belongs to those who believe in the beauty of their dreams.", "author" => "Eleanor Roosevelt"],
  ["text" => "It is during our darkest moments that we must focus to see the light.", "author" => "Aristotle"],
  ["text" => "Debugging is twice as hard as writing the code in the first place.", "author" => "Brian Kernighan"],
  ["text" => "Before software can be reusable it first has to be usable.", "author" => "Ralph Johnson"],
  ["text" => "There are only two kinds of languages: the ones people complain about and the ones nobody uses.", "author" => "Bjarne Stroustrup"],
  ["text" => "Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away.", "author" => "Antoine de Saint-Exupéry"],
  ["text" => "The best time to plant a tree was 20 years ago. The second best time is now.", "author" => "Chinese Proverb"],
];

$categories = ['all', 'dev', 'life'];
$cat = $_GET['cat'] ?? 'all';

$dev_authors = ['Cory House','John Johnson','Harold Abelson','Thomas Fuchs','Kent Beck','Martin Fowler','Linus Torvalds','Brian Kernighan','Ralph Johnson','Bjarne Stroustrup'];

if ($cat === 'dev') {
    $pool = array_filter($quotes, fn($q) => in_array($q['author'], $dev_authors));
    $pool = array_values($pool);
} elseif ($cat === 'life') {
    $pool = array_filter($quotes, fn($q) => !in_array($q['author'], $dev_authors));
    $pool = array_values($pool);
} else {
    $pool = $quotes;
}

$idx   = array_rand($pool);
$quote = $pool[$idx];
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Random Quote Generator — TenaCode</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Mono:wght@300;400;500&display=swap" rel="stylesheet">
<style>
  :root {
    --bg:        #080808;
    --surface:   #111114;
    --border:    #1e1e24;
    --accent:    #47fff6;
    --accent2:   #ff4d6d;
    --text:      #e8e8f0;
    --muted:     #6b6b7e;
    --font-sans: 'Syne', sans-serif;
    --font-mono: 'DM Mono', monospace;
    --radius:    14px;
  }

  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

  body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-sans);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 60px 20px 80px;
  }

  /* ── Background glow ── */
  body::before {
    content: '';
    position: fixed;
    top: -200px; left: 50%;
    transform: translateX(-50%);
    width: 600px; height: 400px;
    background: radial-gradient(ellipse, rgba(71,255,246,.06) 0%, transparent 70%);
    pointer-events: none;
  }

  /* ── Header ── */
  .page-header {
    text-align: center;
    margin-bottom: 48px;
    animation: fadeUp .5s ease both;
  }
  .page-header .eyebrow {
    font-family: var(--font-mono);
    font-size: .7rem;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 12px;
  }
  .page-header h1 {
    font-size: clamp(2rem, 5vw, 3.2rem);
    font-weight: 800;
    line-height: 1.1;
    background: linear-gradient(135deg, var(--text) 40%, var(--accent));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
  }

  /* ── Filter tabs ── */
  .tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 36px;
    animation: fadeUp .5s .05s ease both;
  }
  .tabs a {
    font-family: var(--font-mono);
    font-size: .75rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: 7px 18px;
    border-radius: 999px;
    border: 1px solid var(--border);
    color: var(--muted);
    text-decoration: none;
    transition: border-color .2s, color .2s, background .2s;
  }
  .tabs a:hover { color: var(--text); border-color: var(--muted); }
  .tabs a.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #080808;
    font-weight: 600;
  }

  /* ── Quote card ── */
  .quote-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 48px 40px;
    width: 100%;
    max-width: 620px;
    position: relative;
    animation: fadeUp .5s .1s ease both;
  }
  .quote-card::before {
    content: '\201C';
    position: absolute;
    top: 16px; left: 28px;
    font-size: 5rem;
    line-height: 1;
    color: var(--accent);
    opacity: .25;
    font-family: Georgia, serif;
  }

  .quote-text {
    font-size: clamp(1.1rem, 2.5vw, 1.45rem);
    font-weight: 600;
    line-height: 1.6;
    color: var(--text);
    margin-bottom: 28px;
    position: relative;
    z-index: 1;
  }

  .quote-author {
    font-family: var(--font-mono);
    font-size: .82rem;
    color: var(--accent);
    letter-spacing: .06em;
  }
  .quote-author::before { content: '— '; }

  /* ── Actions ── */
  .card-actions {
    display: flex;
    gap: 12px;
    margin-top: 32px;
    flex-wrap: wrap;
  }
  .btn {
    padding: 12px 24px;
    background: var(--accent);
    color: #080808;
    font-family: var(--font-sans);
    font-weight: 700;
    font-size: .88rem;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    text-decoration: none;
    transition: opacity .2s, transform .15s;
    display: inline-block;
  }
  .btn:hover { opacity: .88; transform: translateY(-1px); }
  .btn-ghost {
    padding: 12px 24px;
    background: transparent;
    color: var(--muted);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: .88rem;
    cursor: pointer;
    text-decoration: none;
    transition: color .2s, border-color .2s;
    display: inline-block;
  }
  .btn-ghost:hover { color: var(--text); border-color: var(--muted); }

  /* ── Counter chip ── */
  .pool-count {
    text-align: center;
    margin-top: 20px;
    font-family: var(--font-mono);
    font-size: .72rem;
    color: var(--muted);
    animation: fadeUp .4s .25s ease both;
  }

  /* ── Toast ── */
  #toast {
    position: fixed;
    bottom: 32px; left: 50%;
    transform: translateX(-50%) translateY(20px);
    background: var(--accent);
    color: #080808;
    font-family: var(--font-mono);
    font-size: .8rem;
    font-weight: 500;
    padding: 10px 22px;
    border-radius: 999px;
    opacity: 0;
    transition: opacity .3s, transform .3s;
    pointer-events: none;
  }
  #toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

  @keyframes fadeUp {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: translateY(0); }
  }

  footer {
    margin-top: 56px;
    font-family: var(--font-mono);
    font-size: .72rem;
    color: var(--muted);
    text-align: center;
  }
  footer a { color: var(--accent); text-decoration: none; }
</style>
</head>
<body>

<header class="page-header">
  <div class="eyebrow">TenaCode · Mini Projects</div>
  <h1>Random Quote Generator</h1>
</header>

<nav class="tabs">
  <a href="?cat=all"  class="<?= $cat === 'all'  ? 'active' : '' ?>">All</a>
  <a href="?cat=dev"  class="<?= $cat === 'dev'  ? 'active' : '' ?>">Dev</a>
  <a href="?cat=life" class="<?= $cat === 'life' ? 'active' : '' ?>">Life</a>
</nav>

<div class="quote-card" id="quoteCard">
  <p class="quote-text" id="quoteText"><?= htmlspecialchars($quote['text']) ?></p>
  <span class="quote-author" id="quoteAuthor"><?= htmlspecialchars($quote['author']) ?></span>

  <div class="card-actions">
    <a class="btn" href="?cat=<?= htmlspecialchars($cat) ?>">New Quote</a>
    <button class="btn-ghost" onclick="copyQuote()">⎘ Copy</button>
    <a class="btn-ghost" href="https://twitter.com/intent/tweet?text=<?= urlencode('"'.$quote['text'].'" — '.$quote['author']) ?>" target="_blank" rel="noopener">Share ↗</a>
  </div>
</div>

<p class="pool-count"><?= count($pool) ?> quote<?= count($pool) !== 1 ? 's' : '' ?> in pool</p>

<div id="toast">Copied to clipboard!</div>

<script>
function copyQuote() {
  const text = `"<?= addslashes($quote['text']) ?>" — <?= addslashes($quote['author']) ?>`;
  navigator.clipboard.writeText(text).then(() => {
    const t = document.getElementById('toast');
    t.classList.add('show');
    setTimeout(() => t.classList.remove('show'), 2200);
  });
}
</script>

<footer>
  <a href="index.php">← Back to TenaCode</a> &nbsp;·&nbsp; Mini Projects Series
</footer>

</body>
</html>

Preview

Comments