Skip to content

Cannot save fiddle #2360

@boogli-moogly

Description

@boogli-moogly

Error code

ERRW:0.85:K1.0:SL0.1:PU0.05:AS

Were you logged in?

Yes

Your username (if logged in)

KanYe_West

Your HTML

<link rel="icon" type="image/png" href="favicon.jpg">
  <link rel="stylesheet" href="style.css">

  <header>
    <div class="header-left">
      <img src="favicon.jpg" alt="favicon" class="header-favicon">
      <span class="header-title">Two Sentence Horrors</span>
    </div>
    <div class="header-center">
      <span class="creator">made for <a href="https://www.tiktok.com/@jarrett_warlick" class="header-link"
          target="_blank">@Jarrett_Warlick</a></span>
      <button class="info-btn" id="infoBtn" aria-label="Information">about</button>
      <a href="/projects" class="info-btn" aria-label="More Games">more games</a>
      <div class="share-container">
        <button class="info-btn" id="shareBtn" aria-label="Share">share</button>
        <div id="copyToast" class="copy-toast">Copied!</div>
      </div>
    </div>
    <div class="header-right">
      <span class="creator">by <a href="/" target="_blank">fish-eater</a></span>
      <button class="donate-btn" onclick="window.open('https://buymeacoffee.com/wyattkarnes', '_blank')">Donate</button>
    </div>
  </header>
  <main>
    <div class="main-layout">
      <!-- About Panel -->
      <div class="about-panel" id="aboutPanel">
        <div class="about-content">
          <button class="panel-close" id="closePanel">&times;</button>
          <h3>about this game</h3>
          <p>try to guess the horror story from the first sentence</p>
          <p>this site was made for my friend, Jarrett, for his tiktok page</p>
          <p><strong><a href="https://git.disroot.org/fisheater/2sentenceexplorer">Source Code</a></strong></p>
          <p>any questions or if you want me to make you something:</p>
          <p><strong>Contact:</strong> <a href="mailto:wyattekarnes@gmail.com">wyattekarnes@gmail.com</a></p>
        </div>
      </div>

      <!-- Content Column -->
      <div class="content-column">
        <!-- Game Container -->
        <div class="game-container">
          <div class="story" id="story"><span class="loading">loading horror...</span></div>
          <div class="selectors">
            <select id="subreddit">
              <option value="TwoSentenceHorror">r/TwoSentenceHorror</option>
              <option value="badtwosentencehorrors">r/badtwosentencehorrors</option>
            </select>
            <select id="sort">
              <option value="year">popular (recent)</option>
              <option value="all">popular (all time)</option>
              <option value="random">random</option>
            </select>
            <button id="reload">more</button>
          </div>
        </div>

        <!-- Comments Card -->
        <div id="commentsOverlay" class="comments-card">
          <iframe src="/creation/comments?url=2sentenceexplorer" class="comments-iframe" id="commentsIframe"></iframe>
        </div>
      </div>
    </div>
  </main>
  <button id="showCommentsBtn" class="comments-trigger">show comments</button>
  <script src="script.js"></script>

Your JavaScript

const CORS_PROXY = "https://cors.eu.org/";
// if cors.eu.org is down:
// https://cors.io/?u=
// https://corsproxy.io/?url=

const POST_LIMIT = 600;
let stories = [], index = 0, lastSub = "", lastSort = "";

const shuffle = arr => {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
};

async function getStories(sub, sort) {
  const base = `https://www.reddit.com/r/${sub}/`;
  let url = (sort === "all" || sort === "year")
    ? `${base}top.json?t=${sort}&limit=${POST_LIMIT}`
    : `${base}new.json?limit=${POST_LIMIT}`;
  const resp = await fetch(CORS_PROXY + encodeURIComponent(url));
  if (!resp.ok) throw new Error("Fetch error or CORS fail");
  const data = await resp.json();
  return data.data.children.filter(p =>
    !p.data.stickied && !p.data.over_18 &&
    p.data.selftext && p.data.selftext !== '[removed]' && p.data.selftext !== '[deleted]'
  ).map(p => ({
    title: p.data.title,
    text: p.data.selftext.trim(),
    score: p.data.score
  }));
}

function renderStory(story) {
  const censoredText = story.text.replace(/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu, ' ');

  document.getElementById("story").innerHTML =
    `<span class="first-sentence">${story.title}</span>
     <span class="censor-block" id="hiddenSentence" title="reveal">
       <mark class="censor-highlight">${censoredText}</mark>
     </span>
     <span class="upvotes">${story.score.toLocaleString()} upvotes</span>`;
  const el = document.getElementById("hiddenSentence");
  const mark = el.querySelector('.censor-highlight');
  let isRevealed = false;

  el.addEventListener('click', function () {
    if (isRevealed) {
      mark.textContent = censoredText;
      mark.style.background = '#101010';
      mark.style.color = '#101010';
      el.setAttribute("title", "reveal");
    } else {
      mark.textContent = story.text;
      mark.style.background = 'transparent';
      mark.style.color = '#181818';
      el.removeAttribute("title");
    }
    isRevealed = !isRevealed;
  });
}

async function loadStoriesAndShow(resetIdx = true) {
  const sub = document.getElementById("subreddit").value;
  const sort = document.getElementById("sort").value;
  document.getElementById("story").innerHTML = '<span class="loading">loading horror...</span>';
  try {
    // fetch if options changed or none loaded yet
    if (sub !== lastSub || sort !== lastSort || !stories.length) {
      stories = shuffle(await getStories(sub, sort));
      lastSub = sub; lastSort = sort;
      if (resetIdx) index = 0;
    }
    if (!stories.length) throw new Error("No stories found.");
    renderStory(stories[index]);
  } catch (e) {
    document.getElementById("story").innerHTML =
      `<span class="loading">failed to load: ${e.message}</span>`;
  }
}

function nextStory() {
  if (!stories.length) { loadStoriesAndShow(); return; }
  index = (index + 1) % stories.length;
  renderStory(stories[index]);
}

document.getElementById("reload").onclick = nextStory;
document.getElementById("subreddit").onchange = () => loadStoriesAndShow();
document.getElementById("sort").onchange = () => loadStoriesAndShow();

window.onload = () => loadStoriesAndShow();

// about panel functionality
const infoBtn = document.getElementById('infoBtn');
const aboutPanel = document.getElementById('aboutPanel');
const closePanel = document.getElementById('closePanel');

function togglePanel(e) {
  if (e) e.stopPropagation();
  if (aboutPanel) {
    aboutPanel.classList.toggle('closed');
  }
}

if (infoBtn) {
  infoBtn.addEventListener('click', togglePanel);
}

if (closePanel) {
  closePanel.addEventListener('click', togglePanel);
}

// close panel with Escape key
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape' && aboutPanel && !aboutPanel.classList.contains('closed')) {
    aboutPanel.classList.add('closed');
  }
});

// share button functionality
const shareBtn = document.getElementById("shareBtn");
const copyToast = document.getElementById("copyToast");
if (shareBtn && copyToast) {
  shareBtn.addEventListener("click", () => {
    navigator.clipboard.writeText(window.location.href).then(() => {
      copyToast.classList.add("show");
      setTimeout(() => {
        copyToast.classList.remove("show");
      }, 2000);
    }).catch(err => {
      console.error("Failed to copy: ", err);
    });
  });
}

// clicking the favicon 5 times disables the background (easter egg)
let clickCount = 0;
let backgroundEnabled = false; // Disabled by default as requested

const headerFavicon = document.querySelector('.header-favicon');

if (headerFavicon) {
  headerFavicon.addEventListener('click', (e) => {
    e.preventDefault();
    clickCount++;
    console.log(`Favicon clicked! Count: ${clickCount}`);

    // toggle background on 5th click
    if (clickCount === 5) {
      backgroundEnabled = !backgroundEnabled;
      const container = document.querySelector('.game-container'); // Updated selector

      if (backgroundEnabled) {
        // Show background
        if (container) container.classList.add('has-background');
        console.log('Background enabled');
      } else {
        // Hide background
        if (container) container.classList.remove('has-background');
        console.log('Background disabled');
      }

      clickCount = 0;
    }
  });
}


// Comments overlay functionality
const showCommentsBtn = document.getElementById('showCommentsBtn');
const commentsOverlay = document.getElementById('commentsOverlay');
const commentsIframe = document.getElementById('commentsIframe');
let commentCount = 0;

async function fetchCommentCount() {
  try {
    const response = await fetch('/creation/comment_count.py?page=2sentenceexplorer');
    if (response.ok) {
      const data = await response.json();
      commentCount = data.count || 0;
      updateButtonText();
    }
  } catch (error) {
    console.error('Failed to fetch comment count:', error);
  }
}

function updateButtonText() {
  if (!showCommentsBtn) return;
  const countText = commentCount > 0 ? ` (${commentCount})` : '';
  if (commentsOverlay.classList.contains('open')) {
    showCommentsBtn.textContent = `hide comments${countText}`;
  } else {
    showCommentsBtn.textContent = `show comments${countText}`;
  }
}

if (showCommentsBtn && commentsOverlay) {
  showCommentsBtn.addEventListener('click', () => {
    commentsOverlay.classList.toggle('open');
    updateButtonText();
  });

  // Fetch count on load
  fetchCommentCount();

  // Dark scrollbar for iframe
  if (commentsIframe) {
    commentsIframe.onload = () => {
      try {
        const doc = commentsIframe.contentDocument;
        if (doc) {
          const style = doc.createElement('style');
          style.textContent = `
            body { color-scheme: dark; }
            ::-webkit-scrollbar { width: 12px; }
            ::-webkit-scrollbar-track { background: #191919; }
            ::-webkit-scrollbar-thumb { background: #444; border-radius: 6px; border: 3px solid #191919; }
            ::-webkit-scrollbar-thumb:hover { background: #555; }
            * { scrollbar-color: #444 #191919; }
          `;
          doc.head.appendChild(style);
        }
      } catch (e) {
        console.warn("Cannot style iframe scrollbar (cross-origin?)");
      }
    };
  }
}

Your CSS

body {
  background: #fff;
  font-family: Georgia, serif;
  display: flex;
  flex-direction: column;
  margin: 0;
  min-height: 100vh;
  overflow-x: hidden;
  position: relative;
}

@keyframes moveDiagonal {
  from {
    background-position: 0 0;
  }

  to {
    background-position: 422px 140px;
  }
}

header {
  width: 100%;
  padding: 0.6em;
  background: #191919;
  color: #fff;
  font-size: 1.1em;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  position: sticky;
  top: 0;
  z-index: 10;
  box-shadow: 0 1.5px 6px #ccc;
  box-sizing: border-box;
  gap: 1em;
}

.header-left,
.header-right {
  flex: 1;
  display: flex;
  align-items: center;
  min-width: fit-content;
}

.header-right {
  justify-content: flex-end;
}

.header-favicon {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: 4px;
  cursor: pointer;
  transition: transform 0.3s;
  padding-right: 10px;
}

.header-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header-center {
  display: flex;
  align-items: center;
  gap: 1.5em;
  justify-content: center;
}

.header-link {
  text-decoration: none;
  font-size: 0.9em;
  white-space: nowrap;
  transition: opacity 0.2s;
}

.header-link:hover {
  opacity: 0.8;
}

.info-btn {
  background: transparent;
  border: 1.5px solid #fff;
  color: #fff;
  border-radius: 5px;
  font-size: 0.75em;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 7px 18px;
  transition: background 0.2s, transform 0.15s;
  font-weight: bold;
  line-height: 1;
}

.info-btn:hover {
  background: rgba(255, 255, 255, 0.2);
  transform: scale(1.1);
}

.share-container {
  position: relative;
  display: flex;
  align-items: center;
}

.copy-toast {
  position: absolute;
  top: 110%;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  padding: 4px 10px;
  border-radius: 4px;
  font-size: 0.7em;
  font-family: sans-serif;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s;
  white-space: nowrap;
  z-index: 100;
}

.copy-toast.show {
  opacity: 1;
}

/* Layout */
.main-layout {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 20px;
  width: 100%;
  max-width: 1200px;
  padding: 0 16px;
  box-sizing: border-box;
  margin-top: 1.6em;
  transition: all 0.3s ease;
}

.about-panel {
  width: 300px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 2px 12px 3px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  opacity: 1;
  transform: translateX(0);
  margin-right: 0;
  height: fit-content;
  position: relative;
  flex-shrink: 0;
}

.about-panel.closed {
  width: 0;
  opacity: 0;
  margin-right: -20px;
  /* Compensate for grid gap */
  padding: 0;
  transform: translateX(-20px);
  pointer-events: none;
}

.about-content {
  padding: 24px;
  width: 300px;
  /* Force width to prevent reflow */
  box-sizing: border-box;
}

.about-content h3 {
  margin: 0 0 1em;
  color: #191919;
  font-size: 1.2em;
}

.about-content p {
  margin: 0.8em 0;
  line-height: 1.5;
  color: #333;
  font-size: 0.95em;
}

.about-content a {
  color: #191919;
  text-decoration: underline;
  font-weight: 600;
}

.panel-close {
  position: absolute;
  top: 10px;
  right: 10px;
  background: transparent;
  border: none;
  font-size: 1.8em;
  color: #999;
  cursor: pointer;
  line-height: 1;
  padding: 0;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s;
}

.panel-close:hover {
  color: #333;
}

/* Header Right Styles */
.header-right {
  display: flex;
  align-items: center;
  gap: 0.8em;
  flex-shrink: 0;
}

header .creator {
  font-size: 0.85em;
  font-style: italic;
  white-space: nowrap;
  flex-shrink: 0;
}

.donate-btn {
  font-size: 0.85em;
  padding: 5px 12px;
  background: #fff;
  color: #191919;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.2s, transform 0.15s;
  font-family: Georgia, serif;
  font-weight: 600;
  white-space: nowrap;
}

.donate-btn:hover {
  background: #f0f0f0;
  transform: scale(1.05);
}

.donate-btn:active {
  background: #e0e0e0;
}

main {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}

.game-container {
  width: 100%;
  text-align: center;
  border-radius: 12px;
  box-shadow: 0 2px 12px 3px rgba(0, 0, 0, 0.15);
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.8);
  padding: 26px 16px 20px 16px;
  transition: all 0.3s ease;
}

.game-container::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('graphic.png');
  background-repeat: repeat;
  background-size: 422px 140px;
  animation: moveDiagonal 30s linear infinite;
  opacity: 0.2;
  z-index: 0;
  pointer-events: none;
  display: none;
}

.game-container>* {
  position: relative;
  z-index: 1;
}

.game-container.has-background::before {
  display: block;
}

.story {
  font-size: 1.2em;
  line-height: 1.55;
  color: #181818;
  margin-bottom: 3px;
  word-break: break-word;
}

.first-sentence {
  font-weight: 500;
  display: block;
  margin-bottom: 7px;
}

.censor-block {
  font-style: italic;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  display: inline;
}

.censor-highlight {
  background: #101010;
  color: #101010;
  border-radius: 3px;
  padding: 2px 4px;
  transition: background 0.15s, color 0.15s;
  display: inline;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

.upvotes {
  display: block;
  font-size: 14px;
  color: #6c6c4e;
  font-style: italic;
  margin-top: 7px;
  margin-bottom: 1px;
  letter-spacing: 0.1em;
}

.loading {
  font-size: 18px;
  color: #999;
  margin: 1em 0;
}

.selectors {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 15px;
  flex-wrap: wrap;
}

select,
button {
  font-family: inherit;
  padding: 7px 9px;
  font-size: 15px;
  border-radius: 4px;
  border: 1.3px solid #aaa;
  background: #fcfcfc;
  margin-bottom: 0;
}

button {
  font-size: 16px;
  border: none;
  background: #191919;
  color: #fff;
  border-radius: 5px;
  cursor: pointer;
  margin-left: 12px;
  font-family: Georgia, serif;
  transition: background 0.18s, transform 0.15s;
  padding: 7px 18px;
  display: inline-block;
}

button:hover {
  transform: scale(1.06);
}

button:active {
  background: #444;
}

a {
  color: #777;
  text-decoration: none;
  transition: transform 0.15s;
  display: inline-block;
}

a:hover {
  transform: scale(1.05);
}

@media (max-width: 900px) {
  .main-layout {
    flex-direction: column;
    align-items: center;
  }

  .about-panel {
    width: 100%;
    max-width: 700px;
    margin-right: 0;
    margin-bottom: 20px;
  }

  .about-panel.closed {
    margin-bottom: -300px;
    margin-right: 0;
    transform: translateY(-20px);
    opacity: 0;
  }

  .about-content {
    width: 100%;
  }
}

@media (max-width: 500px) {

  .header-left,
  .header-right,
  .header-center {
    flex: 1 1 100%;
    justify-content: center;
    text-align: center;
  }

  header .creator {
    font-size: 0.75em;
  }

  .donate-btn {
    font-size: 0.75em;
    padding: 4px 10px;
  }

  .header-favicon {
    width: 24px;
    height: 24px;
  }

  .header-title {
    font-size: 0.9em;
  }
}

/* Content Column for stacking game and comments */
.content-column {
  flex: 1;
  max-width: 1000px;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.game-container {
  width: 100%;
  max-width: 700px;
  text-align: center;
  border-radius: 12px;
  box-shadow: 0 2px 12px 3px rgba(0, 0, 0, 0.15);
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.8);
  padding: 26px 16px 20px 16px;
  transition: all 0.3s ease;
}

/* Comments Section Styles */
.comments-trigger {
  position: fixed;
  bottom: 20px;
  left: 20px;
  z-index: 100;
  margin: 0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.comments-card {
  width: 100%;
  height: 0;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
  overflow: hidden;
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  flex-direction: column;
  opacity: 0;
  pointer-events: none;
  margin-top: 0;
  border: 8px solid #191919;
  box-sizing: border-box;
}

.comments-card.open {
  height: 600px;
  opacity: 1;
  pointer-events: all;
  margin-top: 20px;
}

.comments-iframe {
  flex: 1;
  border: none;
  width: 100%;
  height: 100%;
  color-scheme: dark;
}

@media (max-width: 500px) {
  .comments-card.open {
    height: 600px;
    /* Keep height consistent or auto? */
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions