4
4
import vCard from " vcf" ;
5
5
import cntl from " cntl" ;
6
6
import UploadIcon from " ./UploadIcon.svelte" ;
7
+ import DownloadIcon from " ./DownloadIcon.svelte" ;
8
+ import {fly } from " svelte/transition"
7
9
8
10
const fReader = new FileReader ();
9
11
/** @type {vCard[]} */
10
12
let contacts = [];
11
13
14
+ /**
15
+ * @typedef UpdatePayload
16
+ * @property {Number} index
17
+ * @property {string} blob
18
+ */
19
+
20
+ /**
21
+ * @type {Object<string,UpdatePayload>}
22
+ */
23
+ let contactsToUpdate = {};
24
+
12
25
const uploadBtnStyle = cntl`
13
26
flex flex-col items-center p-4 bg-white
14
27
text-blue rounded-lg shadow-sm tracking-wide
15
28
uppercase border border-blue cursor-pointer
16
29
hover:bg-blue-400 hover:text-white hover:shadow-lg
17
30
transform hover:scale-105 transition duration-200
18
- ` ;
31
+ ` ;
32
+
33
+ const addToUpdate = (index , blob ) => {
34
+ contactsToUpdate[index] = {
35
+ index,
36
+ blob,
37
+ };
38
+ };
39
+
40
+ const removeFromUpdate = (index ) => {
41
+ contactsToUpdate[index] = null ;
42
+ delete contactsToUpdate[index];
43
+ };
19
44
20
45
fReader .onload = (e ) => {
21
46
if (e .target .readyState != 2 ) return ;
22
- if (e .target .error ) {
23
- alert (" Error Reading file." );
24
- return ;
25
- }
26
47
try {
27
- contacts = vCard .parse (e .target .result );
48
+ contacts = vCard .parse (e .target .result ).filter ((vc ) => {
49
+ return ! (vc .data .photo && vc .data .photo .valueOf ());
50
+ });
28
51
} catch (error) {
29
- alert (" Error reading contact(s)." );
52
+ alert (" Error reading contact(s) from file ." );
30
53
}
31
54
};
32
55
</script >
33
56
34
- <main class =" container text-center mx-auto px -24" >
35
- <h1 class =" uppercase text-red-500 font-bold text-5xl mt-12 mb-4 underline" >
57
+ <main class =" container text-center mx-auto lg:p -24 p-5 min-h-screen " >
58
+ <h1 class =" uppercase text-red-500 font-bold text-5xl mb-4 underline" >
36
59
🖼 Image 💪🏾 Contact 📇
37
60
</h1 >
38
61
{#if contacts && contacts .length > 0 }
39
62
<div >
40
63
<p class =" text-sm" >Start Over?</p >
41
64
<button
42
65
on:click ={() => (contacts = [])}
43
- class =" px-3 py-2 rounded shadow-sm m-1 mb-5 transition duration-200 hover:bg-red-400 transform hover:scale-105" >Clear
44
- ❌
66
+ class ={cntl ` px-3 py-2 rounded
67
+ shadow-sm m-1 mb-5 transition
68
+ duration-200 hover:bg-red-400
69
+ transform hover:scale-105 border-red-900 border ` }>
70
+ Clear ❌
45
71
</button >
46
72
</div >
47
73
{:else }
48
- <div >
49
- <p class =" text-md py-4 lowercase " >Click Below to continue</p >
50
- <div class =" flex items-center justify-center bg-grey-lighter mb-12 " >
74
+ <div class = " mb-12 " >
75
+ <p class =" text-md py-4" >Click Below to continue</p >
76
+ <div class =" flex items-center justify-center bg-grey-lighter" >
51
77
<label class ={uploadBtnStyle }>
52
78
<UploadIcon />
53
79
<span class =" mt-2 text-sm leading-normal" >Select vcard file</span >
58
84
accept =" .vcf" />
59
85
</label >
60
86
</div >
87
+ <p class =" block text-sm py-4" >
88
+ Only contacts without photos will be loaded.
89
+ </p >
61
90
</div >
62
91
{/if }
63
- <div class =" grid grid-cols-2 lg:grid-cols-3 gap-12" >
92
+ <div class =" grid grid-cols-1 md:grid-cols- 2 lg:grid-cols-3 gap-12 lg:gap-16 px-8 " >
64
93
{#each contacts as contact , i }
65
94
{#if contact .data .fn .valueOf () && true }
66
- <ContactCard name ={contact .data .fn .valueOf ()} />
95
+ <ContactCard
96
+ name ={contact .data .fn .valueOf ()}
97
+ on:applyphoto ={(e ) => addToUpdate (` ${i } ` , e .detail .data )}
98
+ on:unapplyphoto ={() => removeFromUpdate (` ${i } ` )} />
67
99
{/if }
68
100
{/each }
69
101
</div >
102
+ {#if contacts && contacts .length > 0 }
103
+ <button
104
+ transition:fly ={{y : 100 , duration : 1000 }}
105
+ class ={cntl ` rounded-full bg-blue-500 p-5
106
+ text-white shadow-xl transform transition
107
+ hover:scale-110 hover:shadow-2xl fixed
108
+ fab focus:outline-none ` }
109
+ >
110
+ <DownloadIcon />
111
+ </button >
112
+ {/if }
70
113
</main >
114
+
115
+ <style >
116
+ .fab {
117
+ right : 2rem ;
118
+ bottom : 2rem ;
119
+ }
120
+ @media (min-width : 768px ) {
121
+ .fab {
122
+ right : 8rem ;
123
+ }
124
+ }
125
+ </style >
0 commit comments