1
1
<script >
2
- import { quintOut } from ' svelte/easing' ;
3
- import crossfade from ' ./crossfade.js' ; // TODO put this in svelte/transition!
4
-
5
- const { send , receive } = crossfade ({
6
- fallback (node , params ) {
7
- const style = getComputedStyle (node);
8
- const transform = style .transform === ' none' ? ' ' : style .transform ;
9
-
10
- return {
11
- duration: 600 ,
12
- easing: quintOut,
13
- css : t => `
14
- transform: ${ transform} scale(${ t} );
15
- opacity: ${ t}
16
- `
17
- };
18
- }
2
+ import { crossfade , scale } from ' svelte/transition' ;
3
+ import images from ' ./images.js' ;
4
+
5
+ const [send , receive ] = crossfade ({
6
+ duration: 200 ,
7
+ fallback: scale
19
8
});
20
9
21
- let todos = [
22
- { id: 1 , done: false , description: ' write some docs' },
23
- { id: 2 , done: false , description: ' start writing JSConf talk' },
24
- { id: 3 , done: true , description: ' buy some milk' },
25
- { id: 4 , done: false , description: ' mow the lawn' },
26
- { id: 5 , done: false , description: ' feed the turtle' },
27
- { id: 6 , done: false , description: ' fix some bugs' },
28
- ];
29
-
30
- let uid = todos .length + 1 ;
31
-
32
- function add (input ) {
33
- const todo = {
34
- id: uid++ ,
35
- done: false ,
36
- description: input .value
37
- };
10
+ let selected = null ;
11
+ let loading = null ;
38
12
39
- todos = [todo, ... todos];
40
- input .value = ' ' ;
41
- }
13
+ const ASSETS = ` https://svelte-assets.surge.sh/crossfade` ;
42
14
43
- function remove (todo ) {
44
- todos = todos .filter (t => t !== todo);
45
- }
15
+ const load = image => {
16
+ const timeout = setTimeout (() => loading = image, 100 );
17
+
18
+ const img = new Image ();
19
+
20
+ img .onload = () => {
21
+ selected = image;
22
+ clearTimeout (timeout);
23
+ loading = null ;
24
+ };
25
+
26
+ img .src = ` ${ ASSETS } /${ image .id } .jpg` ;
27
+ };
46
28
</script >
47
29
30
+ <div class =" container" >
31
+ <div class =" phone" >
32
+ <h1 >Photo gallery</h1 >
33
+
34
+ <div class =" grid" >
35
+ {#each images as image }
36
+ <div class =" square" >
37
+ {#if selected !== image }
38
+ <button
39
+ style ="background-color: {image .color };"
40
+ on :click =" {() => load (image )}"
41
+ in:receive ={{key :image .id }}
42
+ out:send ={{key :image .id }}
43
+ >{loading === image ? ' ...' : image .id }</button >
44
+ {/if }
45
+ </div >
46
+ {/each }
47
+ </div >
48
+
49
+ {#if selected }
50
+ {#await selected then d }
51
+ <div class ="photo" in:receive ={{key :d .id }} out:send ={{key :d .id }}>
52
+ <img
53
+ alt ={d .alt }
54
+ src =" {ASSETS }/ {d .id }.jpg"
55
+ on :click =" {() => selected = null }"
56
+ >
57
+
58
+ <p class =' credit' >
59
+ <a target ="_blank" href ="https://www.flickr.com/photos/ {d .path }" >via Flickr</a > –
60
+ <a target ="_blank" href ={d .license .url }>{d .license .name }</a >
61
+ </p >
62
+ </div >
63
+ {/await }
64
+ {/if }
65
+ </div >
66
+ </div >
67
+
48
68
<style >
49
- .new-todo {
50
- font-size : 1.4em ;
69
+ .container {
70
+ position : absolute ;
71
+ display : flex ;
72
+ align-items : center ;
73
+ justify-content : center ;
51
74
width : 100% ;
52
- margin : 2em 0 1em 0 ;
75
+ height : 100% ;
76
+ top : 0 ;
77
+ left : 0 ;
53
78
}
54
79
55
- .board {
56
- max-width : 36em ;
57
- margin : 0 auto ;
80
+ .phone {
81
+ position : relative ;
82
+ display : flex ;
83
+ flex-direction : column ;
84
+ width : 52vmin ;
85
+ height : 76vmin ;
86
+ border : 2vmin solid #ccc ;
87
+ border-bottom-width : 10vmin ;
88
+ padding : 3vmin ;
89
+ border-radius : 2vmin ;
58
90
}
59
91
60
- .left , .right {
61
- float : left ;
62
- width : 50 % ;
63
- padding : 0 1 em 0 0 ;
64
- box-sizing : border-box ;
92
+ h1 {
93
+ font-weight : 300 ;
94
+ text-transform : uppercase ;
95
+ font-size : 5 vmin ;
96
+ margin : 0.2 em 0 0.5 em 0 ;
65
97
}
66
98
67
- h2 {
68
- font-size : 2em ;
69
- font-weight : 200 ;
70
- user-select : none ;
99
+ .grid {
100
+ display : grid ;
101
+ flex : 1 ;
102
+ grid-template-columns : repeat (3 , 1fr );
103
+ grid-template-rows : repeat (4 , 1fr );
104
+ grid-gap : 2vmin ;
71
105
}
72
106
73
- label {
107
+ button {
108
+ width : 100% ;
109
+ height : 100% ;
110
+ color : white ;
111
+ font-size : 5vmin ;
112
+ border : none ;
113
+ margin : 0 ;
114
+ will-change : transform;
115
+ }
116
+
117
+ .photo , img {
118
+ position : absolute ;
74
119
top : 0 ;
75
120
left : 0 ;
76
- display : block ;
77
- font-size : 1em ;
78
- line-height : 1 ;
79
- padding : 0.5em ;
80
- margin : 0 auto 0.5em auto ;
81
- border-radius : 2px ;
82
- background-color : #eee ;
83
- user-select : none ;
121
+ width : 100% ;
122
+ height : 100% ;
123
+ overflow : hidden ;
84
124
}
85
125
86
- input { margin : 0 }
87
-
88
- .right label {
89
- background-color : rgb (180 ,240 ,100 );
126
+ .photo {
127
+ display : flex ;
128
+ align-items : stretch ;
129
+ justify-content : flex-end ;
130
+ flex-direction : column ;
131
+ will-change : transform;
90
132
}
91
133
92
- button {
93
- float : right ;
94
- height : 1em ;
95
- box-sizing : border-box ;
96
- padding : 0 0.5em ;
97
- line-height : 1 ;
98
- background-color : transparent ;
99
- border : none ;
100
- color : rgb (170 ,30 ,30 );
101
- opacity : 0 ;
102
- transition : opacity 0.2s ;
134
+ img {
135
+ object-fit : cover ;
136
+ cursor : pointer ;
103
137
}
104
138
105
- label :hover button {
106
- opacity : 1 ;
139
+ .credit {
140
+ text-align : right ;
141
+ font-size : 2.5vmin ;
142
+ padding : 1em ;
143
+ margin : 0 ;
144
+ color : white ;
145
+ font-weight : bold ;
146
+ opacity : 0.6 ;
147
+ background : rgba (0 ,0 ,0 ,0.4 );
107
148
}
108
- </style >
109
-
110
- <div class =' board' >
111
- <input class ="new-todo" placeholder ="what needs to be done?" on :keydown =" {event => event .which === 13 && add (event .target )}" >
112
-
113
- <div class =' left' >
114
- <h2 >todo</h2 >
115
- {#each todos .filter (t => ! t .done ) as todo (todo .id )}
116
- <label
117
- in:receive =" {{key : todo .id }}"
118
- out:send =" {{key : todo .id }}"
119
- >
120
- <input type =checkbox bind:checked ={todo .done }>
121
- {todo .description }
122
- <button on :click =" {() => remove (todo )}" >x</button >
123
- </label >
124
- {/each }
125
- </div >
126
149
127
- <div class =' right' >
128
- <h2 >done</h2 >
129
- {#each todos .filter (t => t .done ) as todo (todo .id )}
130
- <label
131
- in:receive =" {{key : todo .id }}"
132
- out:send =" {{key : todo .id }}"
133
- >
134
- <input type =checkbox bind:checked ={todo .done }>
135
- {todo .description }
136
- <button on :click =" {() => remove (todo )}" >x</button >
137
- </label >
138
- {/each }
139
- </div >
140
- </div >
150
+ .credit a , .credit a :visited {
151
+ color : white ;
152
+ }
153
+ </style >
0 commit comments