|
17 | 17 | height: 100vh;
|
18 | 18 | transition: background 0.5s ease-in-out;
|
19 | 19 | }
|
| 20 | + |
| 21 | + .header { |
| 22 | + display: flex; |
| 23 | + justify-content: space-between; |
| 24 | + padding: 18px 20px; |
| 25 | + } |
| 26 | + |
| 27 | + .left-controls, .right-controls { |
| 28 | + display: flex; |
| 29 | + gap: 20px; |
| 30 | + } |
| 31 | + |
| 32 | + .main-content { |
| 33 | + flex: 1; |
| 34 | + display: flex; |
| 35 | + justify-content: center; |
| 36 | + align-items: center; |
| 37 | + } |
| 38 | + |
20 | 39 | textarea {
|
21 | 40 | width: 65vw;
|
22 | 41 | height: 65vh;
|
|
32 | 51 | text-align: left;
|
33 | 52 | vertical-align: top;
|
34 | 53 | }
|
| 54 | + |
| 55 | + .icon { |
| 56 | + cursor: pointer; |
| 57 | + opacity: 0.5; |
| 58 | + transition: opacity 0.3s, color 0.3s; |
| 59 | + font-size: 14px; |
| 60 | + color: #e0e0e0; |
| 61 | + } |
| 62 | + |
| 63 | + .icon:hover { |
| 64 | + opacity: 1; |
| 65 | + color: #e0e0e0; |
| 66 | + } |
35 | 67 | </style>
|
36 | 68 | </head>
|
37 | 69 | <body>
|
38 |
| - <textarea id="editor" placeholder="Start writing..."></textarea> |
| 70 | + <div class="header"> |
| 71 | + <div class="left-controls"> |
| 72 | + <span id="downloadButton" class="icon">Download</span> |
| 73 | + </div> |
| 74 | + </div> |
| 75 | + |
| 76 | + <div class="main-content"> |
| 77 | + <textarea id="editor" placeholder="Start writing..."></textarea> |
| 78 | + </div> |
39 | 79 |
|
40 | 80 | <script>
|
| 81 | + // DOM Elements |
41 | 82 | const textarea = document.getElementById("editor");
|
| 83 | + const icons = document.querySelectorAll(".icon"); |
| 84 | + const downloadButton = document.getElementById("downloadButton"); |
42 | 85 |
|
43 |
| - // Load saved text from localStorage |
44 |
| - textarea.value = localStorage.getItem("shiroSavedText") || ""; |
| 86 | + // State Variables |
| 87 | + let buttonsHidden = false; |
45 | 88 |
|
46 |
| - // Save text to localStorage on input |
47 |
| - textarea.addEventListener("input", () => { |
| 89 | + // Utility Functions |
| 90 | + const saveText = () => { |
48 | 91 | localStorage.setItem("shiroSavedText", textarea.value);
|
49 |
| - }); |
| 92 | + }; |
| 93 | + |
| 94 | + const loadText = () => { |
| 95 | + textarea.value = localStorage.getItem("shiroSavedText") || ""; |
| 96 | + }; |
| 97 | + |
| 98 | + const hideIcons = () => { |
| 99 | + icons.forEach(icon => icon.style.opacity = "0"); |
| 100 | + buttonsHidden = true; |
| 101 | + }; |
| 102 | + |
| 103 | + const showIcons = () => { |
| 104 | + icons.forEach(icon => icon.style.opacity = "0.5"); |
| 105 | + buttonsHidden = false; |
| 106 | + }; |
| 107 | + |
| 108 | + const generateFilename = () => { |
| 109 | + const now = new Date(); |
| 110 | + const year = now.getFullYear(); |
| 111 | + const month = (now.getMonth() + 1).toString().padStart(2, "0"); // Months are 0-based |
| 112 | + const day = now.getDate().toString().padStart(2, "0"); |
| 113 | + const hours = now.getHours().toString().padStart(2, "0"); |
| 114 | + const minutes = now.getMinutes().toString().padStart(2, "0"); |
| 115 | + |
| 116 | + return `shiro_${year}-${month}-${day}_${hours}-${minutes}.txt`; |
| 117 | + }; |
| 118 | + |
| 119 | + const downloadText = () => { |
| 120 | + const filename = generateFilename(); |
| 121 | + const blob = new Blob([textarea.value], { type: "text/plain" }); |
| 122 | + const a = Object.assign(document.createElement("a"), { |
| 123 | + href: URL.createObjectURL(blob), |
| 124 | + download: filename |
| 125 | + }); |
| 126 | + a.click(); |
| 127 | + URL.revokeObjectURL(a.href); |
| 128 | + }; |
| 129 | + |
| 130 | + // Event Handlers |
| 131 | + const setupEventListeners = () => { |
| 132 | + // Text area events |
| 133 | + textarea.addEventListener("input", () => { |
| 134 | + saveText(); |
| 135 | + hideIcons(); |
| 136 | + }); |
| 137 | + |
| 138 | + // Document events |
| 139 | + document.addEventListener("mousemove", () => { |
| 140 | + if (buttonsHidden) { |
| 141 | + showIcons(); |
| 142 | + } |
| 143 | + }); |
| 144 | + |
| 145 | + // Button events |
| 146 | + downloadButton.addEventListener("click", downloadText); |
| 147 | + |
| 148 | + // Icon hover effects |
| 149 | + icons.forEach(icon => { |
| 150 | + icon.addEventListener("mouseenter", () => icon.style.opacity = "1"); |
| 151 | + icon.addEventListener("mouseleave", () => icon.style.opacity = buttonsHidden ? "0" : "0.5"); |
| 152 | + }); |
| 153 | + }; |
| 154 | + |
| 155 | + const initialize = () => { |
| 156 | + loadText(); |
| 157 | + setupEventListeners(); |
| 158 | + textarea.focus(); // Focus on editor on load |
| 159 | + }; |
| 160 | + |
| 161 | + // Start the application |
| 162 | + window.onload = initialize; |
50 | 163 | </script>
|
51 | 164 | </body>
|
52 | 165 | </html>
|
0 commit comments