1+ <!DOCTYPE html>
2+ < html >
3+ < head >
4+ < title > Social Media Card Cropper</ title >
5+ < link rel ="stylesheet " href ="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.css ">
6+ < style >
7+ body {
8+ font-family : system-ui, -apple-system, sans-serif;
9+ max-width : 800px ;
10+ margin : 0 auto;
11+ padding : 20px ;
12+ background : # f5f5f5 ;
13+ }
14+ .container {
15+ background : white;
16+ padding : 20px ;
17+ border-radius : 8px ;
18+ box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.1 );
19+ }
20+ .drop-zone {
21+ border : 2px dashed # ccc ;
22+ border-radius : 4px ;
23+ padding : 20px ;
24+ text-align : center;
25+ margin-bottom : 20px ;
26+ background : # fafafa ;
27+ cursor : pointer;
28+ }
29+ .drop-zone .dragover {
30+ border-color : # 666 ;
31+ background : # eee ;
32+ }
33+ .img-container {
34+ max-width : 100% ;
35+ margin-bottom : 20px ;
36+ }
37+ # image {
38+ display : block;
39+ max-width : 100% ;
40+ }
41+ .preview-container {
42+ margin-top : 20px ;
43+ padding : 10px ;
44+ background : # fafafa ;
45+ border-radius : 4px ;
46+ }
47+ # preview {
48+ width : 100% ;
49+ max-width : 600px ;
50+ margin : 0 auto;
51+ display : block;
52+ }
53+ .download-btn {
54+ display : inline-block;
55+ padding : 10px 20px ;
56+ background : # 0066cc ;
57+ color : white;
58+ text-decoration : none;
59+ border-radius : 4px ;
60+ margin-top : 10px ;
61+ }
62+ .download-btn : hover {
63+ background : # 0052a3 ;
64+ }
65+ .hidden {
66+ display : none;
67+ }
68+ </ style >
69+ </ head >
70+ < body >
71+ < div class ="container ">
72+ < h1 > Social Media Card Cropper</ h1 >
73+ < p > Drop an image or click to select. The crop area is fixed to 2:1 ratio.</ p >
74+
75+ < div class ="drop-zone " id ="dropZone ">
76+ Drop image here, click to select, or paste from clipboard
77+ < input type ="file " id ="fileInput " accept ="image/* " class ="hidden ">
78+ </ div >
79+
80+ < div class ="img-container ">
81+ < img id ="image " class ="hidden ">
82+ </ div >
83+
84+ < div class ="preview-container hidden " id ="previewContainer ">
85+ < h3 > Preview (0.7 quality JPEG)</ h3 >
86+ < img id ="preview ">
87+ < div style ="text-align: center; margin-top: 10px; ">
88+ < a href ="# " id ="downloadBtn " class ="download-btn "> Download Social Media Card</ a >
89+ </ div >
90+ </ div >
91+ </ div >
92+
93+ < script src ="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js "> </ script >
94+ < script >
95+ let cropper = null ;
96+ const dropZone = document . getElementById ( 'dropZone' ) ;
97+ const fileInput = document . getElementById ( 'fileInput' ) ;
98+
99+ // Handle paste events
100+ document . addEventListener ( 'paste' , ( e ) => {
101+ e . preventDefault ( ) ;
102+ const items = ( e . clipboardData || e . originalEvent . clipboardData ) . items ;
103+ for ( const item of items ) {
104+ if ( item . type . indexOf ( 'image' ) === 0 ) {
105+ const file = item . getAsFile ( ) ;
106+ handleFile ( file ) ;
107+ break ;
108+ }
109+ }
110+ } ) ;
111+ const image = document . getElementById ( 'image' ) ;
112+ const preview = document . getElementById ( 'preview' ) ;
113+ const previewContainer = document . getElementById ( 'previewContainer' ) ;
114+ const downloadBtn = document . getElementById ( 'downloadBtn' ) ;
115+
116+ // Handle drag and drop
117+ dropZone . addEventListener ( 'dragover' , ( e ) => {
118+ e . preventDefault ( ) ;
119+ dropZone . classList . add ( 'dragover' ) ;
120+ } ) ;
121+
122+ dropZone . addEventListener ( 'dragleave' , ( ) => {
123+ dropZone . classList . remove ( 'dragover' ) ;
124+ } ) ;
125+
126+ dropZone . addEventListener ( 'drop' , ( e ) => {
127+ e . preventDefault ( ) ;
128+ dropZone . classList . remove ( 'dragover' ) ;
129+ handleFile ( e . dataTransfer . files [ 0 ] ) ;
130+ } ) ;
131+
132+ // Handle click to select
133+ dropZone . addEventListener ( 'click' , ( ) => {
134+ fileInput . click ( ) ;
135+ } ) ;
136+
137+ fileInput . addEventListener ( 'change' , ( e ) => {
138+ if ( e . target . files . length ) {
139+ handleFile ( e . target . files [ 0 ] ) ;
140+ }
141+ } ) ;
142+
143+ function handleFile ( file ) {
144+ if ( ! file . type . startsWith ( 'image/' ) ) {
145+ alert ( 'Please select an image file.' ) ;
146+ return ;
147+ }
148+
149+ const reader = new FileReader ( ) ;
150+ reader . onload = ( e ) => {
151+ image . src = e . target . result ;
152+ image . classList . remove ( 'hidden' ) ;
153+ initCropper ( ) ;
154+ } ;
155+ reader . readAsDataURL ( file ) ;
156+ }
157+
158+ function initCropper ( ) {
159+ if ( cropper ) {
160+ cropper . destroy ( ) ;
161+ }
162+
163+ cropper = new Cropper ( image , {
164+ aspectRatio : 2 ,
165+ viewMode : 1 ,
166+ dragMode : 'move' ,
167+ autoCropArea : 1 ,
168+ restore : false ,
169+ guides : true ,
170+ center : true ,
171+ highlight : false ,
172+ cropBoxMovable : true ,
173+ cropBoxResizable : false ,
174+ toggleDragModeOnDblclick : false ,
175+ crop : updatePreview
176+ } ) ;
177+ }
178+
179+ function updatePreview ( ) {
180+ if ( ! cropper ) return ;
181+
182+ const canvas = cropper . getCroppedCanvas ( ) ;
183+ if ( ! canvas ) return ;
184+
185+ // Convert to JPEG with 0.7 quality
186+ const previewUrl = canvas . toDataURL ( 'image/jpeg' , 0.7 ) ;
187+ preview . src = previewUrl ;
188+ previewContainer . classList . remove ( 'hidden' ) ;
189+
190+ // Update download link
191+ downloadBtn . href = previewUrl ;
192+ downloadBtn . download = 'social-media-card.jpg' ;
193+ }
194+ </ script >
195+ </ body >
196+ </ html >
0 commit comments