browtf001

Untitled

Apr 1st, 2025
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 15.14 KB | Source Code | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8" />
  5.   <meta name="viewport" content="width=device-width, initial-scale=1" />
  6.   <title>Pledge Reminder & Self-Control Tracker</title>
  7.  <style>
  8.    /* Base styles */
  9.    body {
  10.      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  11.       background: linear-gradient(135deg, #FFDEE9, #B5FFFC);
  12.       background-size: 200% 200%;
  13.       animation: backgroundShift 10s ease infinite;
  14.       color: #333;
  15.       margin: 0;
  16.       padding: 0 20px;
  17.       transition: background-color 0.3s, color 0.3s;
  18.     }
  19.     @keyframes backgroundShift {
  20.       0% { background-position: 0% 50%; }
  21.       50% { background-position: 100% 50%; }
  22.       100% { background-position: 0% 50%; }
  23.     }
  24.     header {
  25.       text-align: center;
  26.       padding: 20px 0;
  27.       background: rgba(255, 255, 255, 0.8);
  28.       box-shadow: 0 4px 8px rgba(0,0,0,0.2);
  29.       margin-bottom: 20px;
  30.       border-bottom: 4px solid #FF6F61;
  31.     }
  32.     h1 {
  33.       margin: 0;
  34.       font-size: 2.8rem;
  35.       color: #FF6F61;
  36.       text-shadow: 0 2px 5px rgba(255,111,97,0.7);
  37.       animation: pulse 1.5s ease-in-out infinite alternate;
  38.     }
  39.     @keyframes pulse {
  40.       from {
  41.         text-shadow: 0 2px 5px rgba(255,111,97,0.5);
  42.       }
  43.       to {
  44.         text-shadow: 0 2px 10px rgba(255,111,97,1);
  45.       }
  46.     }
  47.     .container {
  48.       max-width: 900px;
  49.       margin: 0 auto;
  50.       background: #fff;
  51.       padding: 20px;
  52.       border-radius: 8px;
  53.       box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  54.     }
  55.     /* Two-column layout for main sections */
  56.     .row {
  57.       display: flex;
  58.       flex-wrap: wrap;
  59.       gap: 20px;
  60.     }
  61.     .column {
  62.       flex: 1;
  63.       min-width: 280px;
  64.     }
  65.     /* Form & list styling */
  66.    form {
  67.      margin-bottom: 20px;
  68.     }
  69.     form input, form button {
  70.       padding: 10px;
  71.       margin-right: 10px;
  72.       font-size: 1rem;
  73.       border: 1px solid #ccc;
  74.       border-radius: 4px;
  75.       transition: box-shadow 0.3s, border 0.3s;
  76.     }
  77.     form input {
  78.       background: #f9f9f9;
  79.       color: #333;
  80.     }
  81.     form input::placeholder {
  82.       color: #999;
  83.     }
  84.     form button {
  85.       background-color: #FF6F61;
  86.       color: #fff;
  87.       cursor: pointer;
  88.       border: none;
  89.     }
  90.     form button:hover {
  91.       background-color: #FF5A4D;
  92.     }
  93.     .site-list {
  94.       list-style-type: none;
  95.       padding: 0;
  96.     }
  97.     .site-item {
  98.       display: flex;
  99.       align-items: center;
  100.       background: #f1f1f1;
  101.       margin-bottom: 10px;
  102.       padding: 10px;
  103.       border-radius: 4px;
  104.       box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  105.       transition: transform 0.2s, background 0.2s;
  106.     }
  107.     .site-item:hover {
  108.       transform: scale(1.02);
  109.       background: #f9f9f9;
  110.     }
  111.     .site-item img {
  112.       width: 32px;
  113.       height: 32px;
  114.       margin-right: 15px;
  115.     }
  116.     .site-details {
  117.       flex-grow: 1;
  118.     }
  119.     .site-link {
  120.       color: #FF6F61;
  121.       text-decoration: none;
  122.       font-weight: bold;
  123.     }
  124.     .site-link:hover {
  125.       text-decoration: underline;
  126.     }
  127.     .site-actions button {
  128.       padding: 5px 10px;
  129.       font-size: 0.9rem;
  130.       margin-left: 5px;
  131.       border: none;
  132.       border-radius: 4px;
  133.       cursor: pointer;
  134.       background-color: #FF6F61;
  135.       color: #fff;
  136.       transition: background-color 0.3s;
  137.     }
  138.     .site-actions button:hover {
  139.       background-color: #FF5A4D;
  140.     }
  141.     /* Dark mode styling */
  142.     .dark-mode {
  143.       background-color: #333;
  144.       color: #ddd;
  145.     }
  146.     .dark-mode header {
  147.       background: rgba(50, 50, 50, 0.9);
  148.       border-bottom: 4px solid #FF6F61;
  149.     }
  150.     .dark-mode h1 {
  151.       color: #FF6F61;
  152.     }
  153.     .dark-mode .container {
  154.       background: #444;
  155.       box-shadow: 0 4px 12px rgba(0,0,0,0.4);
  156.     }
  157.     .dark-mode form input {
  158.       background: #555;
  159.       color: #ddd;
  160.       border: 1px solid #666;
  161.     }
  162.     .dark-mode form input::placeholder {
  163.       color: #bbb;
  164.     }
  165.     .dark-mode .site-item {
  166.       background: #555;
  167.       box-shadow: 0 2px 5px rgba(0,0,0,0.3);
  168.     }
  169.     .dark-mode .site-link {
  170.       color: #FF8A80;
  171.     }
  172.     .dark-mode .site-actions button {
  173.       background-color: #FF8A80;
  174.     }
  175.     .dark-mode .site-actions button:hover {
  176.       background-color: #FF6F61;
  177.     }
  178.     .customization {
  179.       margin-top: 20px;
  180.       border-top: 1px solid #ccc;
  181.       padding-top: 20px;
  182.     }
  183.     .customization label {
  184.       margin-right: 10px;
  185.     }
  186.     .customization input, .customization select, .customization button {
  187.       padding: 8px;
  188.       margin-right: 10px;
  189.       font-size: 1rem;
  190.       border: 1px solid #ccc;
  191.       border-radius: 4px;
  192.       background: #f9f9f9;
  193.       color: #333;
  194.       transition: box-shadow 0.3s;
  195.     }
  196.     .customization button {
  197.       background-color: #FF6F61;
  198.       color: #fff;
  199.       cursor: pointer;
  200.       border: none;
  201.     }
  202.     .customization button:hover {
  203.       background-color: #FF5A4D;
  204.     }
  205.     .ranking {
  206.       margin-top: 20px;
  207.       padding: 15px;
  208.       background: #f9f9f9;
  209.       border-radius: 4px;
  210.       box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  211.     }
  212.     .ranking h2 {
  213.       margin-top: 0;
  214.       color: #FF6F61;
  215.     }
  216.   </style>
  217. </head>
  218. <body>
  219.   <header>
  220.     <h1>Pledge Reminder & Self-Control Tracker</h1>
  221.    <button id="toggle-dark-mode">Toggle Dark Mode</button>
  222.  </header>
  223.  
  224.  <div class="container">
  225.    <div class="row">
  226.      <!-- Left Column: Pledge & Form -->
  227.      <div class="column">
  228.        <!-- Pledge Reminder Message -->
  229.        <section id="pledge-message">
  230.          <p><strong>Remember your commitment!</strong> You pledged to avoid distracting sites for a set period.</p>
  231.        </section>
  232.  
  233.        <!-- Form to add a restricted site with customizable time span -->
  234.        <section id="site-input">
  235.          <form id="add-site-form">
  236.            <input type="url" id="site-url" placeholder="Enter site URL (https://example.com)" required />
  237.            <input type="number" id="duration" placeholder="Duration in hours" required min="0" step="0.1"/>
  238.            <button type="submit">Add Site</button>
  239.          </form>
  240.        </section>
  241.  
  242.        <!-- List of restricted sites -->
  243.        <section id="site-list-section">
  244.          <ul class="site-list" id="site-list"></ul>
  245.        </section>
  246.      </div>
  247.  
  248.      <!-- Right Column: Ranking & Customization -->
  249.      <div class="column">
  250.        <!-- Ranking & Encouragement -->
  251.        <section class="ranking">
  252.          <h2>Your Self-Control Rank:</h2>
  253.          <p id="rank-status">Beginner</p>
  254.          <p>Total Restricted Time Completed: <span id="total-time">0</span> seconds</p>
  255.        </section>
  256.  
  257.        <!-- Customization Options -->
  258.        <section class="customization">
  259.          <h2>Customize Your Page</h2>
  260.          <div>
  261.            <label for="bg-color">Background Color:</label>
  262.            <input type="color" id="bg-color" value="#ffffff" />
  263.          </div>
  264.          <div>
  265.            <label for="text-color">Text Color:</label>
  266.            <input type="color" id="text-color" value="#333333" />
  267.          </div>
  268.          <div>
  269.            <label for="font-select">Font Family:</label>
  270.            <select id="font-select">
  271.              <option value="'Segoe UI', Tahoma, Geneva, Verdana, sans-serif">Segoe UI</option>
  272.              <option value="Arial, sans-serif">Arial</option>
  273.              <option value="'Courier New', monospace">Courier New</option>
  274.            </select>
  275.          </div>
  276.          <button id="apply-customization">Apply Customization</button>
  277.        </section>
  278.      </div>
  279.    </div>
  280.  </div>
  281.  
  282.  <script>
  283.    // Global variables to track sites and total restricted time completed
  284.    let sites = [];
  285.     let totalRestrictedTime = 0;
  286.     let rankLevels = [
  287.       { threshold: 0, rank: "Beginner" },
  288.       { threshold: 3600, rank: "Novice" },
  289.       { threshold: 7200, rank: "Intermediate" },
  290.       { threshold: 14400, rank: "Advanced" },
  291.       { threshold: 28800, rank: "Pro" },
  292.       { threshold: 57600, rank: "Expert" },
  293.       { threshold: 115200, rank: "Master" },
  294.       { threshold: 230400, rank: "Guru" }
  295.     ];
  296.  
  297.     // DOM elements
  298.     const addSiteForm = document.getElementById("add-site-form");
  299.     const siteUrlInput = document.getElementById("site-url");
  300.     const durationInput = document.getElementById("duration");
  301.     const siteList = document.getElementById("site-list");
  302.     const rankStatus = document.getElementById("rank-status");
  303.     const totalTimeEl = document.getElementById("total-time");
  304.     const darkModeButton = document.getElementById("toggle-dark-mode");
  305.  
  306.     // Customization elements
  307.     const bgColorInput = document.getElementById("bg-color");
  308.     const textColorInput = document.getElementById("text-color");
  309.     const fontSelect = document.getElementById("font-select");
  310.     const applyCustomizationButton = document.getElementById("apply-customization");
  311.  
  312.     // Save sites and progress to Local Storage
  313.     function saveData() {
  314.       // Save only serializable properties (exclude interval)
  315.       const sitesToSave = sites.map(site => ({
  316.         id: site.id,
  317.         url: site.url,
  318.         duration: site.duration,
  319.         startTime: site.startTime
  320.       }));
  321.       localStorage.setItem("restrictedSites", JSON.stringify(sitesToSave));
  322.       localStorage.setItem("totalRestrictedTime", totalRestrictedTime);
  323.     }
  324.  
  325.     // Load sites and progress from Local Storage
  326.     function loadSites() {
  327.       const savedSites = JSON.parse(localStorage.getItem("restrictedSites")) || [];
  328.       totalRestrictedTime = parseInt(localStorage.getItem("totalRestrictedTime")) || 0;
  329.       savedSites.forEach(saved => {
  330.         // Create site object and resume its timer
  331.         const siteObj = {
  332.           id: saved.id,
  333.           url: saved.url,
  334.           duration: saved.duration,
  335.           startTime: saved.startTime,
  336.           interval: null
  337.         };
  338.         sites.push(siteObj);
  339.         renderSite(siteObj);
  340.         resumeTimer(siteObj);
  341.       });
  342.       updateRank();
  343.     }
  344.  
  345.     // When a new site is added, set the startTime and save data
  346.     addSiteForm.addEventListener("submit", function(e) {
  347.       e.preventDefault();
  348.       const url = siteUrlInput.value.trim();
  349.       const durationHours = parseFloat(durationInput.value);
  350.       const duration = Math.floor(durationHours * 3600);
  351.       if (url && duration > 0) {
  352.        addSite(url, duration);
  353.         siteUrlInput.value = "";
  354.         durationInput.value = "";
  355.       }
  356.     });
  357.  
  358.     function addSite(url, duration) {
  359.       const id = Date.now();
  360.       const siteObj = {
  361.         id,
  362.         url,
  363.         duration,
  364.         startTime: Date.now(), // Mark the time when the timer starts
  365.         interval: null
  366.       };
  367.       sites.push(siteObj);
  368.       renderSite(siteObj);
  369.       startTimer(siteObj);
  370.       saveData();
  371.     }
  372.  
  373.     // Resume a site's timer based on elapsed time
  374.     function resumeTimer(site) {
  375.       const elapsed = Math.floor((Date.now() - site.startTime) / 1000);
  376.       site.remaining = Math.max(0, site.duration - elapsed);
  377.       updateTimerDisplay(site.id, site.remaining);
  378.       if (site.remaining > 0) {
  379.         startTimer(site);
  380.       } else {
  381.         // If timer is already up, add to total restricted time
  382.         totalRestrictedTime += site.duration;
  383.         updateRank();
  384.         saveData();
  385.       }
  386.     }
  387.  
  388.     // Render a site item in the list
  389.     function renderSite(site) {
  390.       const li = document.createElement("li");
  391.       li.classList.add("site-item");
  392.       li.setAttribute("data-id", site.id);
  393.       const faviconUrl = `https://www.google.com/s2/favicons?domain=${(new URL(site.url)).hostname}`;
  394.       li.innerHTML = `
  395.         <img src="${faviconUrl}" alt="Logo">
  396.         <div class="site-details">
  397.           <a href="${site.url}" target="_blank" class="site-link">${site.url}</a>
  398.           <div class="timer" id="timer-${site.id}">${formatTime(site.duration)}</div>
  399.         </div>
  400.         <div class="site-actions">
  401.           <button onclick="removeSite(${site.id})">Remove</button>
  402.           <button onclick="visitSite('${site.url}', ${site.id})">Visit</button>
  403.         </div>
  404.       `;
  405.       siteList.appendChild(li);
  406.     }
  407.  
  408.     // Start or resume the countdown timer
  409.     function startTimer(site) {
  410.       // Initialize remaining if not already set
  411.       if (typeof site.remaining === 'undefined') {
  412.         site.remaining = site.duration;
  413.       }
  414.       site.interval = setInterval(() => {
  415.         if (site.remaining > 0) {
  416.           site.remaining--;
  417.           updateTimerDisplay(site.id, site.remaining);
  418.           saveData();
  419.         } else {
  420.           clearInterval(site.interval);
  421.           totalRestrictedTime += site.duration;
  422.           updateRank();
  423.           saveData();
  424.         }
  425.       }, 1000);
  426.     }
  427.  
  428.     function updateTimerDisplay(id, time) {
  429.       const timerEl = document.getElementById("timer-" + id);
  430.       if (timerEl) {
  431.         timerEl.textContent = formatTime(time);
  432.       }
  433.     }
  434.  
  435.     // Format seconds to hh:mm:ss
  436.     function formatTime(seconds) {
  437.       const hrs = Math.floor(seconds / 3600);
  438.       const mins = Math.floor((seconds % 3600) / 60);
  439.       const secs = seconds % 60;
  440.       return `${pad(hrs)}:${pad(mins)}:${pad(secs)}`;
  441.     }
  442.  
  443.     function pad(num) {
  444.       return num.toString().padStart(2, "0");
  445.     }
  446.  
  447.     // Remove a site and update data
  448.     function removeSite(id) {
  449.       sites = sites.filter(site => {
  450.         if (site.id === id) {
  451.           clearInterval(site.interval);
  452.           return false;
  453.         }
  454.         return true;
  455.       });
  456.       const li = document.querySelector(`.site-item[data-id="${id}"]`);
  457.       if (li) li.remove();
  458.       saveData();
  459.     }
  460.  
  461.     // Warning and redirect if timer is still active
  462.     function visitSite(url, id) {
  463.       const site = sites.find(s => s.id === id);
  464.       if (site && site.remaining > 0) {
  465.        alert(`Warning: You pledged to avoid ${url} for ${formatTime(site.duration)}. Timer remaining: ${formatTime(site.remaining)}.`);
  466.       } else {
  467.         window.open(url, "_blank");
  468.       }
  469.     }
  470.  
  471.     // Update the rank based on total restricted time completed
  472.     function updateRank() {
  473.       let currentRank = "Beginner";
  474.       for (let i = rankLevels.length - 1; i >= 0; i--) {
  475.         if (totalRestrictedTime >= rankLevels[i].threshold) {
  476.           currentRank = rankLevels[i].rank;
  477.           break;
  478.         }
  479.       }
  480.       rankStatus.textContent = currentRank;
  481.       totalTimeEl.textContent = totalRestrictedTime;
  482.     }
  483.  
  484.     // Dark mode toggle
  485.     darkModeButton.addEventListener("click", function() {
  486.       document.body.classList.toggle("dark-mode");
  487.     });
  488.  
  489.     // Customization options
  490.     applyCustomizationButton.addEventListener("click", function() {
  491.       document.body.style.backgroundColor = bgColorInput.value;
  492.       document.body.style.color = textColorInput.value;
  493.       document.body.style.fontFamily = fontSelect.value;
  494.     });
  495.  
  496.     // Expose functions to global scope for inline onclick usage
  497.     window.removeSite = removeSite;
  498.     window.visitSite = visitSite;
  499.  
  500.     // Load saved sites on page load
  501.     window.onload = loadSites;
  502.   </script>
  503. </body>
  504. </html>
  505.  
Tags: #htmlcode
Advertisement
Add Comment
Please, Sign In to add comment