Skip to content

Commit c8c4622

Browse files
committed
content(series): harley quinn
1 parent c62bbd5 commit c8c4622

File tree

4 files changed

+145
-66
lines changed

4 files changed

+145
-66
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Harley Quinn (TV Series)
2+
3+
- **Category:** Series
4+
- **Creator:** Justin Halpern, Patrick Schumacker, Dean Lorey
5+
- **Date:** 2025-12-25
6+
- **Rating:** 3/5
7+
- **Link:** [IMDb - Harley Quinn](https://www.imdb.com/title/tt7658402/)
8+
9+
## About
10+
11+
**Harley Quinn (2019)** is an American adult animated superhero comedy television series based on the DC Comics character of the same name. Developed by Justin Halpern, Patrick Schumacker, and Dean Lorey, the series follows the misadventures of Harley Quinn after she finally breaks up with the Joker and attempts to strike out on her own. With the help of Poison Ivy and a diverse crew of DC outcasts, Harley aims to become a member of the Legion of Doom and establish herself as a formidable villain in Gotham City.
12+
13+
The series is widely praised for its sharp, irreverent humor, meta-commentary on the superhero genre, and its surprisingly deep exploration of Harley's growth and her relationships, particularly her bond with Poison Ivy. Featuring a stellar voice cast led by Kaley Cuoco, *Harley Quinn* offers a fresh, vibrant, and R-rated take on the DC Universe, blending chaotic action with genuine heart and character-driven storytelling.

public/logs/series/series.piml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
(logs)
2+
> (item)
3+
(category) Series
4+
(creator) Justin Halpern, Patrick Schumacker, Dean Lorey
5+
(date) 2025-12-25
6+
(link) https://www.imdb.com/title/tt7658402/
7+
(platform) Max
8+
(rating) 3
9+
(slug) harley-quinn-tv-series
10+
(title) Harley Quinn (TV Series)
11+
(description) Harley Quinn (2019) is an adult animated superhero comedy series. It follows Harley Quinn's adventures after she breaks up with the Joker and attempts to join the Legion of Doom with the help of Poison Ivy and a ragtag crew of DC outcasts. Known for its dark humor, meta-commentary, and strong character development.
12+
213
> (item)
314
(category) Series
415
(date) 2025-12-25

src/components/BrutalistDialog.jsx

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const BrutalistDialog = ({
77
isOpen,
88
onClose,
99
onConfirm,
10+
children,
1011
title = 'SYSTEM_CONFIRMATION',
1112
message = 'Are you sure you want to execute this operation?',
1213
confirmText = 'CONFIRM_ACTION',
@@ -57,27 +58,33 @@ const BrutalistDialog = ({
5758
</button>
5859
</div>
5960

60-
<div className="space-y-2">
61-
<div className="h-px w-12 bg-emerald-500" />
62-
<p className="text-gray-400 font-mono text-xs uppercase tracking-widest leading-relaxed">
63-
{message}
64-
</p>
65-
</div>
61+
{children ? (
62+
<div className="relative z-10">{children}</div>
63+
) : (
64+
<>
65+
<div className="space-y-2">
66+
<div className="h-px w-12 bg-emerald-500" />
67+
<p className="text-gray-400 font-mono text-xs uppercase tracking-widest leading-relaxed">
68+
{message}
69+
</p>
70+
</div>
6671

67-
<div className="flex flex-col sm:flex-row gap-4 pt-4">
68-
<button
69-
onClick={onConfirm}
70-
className="flex-1 py-4 bg-white text-black font-black uppercase tracking-[0.3em] hover:bg-emerald-400 transition-all text-xs"
71-
>
72-
{confirmText}
73-
</button>
74-
<button
75-
onClick={onClose}
76-
className="flex-1 py-4 border border-white/10 text-gray-500 hover:text-white hover:bg-white/5 transition-all font-mono text-[10px] uppercase tracking-widest"
77-
>
78-
{cancelText}
79-
</button>
80-
</div>
72+
<div className="flex flex-col sm:flex-row gap-4 pt-4">
73+
<button
74+
onClick={onConfirm}
75+
className="flex-1 py-4 bg-white text-black font-black uppercase tracking-[0.3em] hover:bg-emerald-400 transition-all text-xs"
76+
>
77+
{confirmText}
78+
</button>
79+
<button
80+
onClick={onClose}
81+
className="flex-1 py-4 border border-white/10 text-gray-500 hover:text-white hover:bg-white/5 transition-all font-mono text-[10px] uppercase tracking-widest"
82+
>
83+
{cancelText}
84+
</button>
85+
</div>
86+
</>
87+
)}
8188
</div>
8289
</motion.div>
8390
</div>

src/pages/apps/MagazinerPage.jsx

Lines changed: 94 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const MagazinerPage = () => {
9292
const [inputs, setInputs] = useState(initialInputs);
9393
const [isSaveDialogOpen, setIsSaveDialogOpen] = useState(false);
9494
const [isLoadDialogOpen, setIsLoadDialogOpen] = useState(false);
95+
const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);
9596
const [stickyPreview, setStickyPreview] = useState(true);
9697

9798
const handleSavePreset = () => {
@@ -178,7 +179,7 @@ const MagazinerPage = () => {
178179
}
179180
};
180181

181-
const drawMagazine = useCallback((ctx, width, height) => {
182+
const drawMagazine = useCallback((ctx, width, height, options = { includeText: true, includeBgImage: true }) => {
182183
const scale = width / 1000;
183184
const rng = (s) => {
184185
let v = s * 12345.678;
@@ -193,7 +194,7 @@ const MagazinerPage = () => {
193194
ctx.fillStyle = primaryColor.hex;
194195
ctx.fillRect(0, 0, width, height);
195196

196-
if (bgImage) {
197+
if (bgImage && options.includeBgImage) {
197198
const imgRatio = bgImage.width / bgImage.height;
198199
const canvasRatio = width / height;
199200
let dWidth, dHeight, dx, dy;
@@ -374,33 +375,35 @@ const MagazinerPage = () => {
374375
ctx.restore();
375376

376377
// 4. Typography
377-
ctx.fillStyle = accentColor.hex;
378-
ctx.textBaseline = 'middle';
379-
380-
Object.entries(inputs).forEach(([key, config]) => {
381-
ctx.save();
382-
ctx.font = `${style === 'brutalist' ? 'bold' : ''} ${config.size * scale}px "${config.font}"`;
383-
384-
const x = (config.x / 100) * width;
385-
const y = (config.y / 100) * height;
386-
387-
if (key === 'rightEdgeText') {
388-
ctx.translate(x, y);
389-
ctx.rotate(Math.PI / 2);
390-
ctx.textAlign = 'center';
391-
ctx.fillText(config.text.toUpperCase(), 0, 0);
392-
} else if (key === 'title' || key === 'subtitle' || key === 'bottomText') {
393-
ctx.textAlign = 'center';
394-
ctx.fillText(config.text.toUpperCase(), x, y);
395-
} else if (key === 'secondStory' || key === 'secondStorySub') {
396-
ctx.textAlign = 'right';
397-
ctx.fillText(config.text.toUpperCase(), x, y);
398-
} else {
399-
ctx.textAlign = 'left';
400-
ctx.fillText(config.text.toUpperCase(), x, y);
401-
}
402-
ctx.restore();
403-
});
378+
if (options.includeText) {
379+
ctx.fillStyle = accentColor.hex;
380+
ctx.textBaseline = 'middle';
381+
382+
Object.entries(inputs).forEach(([key, config]) => {
383+
ctx.save();
384+
ctx.font = `${style === 'brutalist' ? 'bold' : ''} ${config.size * scale}px "${config.font}"`;
385+
386+
const x = (config.x / 100) * width;
387+
const y = (config.y / 100) * height;
388+
389+
if (key === 'rightEdgeText') {
390+
ctx.translate(x, y);
391+
ctx.rotate(Math.PI / 2);
392+
ctx.textAlign = 'center';
393+
ctx.fillText(config.text.toUpperCase(), 0, 0);
394+
} else if (key === 'title' || key === 'subtitle' || key === 'bottomText') {
395+
ctx.textAlign = 'center';
396+
ctx.fillText(config.text.toUpperCase(), x, y);
397+
} else if (key === 'secondStory' || key === 'secondStorySub') {
398+
ctx.textAlign = 'right';
399+
ctx.fillText(config.text.toUpperCase(), x, y);
400+
} else {
401+
ctx.textAlign = 'left';
402+
ctx.fillText(config.text.toUpperCase(), x, y);
403+
}
404+
ctx.restore();
405+
});
406+
}
404407

405408
// 4. Border (Frame Protocol)
406409
if (borderWidth > 0) {
@@ -448,21 +451,29 @@ const MagazinerPage = () => {
448451
drawMagazine(ctx, rect.width, rect.height);
449452
}, [drawMagazine]);
450453

451-
const handleDownload = () => {
454+
const handleDownload = (mode = 'full') => {
452455
const canvas = document.createElement('canvas');
453456
const ctx = canvas.getContext('2d');
454457
const W = 2480; // A4 at 300DPI approx
455458
const H = 3508;
456459
canvas.width = W;
457460
canvas.height = H;
458461

459-
drawMagazine(ctx, W, H);
462+
const options = {
463+
includeText: mode === 'full',
464+
includeBgImage: mode === 'full',
465+
};
466+
467+
drawMagazine(ctx, W, H, options);
460468

461469
const link = document.createElement('a');
462-
link.download = `magaziner-${Date.now()}.png`;
470+
link.download = `magaziner-${mode}-${Date.now()}.png`;
463471
link.href = canvas.toDataURL('image/png', 1.0);
464472
link.click();
465-
addToast({ title: 'EXPORT_SUCCESS', message: 'Magazine cover exported to your device.' });
473+
addToast({
474+
title: 'EXPORT_SUCCESS',
475+
message: mode === 'full' ? 'Magazine cover exported.' : 'Background template exported.'
476+
});
466477
};
467478

468479
return (
@@ -499,19 +510,56 @@ const MagazinerPage = () => {
499510
>
500511
<FloppyDiskBackIcon weight="bold" size={24} />
501512
</button>
502-
<button
503-
onClick={handleDownload}
504-
className="group relative inline-flex items-center gap-4 px-10 py-6 bg-white text-black hover:bg-emerald-400 transition-all duration-300 font-mono uppercase tracking-widest text-sm font-black rounded-sm shrink-0"
505-
>
506-
<DownloadSimpleIcon weight="bold" size={24} />
507-
<span>Export Cover</span>
508-
</button>
509-
</div>
510-
</div>
511-
</header>
512-
513-
{/* Save Confirmation Dialog */}
514-
<BrutalistDialog
513+
<button
514+
onClick={() => setIsExportDialogOpen(true)}
515+
className="group relative inline-flex items-center gap-4 px-10 py-6 bg-white text-black hover:bg-emerald-400 transition-all duration-300 font-mono uppercase tracking-widest text-sm font-black rounded-sm shrink-0"
516+
>
517+
<DownloadSimpleIcon weight="bold" size={24} />
518+
<span>Export</span>
519+
</button>
520+
</div>
521+
</div>
522+
</header>
523+
524+
{/* Export Manager Dialog */}
525+
<BrutalistDialog
526+
isOpen={isExportDialogOpen}
527+
onClose={() => setIsExportDialogOpen(false)}
528+
title="EXPORT_MANAGER_v1.0"
529+
>
530+
<div className="space-y-6 font-mono text-sm uppercase tracking-wider">
531+
<p className="text-gray-500 text-xs leading-relaxed">
532+
SELECT EXPORT MODE FOR CURRENT ARCHIVE ENTITY:
533+
</p>
534+
535+
<div className="flex flex-col gap-4">
536+
<button
537+
onClick={() => { handleDownload('full'); setIsExportDialogOpen(false); }}
538+
className="w-full py-6 bg-white text-black hover:bg-emerald-500 transition-all font-black text-xs flex flex-col items-center gap-1"
539+
>
540+
<span>EXPORT_COVER</span>
541+
<span className="text-[9px] opacity-60">FULL COMPOSITION WITH TYPOGRAPHY & MEDIA</span>
542+
</button>
543+
544+
<button
545+
onClick={() => { handleDownload('page'); setIsExportDialogOpen(false); }}
546+
className="w-full py-6 border border-white/10 text-white hover:bg-white/5 transition-all font-black text-xs flex flex-col items-center gap-1"
547+
>
548+
<span>EXPORT_PAGE</span>
549+
<span className="text-[9px] text-gray-500">TEMPLATE ONLY // SHAPES + GRID + BORDER</span>
550+
</button>
551+
552+
<button
553+
onClick={() => setIsExportDialogOpen(false)}
554+
className="w-full py-3 text-red-500 hover:text-white transition-all font-mono text-[10px] uppercase tracking-[0.3em]"
555+
>
556+
[ CLOSE_SESSION ]
557+
</button>
558+
</div>
559+
</div>
560+
</BrutalistDialog>
561+
562+
{/* Save Confirmation Dialog */} <BrutalistDialog
515563
isOpen={isSaveDialogOpen}
516564
onClose={() => setIsSaveDialogOpen(false)}
517565
onConfirm={() => { handleSavePreset(); setIsSaveDialogOpen(false); }}

0 commit comments

Comments
 (0)