├── .github └── FUNDING.yml ├── README.md ├── assets ├── android-chrome-192x192.png ├── android-chrome-256x256.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── mstile-150x150.png └── safari-pinned-tab.svg ├── css └── asacoco.css ├── fonts ├── Archicoco.woff └── hkkaikk.ttf ├── images ├── background.jpg ├── cursor.png ├── default_avatar.png ├── logo.png └── templates │ ├── ACU.png │ └── science.png ├── index.html ├── js └── app.js ├── pwabuilder-sw.js ├── screenshot.png └── site.webmanifest /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://www.paypal.me/kento520 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Asacoco Generator 2 | Generate your student card of Asacoco University, [TRY IT NOW](https://rogeraabbccdd.github.io/Asacoco-Generator/)! 3 | 4 | ![screenshot](./screenshot.png) 5 | 6 | ## Credits 7 | - Background photo by [Shunya Koide](https://unsplash.com/@shunyakoide?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 8 | - Student card designed by [YoYa](https://twitter.com/JustinYoYa/status/1319541932742172672) 9 | - Science club card designed by [KoKohi ココヒ](https://twitter.com/kokohi5586) 10 | -------------------------------------------------------------------------------- /assets/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/assets/android-chrome-192x192.png -------------------------------------------------------------------------------- /assets/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/assets/android-chrome-256x256.png -------------------------------------------------------------------------------- /assets/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/assets/apple-touch-icon.png -------------------------------------------------------------------------------- /assets/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /assets/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/assets/favicon-16x16.png -------------------------------------------------------------------------------- /assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/assets/favicon-32x32.png -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/assets/favicon.ico -------------------------------------------------------------------------------- /assets/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/assets/mstile-150x150.png -------------------------------------------------------------------------------- /assets/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 15 | 19 | 22 | 32 | 121 | 122 | 124 | 130 | 133 | 134 | 135 | 136 | 139 | 140 | 141 | 143 | 145 | 146 | 147 | 151 | 153 | 155 | 156 | 158 | 159 | 163 | 165 | 166 | 168 | 169 | 172 | 175 | 179 | 182 | 186 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /css/asacoco.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'cwTeXKai'; 3 | font-style: normal; 4 | font-weight: 500; 5 | src: url(//fonts.gstatic.com/ea/cwtexkai/v3/cwTeXKai-zhonly.eot); 6 | src: url(//fonts.gstatic.com/ea/cwtexkai/v3/cwTeXKai-zhonly.eot?#iefix) format('embedded-opentype'), 7 | url(//fonts.gstatic.com/ea/cwtexkai/v3/cwTeXKai-zhonly.woff2) format('woff2'), 8 | url(//fonts.gstatic.com/ea/cwtexkai/v3/cwTeXKai-zhonly.woff) format('woff'), 9 | url(//fonts.gstatic.com/ea/cwtexkai/v3/cwTeXKai-zhonly.ttf) format('truetype'); 10 | } 11 | 12 | @font-face { 13 | font-family: 'hkkaikk'; 14 | src: url(../fonts/hkkaikk.ttf); 15 | } 16 | 17 | @font-face { 18 | font-family: 'Archicoco'; 19 | font-style: normal; 20 | font-weight: normal; 21 | src: local('Archicoco Regular'), url(../fonts/Archicoco.woff) format('woff'); 22 | } 23 | 24 | canvas { 25 | width: 80%; 26 | max-width: 500px; 27 | margin: 0 auto; 28 | } 29 | 30 | @font-face { 31 | font-family: 'SweiSans'; 32 | src: url(https://cdn.jsdelivr.net/gh/max32002/swei-sans@2.101/WebFont/CJK%20TC/SweiSansCJKtc-Regular.woff2) format("woff2"), 33 | url(https://cdn.jsdelivr.net/gh/max32002/swei-sans@2.101/WebFont/CJK%20TC/SweiSansCJKtc-Regular.woff) format("woff"); 34 | } 35 | 36 | #bg { 37 | width: 100vw; 38 | height: 100vh; 39 | position: fixed; 40 | background-attachment: fixed; 41 | background-image: url(../images/background.jpg); 42 | background-repeat: no-repeat; 43 | background-size: cover; 44 | background-position: center; 45 | filter: brightness(.3); 46 | z-index: -1; 47 | top: 0; 48 | } 49 | 50 | #app { 51 | display: flex; 52 | justify-content: center; 53 | align-items: center; 54 | } 55 | 56 | body { 57 | width: 100vw; 58 | overflow-x: hidden; 59 | height: 100vh; 60 | cursor: url(../images/cursor.png) 0 0, auto !important; 61 | } 62 | 63 | #footer a{ 64 | text-decoration: none; 65 | color: white; 66 | font-weight: bold; 67 | } 68 | 69 | #tab li { 70 | border-radius: 5px; 71 | } 72 | 73 | #tab a { 74 | color: white; 75 | text-decoration: none; 76 | } 77 | 78 | #tab li.active { 79 | background: white; 80 | color: black; 81 | } 82 | 83 | #tab li.active a, 84 | #tab li.active svg { 85 | color: black !important; 86 | } 87 | 88 | .fade-enter-active, .fade-leave-active { 89 | transition: opacity .5s ease; 90 | } 91 | 92 | .fade-enter-from, .fade-leave-to { 93 | opacity: 0; 94 | } 95 | -------------------------------------------------------------------------------- /fonts/Archicoco.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/fonts/Archicoco.woff -------------------------------------------------------------------------------- /fonts/hkkaikk.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/fonts/hkkaikk.ttf -------------------------------------------------------------------------------- /images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/images/background.jpg -------------------------------------------------------------------------------- /images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/images/cursor.png -------------------------------------------------------------------------------- /images/default_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/images/default_avatar.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/images/logo.png -------------------------------------------------------------------------------- /images/templates/ACU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/images/templates/ACU.png -------------------------------------------------------------------------------- /images/templates/science.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/images/templates/science.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | Asacoco Generator 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |
52 |
53 |
54 |
55 | 56 |

ASACOCO GENERATOR

57 |
58 | 78 |
79 |
80 |
81 |
82 | 83 | 84 |
85 |
86 | 87 | 88 |
89 |
90 | 91 | 92 |
93 |
94 | 95 |
96 | 97 | 101 |
102 |
103 | 104 |

105 | 106 |

107 |

108 | Designed by 109 | 110 | YoYa 111 | 112 |

113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | 121 | 122 |
123 |
124 | 125 | 126 |
127 |
128 | 129 | 130 |
131 |
132 | 133 |
134 | 135 | 139 |
140 |
141 | 142 |

143 | 144 |

145 |

146 | Designed by 147 | 148 | KoKohi ココヒ 149 | 150 |

151 |
152 |
153 |
154 | 177 |
178 |
179 |
180 | 181 | 182 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /js/app.js: -------------------------------------------------------------------------------- 1 | const { ref, onMounted, onUpdated } = Vue 2 | 3 | const app = Vue.createApp({ 4 | setup(props, context) { 5 | // mode 6 | // 0 = student 7 | // 1 = science club 8 | const mode = ref(0) 9 | const input = ref({ 10 | id: 'A2020000001', 11 | name: '桐生ココ', 12 | dep: '一擊必殺科', 13 | avatar: null, 14 | lab: '01' 15 | }) 16 | let canvas = null 17 | let ctx = null 18 | let templates = [] 19 | 20 | const date = new Date() 21 | const dateText = ref(date.toISOString().split('T')[0].replace(/-/g, '/')) 22 | const dateYear = ref(date.getFullYear()) 23 | 24 | const selectMode = (value, e) => { 25 | e.preventDefault() 26 | mode.value = value 27 | location.hash = '#mode' + value 28 | } 29 | 30 | const handleFile = (e) => { 31 | const reader = new FileReader() 32 | input.value.file = e.target.files[0] 33 | reader.onload = (ee) => { 34 | const img = new Image() 35 | img.onload = () => { 36 | refresh() 37 | } 38 | img.src = ee.target.result 39 | input.value.avatar = img 40 | } 41 | reader.readAsDataURL(e.target.files[0]) 42 | } 43 | 44 | const refresh = () => { 45 | switch(mode.value) { 46 | case 0: 47 | ctx.font = '50px Arial' 48 | // Clear 49 | ctx.clearRect(0, 0, canvas.width, canvas.height) 50 | // Background 51 | ctx.drawImage(templates[0], 0, 0) 52 | // Draw Texts 53 | const fonts = 'dfkai-sb, KaiTi, stkaiti, 標楷體, 华文楷体, cwTeXKai, Arial, cursive, "Ma Shan Zheng", hkkaikk' 54 | colorText(input.value.id, canvas.width/2 + 450, 500, 'black', '60px ' + fonts, 'center') 55 | colorText(input.value.dep, canvas.width/2 + 450, 670, 'black', '120px ' + fonts, 'center') 56 | colorText(input.value.name, canvas.width/2 + 390, 950, 'black', '170px ' + fonts, 'center') 57 | // Draw avatar 58 | if(input.value.avatar) { 59 | const ratio = 600 / input.value.avatar.width 60 | ctx.save() 61 | roundedImage(120, 430, 600, input.value.avatar.height * ratio, 30) 62 | ctx.clip() 63 | ctx.drawImage(input.value.avatar, 120, 430, 600, input.value.avatar.height * ratio) 64 | ctx.restore() 65 | } 66 | break 67 | case 1: 68 | // Clear 69 | ctx.clearRect(0, 0, canvas.width, canvas.height) 70 | // Background 71 | ctx.drawImage(templates[1], 0, 0) 72 | // Draw Texts 73 | colorText(input.value.name, 570, 280, 'white', '35px SweiSans', 'start') 74 | colorText(input.value.id, 475, 330, 'white', '35px SweiSans', 'start') 75 | colorText(input.value.lab, 760, 468, 'white', '70px Archicoco', 'start') 76 | // Draw avatar 77 | if(input.value.avatar) { 78 | const ratio = 300 / input.value.avatar.width 79 | ctx.save() 80 | roundedImage(50, 80, 300, input.value.avatar.height * ratio, 15) 81 | ctx.clip() 82 | ctx.drawImage(input.value.avatar, 50, 80, 300, input.value.avatar.height * ratio) 83 | ctx.restore() 84 | } 85 | break 86 | } 87 | } 88 | 89 | const colorText = (text, x, y, color, font, align) => { 90 | ctx.font = font 91 | ctx.textAlign = align 92 | ctx.fillStyle = color 93 | ctx.fillText(text, x, y) 94 | } 95 | 96 | const download = () => { 97 | const link = document.createElement('a') 98 | link.download = 'Asacoco.png' 99 | link.href = canvas.toDataURL() 100 | link.click() 101 | } 102 | 103 | const loadImage = (url) => { 104 | return new Promise((resolve) => { 105 | const image = new Image() 106 | image.onload = () => { 107 | resolve(image) 108 | } 109 | image.src = url 110 | }) 111 | } 112 | 113 | const roundedImage = (x, y, width, height, radius) => { 114 | ctx.beginPath() 115 | ctx.moveTo(x + radius, y) 116 | ctx.lineTo(x + width - radius, y) 117 | ctx.quadraticCurveTo(x + width, y, x + width, y + radius) 118 | ctx.lineTo(x + width, y + height - radius) 119 | ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height) 120 | ctx.lineTo(x + radius, y + height) 121 | ctx.quadraticCurveTo(x, y + height, x, y + height - radius) 122 | ctx.lineTo(x, y + radius) 123 | ctx.quadraticCurveTo(x, y, x + radius, y) 124 | ctx.closePath() 125 | } 126 | 127 | onMounted(async () => { 128 | await document.fonts.load('10pt "Ma Shan Zheng"') 129 | await document.fonts.load('10pt cwTeXKai') 130 | await document.fonts.load('10pt hkkaikk') 131 | await document.fonts.load('10pt Archicoco') 132 | await document.fonts.load('10pt SweiSans') 133 | templates[0] = await loadImage('./images/templates/ACU.png') 134 | templates[1] = await loadImage('./images/templates/science.png') 135 | input.value.avatar = await loadImage('./images/default_avatar.png') 136 | const id = parseInt(location.hash.slice(1).replace('mode', '')) 137 | if(!isNaN(id) && id < 2) mode.value = id 138 | else location.hash = '#mode0' 139 | canvas = document.querySelectorAll('.canvas')[mode.value] 140 | ctx = canvas.getContext('2d') 141 | refresh() 142 | }) 143 | 144 | onUpdated(() => { 145 | canvas = document.querySelectorAll('.canvas')[mode.value] 146 | ctx = canvas.getContext('2d') 147 | refresh() 148 | }) 149 | 150 | return { 151 | mode, 152 | input, 153 | canvas, 154 | ctx, 155 | dateText, 156 | dateYear, 157 | selectMode, 158 | handleFile, 159 | refresh, 160 | date, 161 | download 162 | } 163 | } 164 | }).mount('#app') -------------------------------------------------------------------------------- /pwabuilder-sw.js: -------------------------------------------------------------------------------- 1 | importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js'); 2 | 3 | const CACHE = "pwabuilder-page"; 4 | 5 | const offlineFallbackPage = "index.html"; 6 | 7 | self.addEventListener("message", (event) => { 8 | if (event.data && event.data.type === "SKIP_WAITING") { 9 | self.skipWaiting(); 10 | } 11 | }); 12 | 13 | self.addEventListener('install', async (event) => { 14 | event.waitUntil( 15 | caches.open(CACHE) 16 | .then((cache) => cache.add(offlineFallbackPage)) 17 | ); 18 | }); 19 | 20 | if (workbox.navigationPreload.isSupported()) { 21 | workbox.navigationPreload.enable(); 22 | } 23 | 24 | self.addEventListener('fetch', (event) => { 25 | if (event.request.mode === 'navigate') { 26 | event.respondWith((async () => { 27 | try { 28 | const preloadResp = await event.preloadResponse; 29 | 30 | if (preloadResp) { 31 | return preloadResp; 32 | } 33 | 34 | const networkResp = await fetch(event.request); 35 | return networkResp; 36 | } catch (error) { 37 | 38 | const cache = await caches.open(CACHE); 39 | const cachedResp = await cache.match(offlineFallbackPage); 40 | return cachedResp; 41 | } 42 | })()); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogeraabbccdd/Asacoco-Generator/0740863f9e3d0f39f3beb0f8c58015c1240b422b/screenshot.png -------------------------------------------------------------------------------- /site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Asacoco Generator", 3 | "short_name": "Asacoco", 4 | "start_url": "./index.html", 5 | "icons": [ 6 | { 7 | "src": "./assets/android-chrome-192x192.png", 8 | "sizes": "192x192", 9 | "type": "image/png" 10 | }, 11 | { 12 | "src": "./assets/android-chrome-256x256.png", 13 | "sizes": "256x256", 14 | "type": "image/png" 15 | } 16 | ], 17 | "theme_color": "#ffffff", 18 | "background_color": "#ffffff", 19 | "display": "standalone" 20 | } 21 | --------------------------------------------------------------------------------