LiveTRA 火車時刻表 UI 設計

LiveTRA 是我的一個 side project,開始的契機是某個時期,因時常搭乘台鐵通勤,而台鐵又經常誤點,想說如果可以在出門前就可以先得知月台上的誤點時間,就可以避免匆匆忙忙趕到車站後才發現原來列車誤點的窘況。

Google了一下馬上就找到了當時由交通部主催的「公共運輸整合資訊流通服務平台 (PTX)」API服務(目前已整合進 「運輸資料流通服務 (TDX)」),很快地就做出了第一版,以下是當時第一版的畫面設計。

舊版車站頁
舊版列車頁

舊版的頁面結構中沒有首頁,以台北車站做為預設車站當作首頁。一旦選擇過車站後,便以上一次選擇的車站當作預設顯示車站。且因為想把車站選擇器順便當作標題使用,因此將車站選擇器放在頁面最上面。

當這個版本運行一陣子後,意外地還蠻多人用的,並且收到了一些反饋,同時也因為想優化整個網站的架構,因此做了改版。

新版首頁與車站頁設計

首頁
車站頁

這個版本出現了首頁,首頁會顯示最後兩次選擇的車站的最近一班列車,以及一些子功能的入口。例如:語系選擇、誤點班次列表、列車誤點賠償規則、最近使用車站、熱門車站⋯等等。

閱讀全文 LiveTRA 火車時刻表 UI 設計

關於 vite 與 webpack 的檔案分割

之前一直很好奇 nuxt 是怎麼做到分割檔案的,但一直沒有時間來好好研究。上網搜尋一下之後,得知原來就跟寫 vue-router 想要 lazy load 的時候一樣,只要不用 import xxx from 'xxx' 匯入,而是改用 import('xxx') 的方式匯入,就會被自動分割,達成在需要的時候才 import 的目的,也就是 component 的 lazy loading。

例如當我們在 vue3 裡要宣告一個 component 的時候可以用:const xxx = defineAsyncComponent(() => import('xxx'))

以下的描述是單純以 vite or webpack 來打包程式碼的情況,而非 nuxt。

因此這個 import() 就是關鍵之處。平常較為人知的 import 是只能在一個檔案的最上頭,並且是以 import xxx from 'xxx' 這樣的形式使用。不過以這種方式 import 的話,全部的 code 將都會被打包在一起,output 到你設定的路徑。

閱讀全文 關於 vite 與 webpack 的檔案分割

[單字筆記] Web工程師相關日文單字

因爲本身是Web前端工程師,常常在查找文件或技術文章時,如果中文英文找不到需要的資訊時,也會試試看用日文來找。這時候就會接觸到一些與程式相關的日文單字,以下整理了一些實用且常看到的單字,之後如果有新增也會在這篇更新。

閱讀全文 [單字筆記] Web工程師相關日文單字

[css筆記] 多行的情況下使用刪節號

上次介紹過如何在表格中使用刪節號,然而之前介紹的這個刪節號的方式,因搭配white-space: nowrap,使得我們使用刪節號會被限制在一行內。這次想要介紹的是在多行的情況下使用刪節號。

這次會使用到的屬性或值會需要加上 webkit prefix,分別是:display: -webkit-box,-webkit-line-clamp: 2, -webkit-box-orient: vertical,因為都還不是標規,亦或者是已經在css level3中有制定,但各家瀏覽器還是暫時只支援加上prefix的版本。例如 line-clamp,我們用caniuse查一下,可以看到他已經制定了,但不管是在edge, firefox, safari, chrome等等的瀏覽器,都還是必須加上prefix。

我們要做的很簡單,就是把 white-space: nowrap 拿掉,原本的 overflow: hidden; text-overflow: ellipsis; 保留,並加上 display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; 即可。

以下來解釋一下個屬性或值的意義。

display: -webkit-box; 其實就是個跟 display: flex 類似的東西,都是讓你可以做彈性編排的屬性值。但在此如果我們換成 flex,刪節號會失效。

-webkit-line-clamp 用於限制內文行數。

-webkit-box-orient: vertical; 以垂直 (vertical) 還是水平 (horizontal) 的方式排列內容

以下是範例程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .text {
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
    }
  </style>
</head>
<body>
  <div class="text">
    最後,當他們回到了小咖啡的家中時,天已經亮了。小咖啡感激地對彩虹說:“謝謝你陪我一起冒險,如果沒有你,我可能永遠都找不到回家的路。”而彩虹笑著回答說:“沒關係,朋友就應該互相幫助。”他們相擁而睡,帶著對未來的無限期待。小雨班聽完這個故事後,眼皮漸漸變得沉重,他靜靜地閉上了眼睛,腦海中充滿了對動物冒險的美好幻想。最後,他甜甜地入睡了,做著美好的夢境。
  </div>
</body>
</html>

[css筆記] 在表格中使用刪節號 css text-overflow: ellipsis

下圖是最終我們希望得到的結果:當表格中的 text 2 欄位文字過長時,可以被自動截斷,並加上刪節號。不過在實作的過程中,有遇到一些問題。以下是遇到的問題與解決方式:

首先,我們先做一個表格,外觀與程式碼如下:

閱讀全文 [css筆記] 在表格中使用刪節號 css text-overflow: ellipsis

日文AI歌聲生成NEUTRINO手把手教學

之前介紹過中文歌聲生成AI「雅婷」還沒看過的傳送門在此。今天要介紹的是日文版的雅婷「NEUTRINO」。他的功能基本上就跟雅婷一樣,也完全免費,還有免費的多組聲音model可選,實在是非常佛心來的。但也有個小缺點,就是必須下載,且沒有圖形介面,只能透過終端機 command line 來下指令。

閱讀全文 日文AI歌聲生成NEUTRINO手把手教學

AdSense 新加坡稅務資訊相關申請與設定教學

最近 Google AdSense 開始要台灣的 AdSense 使用者提交新加坡稅務資訊了。這是因為台灣的 AdSense 是透過 Google Asia 付款,而他們的地點設在新加坡。目前新加坡似乎還尚未開始扣稅,但如果之後法律要求預扣稅款,支付的款項可能會扣除較高的扣繳稅額。

先說一下,雖然不是很複雜,但整個過程其實需要點時間,主要是因為需要跟國稅局申請「稅務居住地證明」這個文件,且每年需要重新申請並去Adsense更新。以下就是整個申請與設定流程:

先到財政部稅務入口網,填寫申請表格。可以選要用自然人憑證登入或是以健保卡登入。

閱讀全文 AdSense 新加坡稅務資訊相關申請與設定教學

判斷上傳的圖片格式

當我們想要限制上傳檔案的格式時,最簡單的方式是檢查副檔名或Mime types,不過如果該檔案被更改過副檔名的話,這個檢查就沒意義了。好在我們可以透過各種檔案格式的「魔術數字」來檢查該檔案的內容是否真的符合副檔名所對應的格式。

閱讀全文 判斷上傳的圖片格式

用 color-mix() 處理CSS原生變數的顏色透明度

以往如果我們要在 css 中,對一個顏色變數做透明度處理,第一個想到的應該是透過 sass 的 color module 來處理。但如果我們是要在 runtime 處理一個 css 的原生變數呢?可能會有人想到把 rgb 拆成三個變數,再透過 rgba(var(–r), var(–g), var(–b), 0.5) 這種形式來改變透明度,相同的原理也能套用到 hsla 等等的 css 色彩函式中。

拆開變數的這個做法雖然可行,且在應用上可以很靈活,但同時也增加了變數的數量、造成閱讀與維護時的難度。

這時候不妨試試看 color-mix 函數來對顏色做透明度處理,且除了透明度以外,color-mix 其實本來是用來混合兩個顏色用的。且目前看起來各瀏覽器已經都普遍支援了(除了IE,但現在還有誰管它),請放心使用。

目前已經普遍支援各瀏覽器
閱讀全文 用 color-mix() 處理CSS原生變數的顏色透明度

用 View Transitions API 快速做出有趣的換頁動態吧

如果有在做 Native-like 的 Web Application 的人,應該都曾為了要做到像是 Native 的頁面轉換動態而絞盡腦汁。現在 View Transitions API 提供一種輕鬆創建不同 DOM 狀態之間的動畫轉換的機制。該 API 目前只能用於單一頁面中的 DOM 狀態轉換,但正在計劃支援於同 Domain 的不同頁面間的轉換。目前(2023/09)雖然僅有 Chrome, Edge, Opera 三個瀏覽器支援,但相信未來勢必會成為做動態時很重要的一環。

目前僅Chrome, Edge, Opera 三個瀏覽器支援
閱讀全文 用 View Transitions API 快速做出有趣的換頁動態吧

自動更新 Linode Object Storage SSL/TLS憑證

前一篇文章,我們了解了如何自訂Linode Object Storage的網域,但因Object Storage需要自己手動上傳SSL憑證,且Let’s Encrypt的憑證90天會到期,因此每到即將過期的時間,勢必就得再手動更新一次。因此,這篇就要繼續來了解,如何自動更新憑證。

閱讀全文 自動更新 Linode Object Storage SSL/TLS憑證

Linode Object Storage 自訂網域設定與大阪region Cyberduck設定

Custom Domain 步驟

開好 Linode 的 Object Storage 之後,常常覺得網址有夠長,查了一下自訂網域的方式。跟 AWS 比起來麻煩多了,還要自己用 Certbot 手動建立 ssl 憑證,而這也意味著會遇到無法自動更新憑證的問題。之後會再介紹用 API 更新憑證的方法,這篇的重點就先放在整個設定的步驟。

閱讀全文 Linode Object Storage 自訂網域設定與大阪region Cyberduck設定

[筆記] Critical Render Path 與 Reflow, Repaint

Critical Render Path

讀取 html => 產生 DOM Tree => 產生 CSSOM Tree => 產生 Render Tree => Layout => Paint => Compositing

Layout做的事情

依照樣式表與元素的可視與否,計算每個元素的尺寸、位置

Paint做的事情

繪製每個Layout的文字、顏色、圖片、透明度、transform。也就是把Layout轉為實際視覺上的結果。

Compositing做的事情

將所有的Layout組合起來

閱讀全文 [筆記] Critical Render Path 與 Reflow, Repaint

Nuxt Hydration Fails – SSR與CSR的比對錯誤

在 Nuxt 中,當我們 refresh 頁面時,寫在 data 或 computed 中的程式碼,在 server 端與 client 端都會各執行一次,並且在前端會進行html tag的比對,若兩者不相符會噴錯,甚至沒有辦法進行接下來的操作。

因此,當我們用了 new Date().getTime(), Math.random() 這類的程式碼在data中,是一定會造成錯誤的。甚至 new Date().getDay() 也是有可能,因為 server time 有很大的可能性,跟 client 端的時區不同。最後我們再來看看如何解決,我們先來看看相同的程式碼,在 Nuxt2 與 Nuxt3 分別會導出怎樣的結果。

閱讀全文 Nuxt Hydration Fails – SSR與CSR的比對錯誤

PM2 watch 造成的無限迴圈

pm2 的 watch 是用於監聽檔案變動,自動重啟服務的一個功能。我們可以透過在 pm2.config.js 檔案中設定 watch: true 來開啟此功能。這樣一旦進了新 code 就會自動重啟,不用手動 pm2 restart {id} 非常方便。

但也就是因為這麼方便,所以常常會忘了他的存在。

前陣子做了一個透過排程,自動到某處去下載json檔案回來存放,再提供一隻API來吐出篩選過的資料的小工具。在開發環境完成後,一樣就很順手的在正式環境用PM2跑起來。

閱讀全文 PM2 watch 造成的無限迴圈