12월에 저는 Firefox의 테마 API에 대한 소개를 했습니다. 이는 animated themes, macOS-style overscroll 또는 interactive theme editors와 같은 많은 것들을 할 수 있게 해주지만 몇 가지 한계가 있습니다. 전통적인 CSS와 비교해서 동적 테마 API의 한 가지 문제는 기본 동적 테마를 만들기 위해선 JavaScript와 WebExtension API를 알아야 한다는 점입니다.
이 문제를 해결하기 위해 간단한 테마 “규칙”을 사용하여 동적 테마를 사용하는 간단한 시스템으로 실험을 진행하였습니다. “규칙”은 테마 이름 쌍을 나타내는 JavaScript 조건 문자열로 구성되어 있습니다. 여기 있습니다: https://github.com/nt1m/theming-rules
이 boilerplate는 WebExtension 리스너를 설정하고 다른 API와 연동하기 위해 동적 테마에 필요한 모든 복잡한 작업을 처리하여 우리가 동적 테마 설정에 집중할 수 있게 해줍니다.
위의 저장소를 클론하여 시작합시다. 모든 설정은 boilerplate의 config.js
파일에 위치합니다. 이 파일을 열면 아래와 같은 코드를 보시게 될 것입니다:
// The default theme: used when no rule is matched
const DEFAULT_THEME = "bright";
// The theming rules: priority is given to the bottom-most rule
const RULES = [
["privatebrowsing", "shady"],
["(hour >= 21) || (hour < 9)", "shady"]
];
이런 경우, “shady” 테마는 사생활 보호 탭에서 저녁 9시부터 아침 9시까지 사용됩니다. 다른 모든 경우에서는 “bright” 기본 테마가 사용됩니다.
좀 더 복잡하게 config.js
파일을 수정해 봅시다:
// The default theme: used when no rule is matched
onst DEFAULT_THEME = "bright";
// The theming rules: priority is given to the bottom-most rule
const RULES = [
["privatebrowsing", "shady"],
["(hour >= 21) || (hour < 9)", "shady"],
["privatebrowsing && ((hour >= 21) || (hour < 9))", "bright"]
];
어떤 동작을 할지 예상이 되십니까?
힌트입니다: 규칙에는 “우선순위” 개념이 있어, 하나 이상의 규칙이 만족하면 가장 아래의 규칙이 사용됩니다.
이 경우에는, “bright” 테마는 밤 시간의 사생활 보호 창과 낮 시간 동안에 사용됩니다. “shady” 테마는 낮 시간의 사생활 보호 창과 밤 시간에 사용됩니다. 휴!
사용하실 수 있는 몇 가지 프로퍼티가 더 있습니다:
- inactive_window
- privatebrowsing
- container
- domain
- protocol
- year
- month
- date
- day
- hour
- minutes
- seconds
이 글의 후반부에서 여러분만의 프로퍼티를 정의하는 방법을 알려드리겠습니다.
이전 예제에서 사용된 “bright”와 “shady” 테마를 포함해, 이런 테마들은 표준 WebExtension 테마 형식으로 정의되어 있고, config.js
파일에도 있습니다:
const THEMES = {
bright: {
images: {
headerURL: ""
},
colors: {
accentcolor: "#dedede",
textcolor: "#000",
toolbar_text: "#000",
toolbar: "#f8f8f8",
}
},
shady: {
images: {
headerURL: ""
},
colors: {
accentcolor: "#000",
textcolor: "#ddd",
toolbar_text: "#ccc",
toolbar: "#3a3a3a"
}
}
};
유즈 케이스: 프로토콜 기반 브라우저 스타일링
이제 시스템에 대한 소개를 했으니, 유용한 예제를 만들어 봅시다: 현재 탭이 HTTP 페이지인지 HTTPS 페이지인지 여부에 따라 브라우저를 스타일링 해봅시다.
먼저 HTTP와 HTTPS 테마의 외관을 정의할겁니다. HTTP 사이트는 빨강, HTTPS 사이트는 초록을 사용합시다:
insecure: {
images: {
headerURL: ""
},
colors: {
accentcolor: "red",
textcolor: "black",
toolbar: "pink",
toolbar_text: "black"
}
},
secure: {
images: {
headerURL: ""
},
colors: {
accentcolor: "green",
textcolor: "white",
toolbar: "lightgreen",
toolbar_text: "black"
}
}
이제 규칙을 정의합시다:
// The default theme: used when no rule is matched
const DEFAULT_THEME = "bright";
// The theming rules: priority is given to the bottom-most rule
const RULES = [
["protocol == 'http:'", "insecure"],
["protocol == 'https:'", "secure"]
];
…됐습니다! “bright”를 기본 테마로 유지하고 있는것에 유의하시기 바랍니다. 이는 file://
와 같이 extension에 테마가 적용되지 않는 다른 프로토콜이 존재하기 때문입니다.
예제는 다음과 같이 나타납니다:
더 많은 프로퍼티 추가하기
여러분은 특별한 키워드인 privatebrowsing
, hour
그리고 protocol
를 알아채셨을 수도 있습니다. 이는 내장된 프로퍼티이며 다음과 같은 형태로 정의되어 있습니다:
privatebrowsing: {
type: "boolean",
async get(tab) {
return tab.incognito;
}
},
protocol: {
type: "string",
async get(tab) {
return new URL(tab.url).protocol;
}
},
hour: {
type: "integer",
async get(tab) {
return (new Date(Date.now())).getHours();
}
}
각 프로퍼티 정의는 WebExtension Tab
object (무시하도록 선택 가능)를 사용하며, 하나의 값을 반환합니다.
모든 내장 프로퍼티 정의는 properties.js
파일에서 확인하실 수 있습니다.
여러분만의 프로퍼티 추가를 원하십니까? 프로퍼티 추가는 프로퍼티 정의 추가와 같이 간단합니다. 쿠키 API를 사용하여 현재 탭 도메인에 대한 쿠키의 수를 반환하는 에제입니다:
cookies: {
type: "integer",
async get(tab) {
let cookies = await browser.cookies.getAll({
domain: new URL(tab.url).hostname
});
return cookies.length;
}
}
쿠키의 수에 따라 탭의 스타일을 다르게 설정하도록 활용할 수 있습니다.
프로퍼티 정의는 아주 유연하며, XHR을 통해 현재 날씨를 반환하거나 페이지의 추적자수를 반환하는 프로퍼티를 설정할수도 있습니다. 이는 여러분의 상상에 달려있습니다 🙂
한번 시도해보세요!
WebExtinsion API에 대한 깊은 지식을 필요로하지 않는 동적 테마를 생성하는 아주 간단한 방법이 필요하든, 상황별 UI 기능을 빠르게 프로토타이핑하기 위한 간단한 방법이 필요하든, 이는 여러분에게 가장 적합한 도구입니다!
이 시스템을 사용하는데에는 아주 많은 가능성이 있으며, 여러분이 무엇을 만들어 낼 수 있을지 기대됩니다.
저장소입니다: https://github.com/nt1m/theming-rules.
댓글이나 Github 이슈에 여러분의 경험을 자유롭게 공유해주세요.
이 글은 Tim Nguyen의 A rule-based framework to create dynamic themes의 한국어 번역입니다.
작성자: Seul Gi Choi
Open Source // Web // Javascript // Map engineer
댓글이 없습니다.