Skip to content

Commit 97cb9e3

Browse files
authored
Add files via upload
1 parent cce74ed commit 97cb9e3

File tree

1 file changed

+276
-0
lines changed

1 file changed

+276
-0
lines changed

TraderJokes.html

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
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.0">
6+
<title>Trader Jokes Printer</title>
7+
<!-- Load Tailwind CSS -->
8+
<script src="https://cdn.tailwindcss.com"></script>
9+
<!-- Use Inter font family -->
10+
<style>
11+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
12+
body {
13+
font-family: 'Inter', sans-serif;
14+
@apply bg-gray-50;
15+
}
16+
/* Define a CSS variable for dynamic padding, applied by the JS sliders */
17+
#outputContent {
18+
--joke-padding: 24px; /* Default value */
19+
/* Initial font size is set here */
20+
font-size: 16pt;
21+
}
22+
23+
/* --- Print Styles (Crucial for 8.5x11 Paper) --- */
24+
@media print {
25+
/* Set the page size and default margins for the paper */
26+
@page {
27+
size: Letter; /* 8.5in x 11in */
28+
margin: 0.75in;
29+
}
30+
31+
/* Hide all UI elements except the dedicated print area */
32+
.no-print {
33+
display: none !important;
34+
}
35+
36+
/* Ensure the print area takes up the whole space */
37+
.print-area {
38+
width: 100% !important;
39+
min-height: 100vh !important;
40+
margin: 0 !important;
41+
padding: 0 !important;
42+
box-shadow: none !important;
43+
background-color: white !important;
44+
}
45+
46+
/* The core rule to prevent joke blocks from breaking mid-page */
47+
/* Use the dynamic variable for spacing */
48+
.joke-block {
49+
page-break-inside: avoid;
50+
break-inside: avoid;
51+
margin-bottom: var(--joke-padding) !important;
52+
}
53+
}
54+
</style>
55+
</head>
56+
<body class="p-4 md:p-8">
57+
58+
<div id="app" class="max-w-4xl mx-auto">
59+
60+
<!-- Header - Non-Printable -->
61+
<header class="mb-8 p-6 bg-white rounded-xl shadow-lg no-print">
62+
<h1 class="text-3xl font-bold text-gray-800 tracking-tight">Trader Jokes Print Formatter</h1>
63+
<p class="text-gray-500 mt-2">Customize the header and formatting below, then paste your joke text.</p>
64+
</header>
65+
66+
<!-- Input and Control Area - Non-Printable -->
67+
<div class="space-y-6 no-print">
68+
69+
<!-- Custom Header Inputs -->
70+
<div class="bg-white p-6 rounded-xl shadow-lg grid grid-cols-1 md:grid-cols-3 gap-4">
71+
<div>
72+
<label for="customTitle" class="block text-sm font-medium text-gray-700 mb-1">Print Title (e.g., Nov Show)</label>
73+
<input type="text" id="customTitle" value="TRADER JOKES" class="w-full p-2 border border-gray-300 rounded-lg text-gray-800" />
74+
</div>
75+
<div>
76+
<label for="customDate" class="block text-sm font-medium text-gray-700 mb-1">Date</label>
77+
<!-- Date input will be set to today's date via script -->
78+
<input type="date" id="customDate" class="w-full p-2 border border-gray-300 rounded-lg text-gray-800" />
79+
</div>
80+
<div>
81+
<label for="recipientName" class="block text-sm font-medium text-gray-700 mb-1">Recipient Name (Optional)</label>
82+
<input type="text" id="recipientName" placeholder="Comedian's Name" class="w-full p-2 border border-gray-300 rounded-lg text-gray-800" />
83+
</div>
84+
</div>
85+
86+
<!-- Style Controls (Sliders) -->
87+
<div class="bg-white p-6 rounded-xl shadow-lg space-y-4">
88+
<h3 class="text-lg font-semibold text-gray-800 border-b pb-2 mb-4">Print Formatting</h3>
89+
90+
<!-- Font Size Control -->
91+
<div>
92+
<label for="fontSizeSlider" class="block text-sm font-medium text-gray-700 mb-2">Font Size: <span id="fontSizeValue">16</span>pt</label>
93+
<input type="range" id="fontSizeSlider" min="12" max="24" value="16" step="2" oninput="updatePrintStyles()" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer range-lg" />
94+
</div>
95+
96+
<!-- Padding Control (Vertical Spacing between jokes) -->
97+
<div>
98+
<label for="paddingSlider" class="block text-sm font-medium text-gray-700 mb-2">Vertical Joke Spacing: <span id="paddingValue">24</span>px</label>
99+
<input type="range" id="paddingSlider" min="12" max="60" value="24" step="6" oninput="updatePrintStyles()" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer range-lg" />
100+
</div>
101+
</div>
102+
103+
<!-- Input Textarea -->
104+
<div class="bg-white p-6 rounded-xl shadow-lg">
105+
<label for="jokeInput" class="block text-sm font-medium text-gray-700 mb-2">Paste Joke Text Here</label>
106+
<textarea id="jokeInput" rows="15" oninput="formatAndRenderPreview()" class="w-full p-4 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500 text-gray-800" placeholder="Paste all your jokes, even if they have weird spacing or formatting."></textarea>
107+
</div>
108+
109+
<!-- Action Button -->
110+
<button onclick="formatAndPrint()" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-3 px-6 rounded-xl shadow-lg transition duration-150 ease-in-out transform hover:scale-[1.01] focus:outline-none focus:ring-4 focus:ring-indigo-500 focus:ring-opacity-50">
111+
Format & Print Jokes
112+
</button>
113+
</div>
114+
115+
<!-- Print Preview Area -->
116+
<div id="print-area" class="print-area mt-10 p-8 md:p-12 bg-white rounded-xl shadow-xl transition-all duration-300">
117+
<h2 class="text-xl font-bold text-gray-500 text-center mb-6 no-print">Print Preview</h2>
118+
<div id="outputContent" class="text-gray-900 leading-relaxed">
119+
<p class="text-center italic text-gray-400 text-lg">Paste your jokes above and adjust settings to see the final, print-ready output here.</p>
120+
</div>
121+
</div>
122+
123+
</div>
124+
125+
<script>
126+
// Global references
127+
const jokeInput = document.getElementById('jokeInput');
128+
const outputContent = document.getElementById('outputContent');
129+
const customTitleInput = document.getElementById('customTitle');
130+
const customDateInput = document.getElementById('customDate');
131+
const recipientNameInput = document.getElementById('recipientName');
132+
const fontSizeSlider = document.getElementById('fontSizeSlider');
133+
const paddingSlider = document.getElementById('paddingSlider');
134+
const fontSizeValue = document.getElementById('fontSizeValue');
135+
const paddingValue = document.getElementById('paddingValue');
136+
137+
138+
/**
139+
* Updates the font size and padding styles on the output content for live preview.
140+
*/
141+
function updatePrintStyles() {
142+
const fs = fontSizeSlider.value;
143+
const padding = paddingSlider.value;
144+
145+
// Update displayed values
146+
fontSizeValue.textContent = fs;
147+
paddingValue.textContent = padding;
148+
149+
// Apply styles to the output container for live preview
150+
outputContent.style.fontSize = `${fs}pt`;
151+
outputContent.style.setProperty('--joke-padding', `${padding}px`);
152+
153+
// Re-render the jokes immediately if content exists to update joke-block margins
154+
if (jokeInput.value.trim()) {
155+
formatAndRenderPreview();
156+
}
157+
}
158+
159+
160+
/**
161+
* Formats the raw text, applies custom header fields, and renders it into the preview area.
162+
*/
163+
function formatAndRenderPreview() {
164+
const rawText = jokeInput.value.trim();
165+
let formattedHtml = '';
166+
167+
// Get custom header values
168+
const title = customTitleInput.value.trim().toUpperCase() || "TRADER JOKES";
169+
// Format the date input if it exists, otherwise use today's date
170+
let dateStr;
171+
if (customDateInput.value) {
172+
dateStr = new Date(customDateInput.value + 'T00:00:00').toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
173+
} else {
174+
dateStr = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
175+
}
176+
const recipient = recipientNameInput.value.trim();
177+
178+
179+
// Process the input text (split by two or more newlines)
180+
const jokeBlocks = rawText
181+
.replace(/\r\n/g, '\n') // Normalize CRLF to LF
182+
.split(/\n{2,}/) // Split by two or more consecutive newlines
183+
.map(block => block.trim()) // Clean up whitespace around each block
184+
.filter(block => block.length > 0); // Remove any empty blocks
185+
186+
187+
// Set the print-specific title, date, and recipient (Comedian's Name)
188+
let headerHtml = `
189+
<div class="text-center pb-4 border-b border-gray-300 joke-block" style="margin-bottom: 30px !important;">
190+
<h1 class="font-extrabold mb-1">${title}</h1>
191+
<p class="font-medium">${dateStr}</p>
192+
${recipient ? `<p class="font-semibold mt-2">${recipient}</p>` : ''}
193+
</div>
194+
`;
195+
196+
if (jokeBlocks.length > 0) {
197+
// Map each joke block to a div with the anti-break class and line breaks converted
198+
formattedHtml = jokeBlocks.map(block => `
199+
<div class="joke-block leading-relaxed">
200+
${block.replace(/\n/g, '<br>')}
201+
</div>
202+
`).join('');
203+
} else {
204+
formattedHtml = '<p class="text-center italic text-gray-400">Paste your jokes above to see the output.</p>';
205+
}
206+
207+
outputContent.innerHTML = headerHtml + formattedHtml;
208+
}
209+
210+
/**
211+
* Cleans, formats, and renders the text for print, then triggers the print dialog.
212+
*/
213+
function formatAndPrint() {
214+
if (!jokeInput.value.trim()) {
215+
// Use a custom message box instead of alert()
216+
showUserMessage("No Content", "Please paste your joke text into the box first.", "bg-yellow-500");
217+
return;
218+
}
219+
220+
// 1. Ensure latest styles and content are rendered
221+
updatePrintStyles(); // Apply dynamic styles to outputContent
222+
formatAndRenderPreview(); // Generate content based on inputs
223+
224+
// 2. Trigger Print
225+
window.print();
226+
}
227+
228+
// --- Custom Modal/Message Box (Replaces alert()) ---
229+
230+
function showUserMessage(title, message, bgColor) {
231+
const modalId = 'custom-message-modal';
232+
let modal = document.getElementById(modalId);
233+
234+
if (!modal) {
235+
modal = document.createElement('div');
236+
modal.id = modalId;
237+
modal.className = 'fixed inset-0 z-50 flex items-center justify-center bg-gray-900 bg-opacity-50 transition-opacity duration-300 opacity-0 pointer-events-none';
238+
modal.innerHTML = `
239+
<div class="bg-white rounded-xl shadow-2xl overflow-hidden w-full max-w-sm transform scale-90 transition-transform duration-300">
240+
<div id="modal-header" class="${bgColor} p-4 text-white">
241+
<h3 class="text-lg font-bold" id="modal-title"></h3>
242+
</div>
243+
<div class="p-6">
244+
<p class="text-gray-700 mb-6" id="modal-message"></p>
245+
<button onclick="document.getElementById('${modalId}').classList.add('opacity-0', 'pointer-events-none'); document.getElementById('${modalId}').classList.remove('opacity-100');"
246+
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 rounded-lg transition duration-150">
247+
OK
248+
</button>
249+
</div>
250+
</div>
251+
`;
252+
document.body.appendChild(modal);
253+
}
254+
255+
// Update content and show
256+
document.getElementById('modal-title').textContent = title;
257+
document.getElementById('modal-message').textContent = message;
258+
document.getElementById('modal-header').className = `${bgColor} p-4 text-white`;
259+
260+
// Use requestAnimationFrame to ensure CSS transition works
261+
requestAnimationFrame(() => {
262+
modal.classList.remove('opacity-0', 'pointer-events-none');
263+
modal.classList.add('opacity-100');
264+
});
265+
}
266+
267+
// Initialize styles and date on load
268+
window.onload = () => {
269+
updatePrintStyles();
270+
// Set the default date to today
271+
customDateInput.valueAsDate = new Date();
272+
formatAndRenderPreview(); // Initial render of the header
273+
};
274+
</script>
275+
</body>
276+
</html>

0 commit comments

Comments
 (0)