@egjs/vue3-flicking 4.14.1 → 4.16.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/declaration/FlickingProps.d.ts +1 -1
- package/declaration/VuePanel.d.ts +1 -1
- package/declaration/VueRenderer.d.ts +1 -1
- package/declaration/types.d.ts +3 -3
- package/dev/archive/App.vue +156 -0
- package/dev/archive/BasicDemo.vue +171 -0
- package/dev/archive/MainApp.vue +73 -0
- package/dev/archive/ReactiveDemo.vue +120 -0
- package/dev/archive/components/Test.vue +3 -0
- package/dev/archive/components/Test2.vue +3 -0
- package/dev/archive/demo-common.css +208 -0
- package/dev/archive/main.ts +15 -0
- package/dev/archive/router.ts +29 -0
- package/dev/basic-sample/App.vue +32 -0
- package/dev/basic-sample/index.html +15 -0
- package/dev/basic-sample/main.ts +13 -0
- package/dev/index.html +18 -0
- package/dev/plugin-check/App.vue +245 -0
- package/dev/plugin-check/index.html +15 -0
- package/dev/plugin-check/main.ts +13 -0
- package/dev/scratch/App.vue +32 -0
- package/dev/scratch/index.html +15 -0
- package/dev/scratch/main.ts +13 -0
- package/dev/vite-env.d.ts +9 -0
- package/dist/flicking.cjs.js +446 -542
- package/dist/flicking.cjs.js.map +1 -1
- package/dist/flicking.esm.js +450 -541
- package/dist/flicking.esm.js.map +1 -1
- package/package.json +16 -22
- package/src/Flicking.ts +55 -62
- package/src/FlickingProps.ts +3 -2
- package/src/VueElementProvider.ts +3 -1
- package/src/VueRenderer.ts +3 -8
- package/src/reactive.ts +1 -2
- package/src/types.ts +27 -30
- package/vite.config.ts +34 -0
- package/vite.dev.config.ts +49 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +0 -18
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/* 공통 데모 스타일 */
|
|
2
|
+
|
|
3
|
+
/* 기본 레이아웃 */
|
|
4
|
+
.demo-container {
|
|
5
|
+
max-width: 1200px;
|
|
6
|
+
margin: 0 auto;
|
|
7
|
+
padding: 40px 20px;
|
|
8
|
+
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
9
|
+
-webkit-font-smoothing: antialiased;
|
|
10
|
+
-moz-osx-font-smoothing: grayscale;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* 타이포그래피 */
|
|
14
|
+
h1 {
|
|
15
|
+
color: #333;
|
|
16
|
+
margin: 40px 0 20px;
|
|
17
|
+
font-size: 24px;
|
|
18
|
+
font-weight: 600;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
h1:first-child {
|
|
22
|
+
margin-top: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
h2 {
|
|
26
|
+
color: #333;
|
|
27
|
+
text-align: center;
|
|
28
|
+
margin-bottom: 30px;
|
|
29
|
+
font-size: 28px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
h3 {
|
|
33
|
+
color: #666;
|
|
34
|
+
margin-bottom: 15px;
|
|
35
|
+
font-size: 20px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* 섹션 */
|
|
39
|
+
.section {
|
|
40
|
+
margin-bottom: 30px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* 패널 스타일 */
|
|
44
|
+
.panel {
|
|
45
|
+
width: 200px;
|
|
46
|
+
height: 200px;
|
|
47
|
+
margin-right: 20px;
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
justify-content: center;
|
|
50
|
+
align-items: center;
|
|
51
|
+
font-size: 48px;
|
|
52
|
+
font-weight: bold;
|
|
53
|
+
color: white;
|
|
54
|
+
border-radius: 8px;
|
|
55
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
56
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.panel:nth-child(2) {
|
|
60
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.panel:nth-child(3) {
|
|
64
|
+
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.panel:nth-child(4) {
|
|
68
|
+
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.panel:nth-child(5) {
|
|
72
|
+
background: linear-gradient(135deg, #feca57 0%, #ff9f43 100%);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.panel:nth-child(6) {
|
|
76
|
+
background: linear-gradient(135deg, #fa8bff 0%, #2bd2ff 100%);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.panel:nth-child(7) {
|
|
80
|
+
background: linear-gradient(135deg, #ff6b6b 0%, #ffa502 100%);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.panel:nth-child(n + 8) {
|
|
84
|
+
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* 컨트롤 버튼 */
|
|
88
|
+
.controls {
|
|
89
|
+
display: flex;
|
|
90
|
+
gap: 10px;
|
|
91
|
+
justify-content: center;
|
|
92
|
+
margin: 20px 0;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.button,
|
|
97
|
+
.btn,
|
|
98
|
+
button {
|
|
99
|
+
padding: 10px 20px;
|
|
100
|
+
background-color: #007bff;
|
|
101
|
+
color: white;
|
|
102
|
+
border: none;
|
|
103
|
+
border-radius: 5px;
|
|
104
|
+
cursor: pointer;
|
|
105
|
+
font-size: 14px;
|
|
106
|
+
transition: background-color 0.3s;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.button:hover,
|
|
110
|
+
.btn:hover:not(:disabled),
|
|
111
|
+
button:hover:not(:disabled) {
|
|
112
|
+
background-color: #0056b3;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.button:active,
|
|
116
|
+
.btn:active:not(:disabled),
|
|
117
|
+
button:active:not(:disabled) {
|
|
118
|
+
transform: translateY(1px);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.btn:disabled,
|
|
122
|
+
button:disabled {
|
|
123
|
+
background-color: #ccc;
|
|
124
|
+
cursor: not-allowed;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* 상태 표시 */
|
|
128
|
+
.status {
|
|
129
|
+
background-color: #f8f9fa;
|
|
130
|
+
padding: 15px;
|
|
131
|
+
border-radius: 5px;
|
|
132
|
+
margin: 20px 0;
|
|
133
|
+
text-align: center;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.status p {
|
|
137
|
+
margin: 5px 0;
|
|
138
|
+
color: #666;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* 폼 요소 */
|
|
142
|
+
label {
|
|
143
|
+
display: inline-block;
|
|
144
|
+
margin: 10px 20px 10px 0;
|
|
145
|
+
cursor: pointer;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
input[type="checkbox"] {
|
|
149
|
+
margin-right: 5px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* 페이지네이션 */
|
|
153
|
+
.pagination {
|
|
154
|
+
display: flex;
|
|
155
|
+
gap: 10px;
|
|
156
|
+
justify-content: center;
|
|
157
|
+
margin: 20px 0;
|
|
158
|
+
flex-wrap: wrap;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.pagination-btn {
|
|
162
|
+
padding: 10px 20px;
|
|
163
|
+
background-color: #007bff;
|
|
164
|
+
color: white;
|
|
165
|
+
border: none;
|
|
166
|
+
border-radius: 5px;
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
font-size: 14px;
|
|
169
|
+
transition: background-color 0.3s;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.pagination-btn:hover {
|
|
173
|
+
background-color: #0056b3;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.pagination-btn:active {
|
|
177
|
+
transform: translateY(1px);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.pagination-btn.active {
|
|
181
|
+
background-color: #28a745;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* 프로그레스 바 */
|
|
185
|
+
.progress-container {
|
|
186
|
+
position: relative;
|
|
187
|
+
width: 100%;
|
|
188
|
+
height: 20px;
|
|
189
|
+
background: #f0f0f0;
|
|
190
|
+
border-radius: 10px;
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
margin: 20px 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.progress-bar {
|
|
196
|
+
height: 100%;
|
|
197
|
+
background: linear-gradient(90deg, #007bff, #28a745);
|
|
198
|
+
transition: width 0.3s ease;
|
|
199
|
+
border-radius: 10px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.progress-text {
|
|
203
|
+
text-align: center;
|
|
204
|
+
margin-top: 10px;
|
|
205
|
+
font-size: 14px;
|
|
206
|
+
color: #666;
|
|
207
|
+
font-weight: bold;
|
|
208
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createApp } from "vue";
|
|
2
|
+
import MainApp from "./MainApp.vue";
|
|
3
|
+
import router from "./router";
|
|
4
|
+
|
|
5
|
+
// CSS imports
|
|
6
|
+
import "@dev/flicking-css";
|
|
7
|
+
import "@dev/plugins-css";
|
|
8
|
+
|
|
9
|
+
// @ts-expect-error - injected by vite
|
|
10
|
+
const buildMode = __DEV__ ? "source" : "build";
|
|
11
|
+
console.log(`🔧 Vue3 Flicking Dev - ${buildMode} 모드`);
|
|
12
|
+
|
|
13
|
+
const app = createApp(MainApp);
|
|
14
|
+
app.use(router);
|
|
15
|
+
app.mount("#app");
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createRouter, createWebHistory } from "vue-router";
|
|
2
|
+
import App from "./App.vue";
|
|
3
|
+
import BasicDemo from "./BasicDemo.vue";
|
|
4
|
+
import ReactiveDemo from "./ReactiveDemo.vue";
|
|
5
|
+
|
|
6
|
+
const routes = [
|
|
7
|
+
{
|
|
8
|
+
path: "/",
|
|
9
|
+
name: "Home",
|
|
10
|
+
component: App
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
path: "/basic",
|
|
14
|
+
name: "BasicDemo",
|
|
15
|
+
component: BasicDemo
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
path: "/reactive",
|
|
19
|
+
name: "ReactiveDemo",
|
|
20
|
+
component: ReactiveDemo
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const router = createRouter({
|
|
25
|
+
history: createWebHistory(),
|
|
26
|
+
routes
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default router;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :style="css.container">
|
|
3
|
+
<h1>Basic Sample</h1>
|
|
4
|
+
<Flicking :options="{ align: 'prev', circular: true }">
|
|
5
|
+
<div v-for="n in 5" :key="n" :style="css.panel">{{ n }}</div>
|
|
6
|
+
</Flicking>
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
import Flicking from "@dev/vue3-flicking";
|
|
12
|
+
|
|
13
|
+
const css = {
|
|
14
|
+
container: {
|
|
15
|
+
maxWidth: "800px",
|
|
16
|
+
margin: "0 auto",
|
|
17
|
+
padding: "20px"
|
|
18
|
+
},
|
|
19
|
+
panel: {
|
|
20
|
+
minWidth: "200px",
|
|
21
|
+
height: "200px",
|
|
22
|
+
margin: "0 5px",
|
|
23
|
+
background: "#e0e7ff",
|
|
24
|
+
borderRadius: "8px",
|
|
25
|
+
display: "flex",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
justifyContent: "center",
|
|
28
|
+
fontSize: "24px",
|
|
29
|
+
fontWeight: "bold"
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
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" />
|
|
6
|
+
<title>Basic Sample - Vue3 Flicking</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { margin: 0; padding: 20px; font-family: sans-serif; }
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app"></div>
|
|
13
|
+
<script type="module" src="./main.ts"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic Sample - 기본 동작 확인용
|
|
3
|
+
*
|
|
4
|
+
* http://localhost:3002/basic-sample/
|
|
5
|
+
*
|
|
6
|
+
* 이 파일은 수정하지 마세요.
|
|
7
|
+
* 샘플 코드는 App.vue에 작성합니다.
|
|
8
|
+
*/
|
|
9
|
+
import { createApp } from "vue";
|
|
10
|
+
import "@dev/flicking-css";
|
|
11
|
+
import App from "./App.vue";
|
|
12
|
+
|
|
13
|
+
createApp(App).mount("#app");
|
package/dev/index.html
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
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" />
|
|
6
|
+
<title>Vue3 Flicking - Dev</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { margin: 0; padding: 40px; font-family: sans-serif; }
|
|
9
|
+
a { display: block; margin: 8px 0; font-size: 18px; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<h1>Vue3 Flicking Dev</h1>
|
|
14
|
+
<a href="/basic-sample/">Basic Sample</a>
|
|
15
|
+
<a href="/plugin-check/">Plugin Check (마이그레이션 검증용)</a>
|
|
16
|
+
<a href="/scratch/">Scratch (이슈 재현)</a>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
플러그인 마이그레이션 검증용 (임시)
|
|
3
|
+
docs 데모 추가 후 제거 예정
|
|
4
|
+
|
|
5
|
+
참고: https://naver.github.io/egjs-flicking/ko/Plugins
|
|
6
|
+
-->
|
|
7
|
+
<template>
|
|
8
|
+
<div :style="{ maxWidth: '640px', margin: '0 auto', padding: '20px' }">
|
|
9
|
+
<h1>Plugin Check</h1>
|
|
10
|
+
<p :style="css.note">마이그레이션 검증용 — docs 데모 추가 후 제거 예정</p>
|
|
11
|
+
|
|
12
|
+
<!-- Arrow -->
|
|
13
|
+
<section :style="css.section">
|
|
14
|
+
<div :style="css.title">Arrow</div>
|
|
15
|
+
<Flicking :options="{ circular: true }" :plugins="arrowPlugins">
|
|
16
|
+
<div v-for="n in 5" :key="n" :style="css.panel">{{ n }}</div>
|
|
17
|
+
<template #viewport>
|
|
18
|
+
<span class="flicking-arrow-prev"></span>
|
|
19
|
+
<span class="flicking-arrow-next"></span>
|
|
20
|
+
</template>
|
|
21
|
+
</Flicking>
|
|
22
|
+
</section>
|
|
23
|
+
|
|
24
|
+
<!-- AutoPlay -->
|
|
25
|
+
<section :style="css.section">
|
|
26
|
+
<div :style="css.title">AutoPlay</div>
|
|
27
|
+
<Flicking :options="{ circular: true, preventDefaultOnDrag: true }" :plugins="autoPlayPlugins">
|
|
28
|
+
<div v-for="(src, i) in images.slice(0, 3)" :key="i" :style="css.pluginsPanel">
|
|
29
|
+
<img :style="css.panelImage" :src="src" />
|
|
30
|
+
</div>
|
|
31
|
+
</Flicking>
|
|
32
|
+
</section>
|
|
33
|
+
|
|
34
|
+
<!-- Pagination -->
|
|
35
|
+
<section :style="css.section">
|
|
36
|
+
<div :style="css.title">Pagination (bullet)</div>
|
|
37
|
+
<Flicking :options="{ circular: true }" :plugins="paginationPlugins">
|
|
38
|
+
<div v-for="n in 8" :key="n" :style="css.panel">{{ n }}</div>
|
|
39
|
+
<template #viewport>
|
|
40
|
+
<div class="flicking-pagination"></div>
|
|
41
|
+
</template>
|
|
42
|
+
</Flicking>
|
|
43
|
+
</section>
|
|
44
|
+
|
|
45
|
+
<!-- Fade -->
|
|
46
|
+
<section :style="css.section">
|
|
47
|
+
<div :style="css.title">Fade</div>
|
|
48
|
+
<Flicking :options="{ circular: true, preventDefaultOnDrag: true }" :plugins="fadePlugins">
|
|
49
|
+
<div v-for="(src, i) in images.slice(0, 3)" :key="i" :style="css.pluginsPanel">
|
|
50
|
+
<img :style="css.panelImage" :src="src" />
|
|
51
|
+
</div>
|
|
52
|
+
</Flicking>
|
|
53
|
+
</section>
|
|
54
|
+
|
|
55
|
+
<!-- Parallax -->
|
|
56
|
+
<section :style="css.section">
|
|
57
|
+
<div :style="css.title">Parallax</div>
|
|
58
|
+
<Flicking :options="{ circular: true, preventDefaultOnDrag: true, gap: 2 }" :plugins="parallaxPlugins">
|
|
59
|
+
<div v-for="(src, i) in images.slice(0, 3)" :key="i" :style="{ ...css.pluginsPanel, width: '100%' }">
|
|
60
|
+
<img :style="{ ...css.panelImage, width: '150%', maxWidth: 'none' }" :src="src" />
|
|
61
|
+
</div>
|
|
62
|
+
</Flicking>
|
|
63
|
+
</section>
|
|
64
|
+
|
|
65
|
+
<!-- Perspective -->
|
|
66
|
+
<section :style="css.section">
|
|
67
|
+
<div :style="css.title">Perspective</div>
|
|
68
|
+
<Flicking :options="{ circular: true }" :plugins="perspectivePlugins">
|
|
69
|
+
<div v-for="n in 5" :key="n" :style="css.panel">{{ n }}</div>
|
|
70
|
+
</Flicking>
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
<!-- Sync (camera) -->
|
|
74
|
+
<section :style="css.section">
|
|
75
|
+
<div :style="css.title">Sync (camera)</div>
|
|
76
|
+
<Flicking ref="syncCam0" :options="{ align: 'prev', bound: true, bounce: 30 }" :plugins="syncCameraPlugins">
|
|
77
|
+
<span v-for="item in fruits" :key="item" :style="css.syncItem">{{ item }}</span>
|
|
78
|
+
</Flicking>
|
|
79
|
+
<div style="margin-top: 4px;">
|
|
80
|
+
<Flicking ref="syncCam1" :options="{ align: 'prev', bound: true, bounce: 30 }">
|
|
81
|
+
<span v-for="item in foods" :key="item" :style="css.syncItem">{{ item }}</span>
|
|
82
|
+
</Flicking>
|
|
83
|
+
</div>
|
|
84
|
+
<div style="margin-top: 4px;">
|
|
85
|
+
<Flicking ref="syncCam2" :options="{ align: 'prev', bound: true, bounce: 30 }">
|
|
86
|
+
<span v-for="item in drinks" :key="item" :style="css.syncItem">{{ item }}</span>
|
|
87
|
+
</Flicking>
|
|
88
|
+
</div>
|
|
89
|
+
</section>
|
|
90
|
+
|
|
91
|
+
<!-- Sync (index + thumbnail) -->
|
|
92
|
+
<section :style="css.section">
|
|
93
|
+
<div :style="css.title">Sync (index + thumbnail)</div>
|
|
94
|
+
<Flicking ref="syncMain" :options="{ bounce: 30, preventDefaultOnDrag: true }" :plugins="syncIndexPlugins">
|
|
95
|
+
<div v-for="(src, i) in images" :key="i" :style="css.pluginsPanel">
|
|
96
|
+
<img :style="css.panelImage" :src="src" />
|
|
97
|
+
</div>
|
|
98
|
+
</Flicking>
|
|
99
|
+
<div style="margin-top: 8px;">
|
|
100
|
+
<Flicking ref="syncThumb" :options="{ moveType: 'freeScroll', bound: true, bounce: 30, preventDefaultOnDrag: true }">
|
|
101
|
+
<div v-for="(src, i) in images" :key="i" :style="css.thumbPanel">
|
|
102
|
+
<img :style="css.thumbImage" :src="src" />
|
|
103
|
+
</div>
|
|
104
|
+
</Flicking>
|
|
105
|
+
</div>
|
|
106
|
+
</section>
|
|
107
|
+
</div>
|
|
108
|
+
</template>
|
|
109
|
+
|
|
110
|
+
<script setup lang="ts">
|
|
111
|
+
import { Arrow, AutoPlay, Fade, Pagination, Parallax, Perspective, Sync } from "@dev/plugins";
|
|
112
|
+
import Flicking from "@dev/vue3-flicking";
|
|
113
|
+
import { onMounted, ref } from "vue";
|
|
114
|
+
|
|
115
|
+
const css = {
|
|
116
|
+
section: { marginBottom: "48px" },
|
|
117
|
+
title: {
|
|
118
|
+
fontSize: "18px",
|
|
119
|
+
fontWeight: "bold",
|
|
120
|
+
marginBottom: "12px",
|
|
121
|
+
borderBottom: "2px solid #333",
|
|
122
|
+
paddingBottom: "4px"
|
|
123
|
+
},
|
|
124
|
+
note: { fontSize: "12px", color: "#666", marginTop: "8px" },
|
|
125
|
+
panel: {
|
|
126
|
+
minWidth: "200px",
|
|
127
|
+
height: "160px",
|
|
128
|
+
margin: "0 5px",
|
|
129
|
+
background: "#e0e7ff",
|
|
130
|
+
borderRadius: "8px",
|
|
131
|
+
display: "flex",
|
|
132
|
+
alignItems: "center",
|
|
133
|
+
justifyContent: "center",
|
|
134
|
+
fontSize: "24px",
|
|
135
|
+
fontWeight: "bold",
|
|
136
|
+
overflow: "hidden"
|
|
137
|
+
},
|
|
138
|
+
pluginsPanel: { position: "relative" as const, width: "100%", height: "200px", overflow: "hidden" },
|
|
139
|
+
panelImage: { width: "100%", height: "100%", objectFit: "cover" as const },
|
|
140
|
+
thumbPanel: {
|
|
141
|
+
width: "100px",
|
|
142
|
+
height: "70px",
|
|
143
|
+
margin: "0 2px",
|
|
144
|
+
overflow: "hidden",
|
|
145
|
+
opacity: "0.5",
|
|
146
|
+
transition: "opacity 0.3s"
|
|
147
|
+
},
|
|
148
|
+
thumbImage: { width: "100%", height: "100%", objectFit: "cover" as const },
|
|
149
|
+
syncItem: {
|
|
150
|
+
display: "inline-block",
|
|
151
|
+
padding: "8px 16px",
|
|
152
|
+
margin: "0 4px",
|
|
153
|
+
background: "#f5f5f5",
|
|
154
|
+
borderRadius: "4px",
|
|
155
|
+
whiteSpace: "nowrap"
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const images = [
|
|
160
|
+
"https://picsum.photos/seed/a/600/300",
|
|
161
|
+
"https://picsum.photos/seed/b/600/300",
|
|
162
|
+
"https://picsum.photos/seed/c/600/300",
|
|
163
|
+
"https://picsum.photos/seed/d/600/300",
|
|
164
|
+
"https://picsum.photos/seed/e/600/300",
|
|
165
|
+
"https://picsum.photos/seed/f/600/300"
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
const fruits = [
|
|
169
|
+
"🍎 Apple",
|
|
170
|
+
"🍉 Watermelon",
|
|
171
|
+
"🥝 Kiwi",
|
|
172
|
+
"🍊 Orange",
|
|
173
|
+
"🍇 Grape",
|
|
174
|
+
"🍓 Strawberry",
|
|
175
|
+
"🍑 Peach",
|
|
176
|
+
"🍋 Lemon",
|
|
177
|
+
"🫐 Blueberry",
|
|
178
|
+
"🍌 Banana"
|
|
179
|
+
];
|
|
180
|
+
const foods = [
|
|
181
|
+
"🍔 Hamburger",
|
|
182
|
+
"🍕 Pizza",
|
|
183
|
+
"🍞 Bread",
|
|
184
|
+
"🌮 Taco",
|
|
185
|
+
"🍜 Ramen",
|
|
186
|
+
"🍣 Sushi",
|
|
187
|
+
"🥗 Salad",
|
|
188
|
+
"🍝 Pasta",
|
|
189
|
+
"🥘 Stew",
|
|
190
|
+
"🍱 Bento"
|
|
191
|
+
];
|
|
192
|
+
const drinks = [
|
|
193
|
+
"🥛 Milk",
|
|
194
|
+
"☕ Coffee",
|
|
195
|
+
"🍵 Green tea",
|
|
196
|
+
"🧃 Juice",
|
|
197
|
+
"🥤 Soda",
|
|
198
|
+
"🍺 Beer",
|
|
199
|
+
"🧋 Bubble tea",
|
|
200
|
+
"🍷 Wine",
|
|
201
|
+
"🥥 Coconut",
|
|
202
|
+
"🍶 Sake"
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
// Simple plugins (no ref dependency)
|
|
206
|
+
const arrowPlugins = [new Arrow()];
|
|
207
|
+
const autoPlayPlugins = [new AutoPlay()];
|
|
208
|
+
const paginationPlugins = [new Pagination({ type: "bullet" })];
|
|
209
|
+
const fadePlugins = [new Fade()];
|
|
210
|
+
const parallaxPlugins = [new Parallax("img")];
|
|
211
|
+
const perspectivePlugins = [new Perspective({ rotate: 1, scale: 2, perspective: 600 })];
|
|
212
|
+
|
|
213
|
+
// Sync plugins (need refs)
|
|
214
|
+
const syncCam0 = ref<InstanceType<typeof Flicking> | null>(null);
|
|
215
|
+
const syncCam1 = ref<InstanceType<typeof Flicking> | null>(null);
|
|
216
|
+
const syncCam2 = ref<InstanceType<typeof Flicking> | null>(null);
|
|
217
|
+
const syncCameraPlugins = ref<Sync[]>([]);
|
|
218
|
+
|
|
219
|
+
const syncMain = ref<InstanceType<typeof Flicking> | null>(null);
|
|
220
|
+
const syncThumb = ref<InstanceType<typeof Flicking> | null>(null);
|
|
221
|
+
const syncIndexPlugins = ref<Sync[]>([]);
|
|
222
|
+
|
|
223
|
+
onMounted(() => {
|
|
224
|
+
syncCameraPlugins.value = [
|
|
225
|
+
new Sync({
|
|
226
|
+
type: "camera",
|
|
227
|
+
synchronizedFlickingOptions: [
|
|
228
|
+
{ flicking: syncCam0.value!, isClickable: false },
|
|
229
|
+
{ flicking: syncCam1.value!, isClickable: false },
|
|
230
|
+
{ flicking: syncCam2.value!, isClickable: false }
|
|
231
|
+
]
|
|
232
|
+
})
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
syncIndexPlugins.value = [
|
|
236
|
+
new Sync({
|
|
237
|
+
type: "index",
|
|
238
|
+
synchronizedFlickingOptions: [
|
|
239
|
+
{ flicking: syncMain.value!, isSlidable: true },
|
|
240
|
+
{ flicking: syncThumb.value!, isClickable: true, activeClass: "active" }
|
|
241
|
+
]
|
|
242
|
+
})
|
|
243
|
+
];
|
|
244
|
+
});
|
|
245
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
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" />
|
|
6
|
+
<title>Plugin Check - Vue3 Flicking</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { margin: 0; padding: 20px; font-family: sans-serif; }
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app"></div>
|
|
13
|
+
<script type="module" src="./main.ts"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Check - 플러그인 마이그레이션 검증용 (임시)
|
|
3
|
+
*
|
|
4
|
+
* http://localhost:3002/plugin-check/
|
|
5
|
+
*
|
|
6
|
+
* 이 파일은 수정하지 마세요.
|
|
7
|
+
*/
|
|
8
|
+
import { createApp } from "vue";
|
|
9
|
+
import "@dev/flicking-css";
|
|
10
|
+
import "@dev/plugins-css";
|
|
11
|
+
import App from "./App.vue";
|
|
12
|
+
|
|
13
|
+
createApp(App).mount("#app");
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
이슈 재현 템플릿
|
|
3
|
+
|
|
4
|
+
이 파일을 덮어써서 이슈를 재현하세요.
|
|
5
|
+
-->
|
|
6
|
+
<template>
|
|
7
|
+
<div>
|
|
8
|
+
<h2>Scratch</h2>
|
|
9
|
+
<Flicking :options="{ align: 'prev', circular: true }">
|
|
10
|
+
<div v-for="n in 3" :key="n" :style="css.panel">{{ n }}</div>
|
|
11
|
+
</Flicking>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import Flicking from "@dev/vue3-flicking";
|
|
17
|
+
|
|
18
|
+
const css = {
|
|
19
|
+
panel: {
|
|
20
|
+
minWidth: "200px",
|
|
21
|
+
height: "200px",
|
|
22
|
+
margin: "0 5px",
|
|
23
|
+
background: "#f0f0f0",
|
|
24
|
+
borderRadius: "8px",
|
|
25
|
+
display: "flex",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
justifyContent: "center",
|
|
28
|
+
fontSize: "24px",
|
|
29
|
+
fontWeight: "bold"
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
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" />
|
|
6
|
+
<title>Scratch - Vue3 Flicking</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { margin: 0; padding: 20px; font-family: sans-serif; }
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app"></div>
|
|
13
|
+
<script type="module" src="./main.ts"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scratch - 이슈 재현용 독립 페이지
|
|
3
|
+
*
|
|
4
|
+
* http://localhost:3002/scratch/
|
|
5
|
+
*
|
|
6
|
+
* 이 파일은 수정하지 마세요.
|
|
7
|
+
* 재현 코드는 App.vue에 작성합니다.
|
|
8
|
+
*/
|
|
9
|
+
import { createApp } from "vue";
|
|
10
|
+
import "@dev/flicking-css";
|
|
11
|
+
import App from "./App.vue";
|
|
12
|
+
|
|
13
|
+
createApp(App).mount("#app");
|