>>16,t[1],t[0]<<16|t[3]>>>16,t[2],t[1]<<16|t[0]>>>16,t[3],t[2]<<16|t[1]>>>16],i=this._C=[t[2]<<16|t[2]>>>16,4294901760&t[0]|65535&t[1],t[3]<<16|t[3]>>>16,4294901760&t[1]|65535&t[2],t[0]<<16|t[0]>>>16,4294901760&t[2]|65535&t[3],t[1]<<16|t[1]>>>16,4294901760&t[3]|65535&t[0]],n=this._b=0;n<4;n++)Mt.call(this);for(n=0;n<8;n++)i[n]^=r[n+4&7];if(e){var o=e.words,s=o[0],c=o[1],a=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),h=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),l=a>>>16|4294901760&h,f=h<<16|65535&a;i[0]^=a,i[1]^=l,i[2]^=h,i[3]^=f,i[4]^=a,i[5]^=l,i[6]^=h,i[7]^=f;for(n=0;n<4;n++)Mt.call(this)}},_doProcessBlock:function(t,e){var r=this._X;Mt.call(this),Bt[0]=r[0]^r[5]>>>16^r[3]<<16,Bt[1]=r[2]^r[7]>>>16^r[5]<<16,Bt[2]=r[4]^r[1]>>>16^r[7]<<16,Bt[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)Bt[i]=16711935&(Bt[i]<<8|Bt[i]>>>24)|4278255360&(Bt[i]<<24|Bt[i]>>>8),t[e+i]^=Bt[i]},blockSize:4,ivSize:2}),vt.RabbitLegacy=yt._createHelper(St),bt.pad.ZeroPadding={pad:function(t,e){var r=4*e;t.clamp(),t.sigBytes+=r-(t.sigBytes%r||r)},unpad:function(t){var e=t.words,r=t.sigBytes-1;for(r=t.sigBytes-1;0<=r;r--)if(e[r>>>2]>>>24-r%4*8&255){t.sigBytes=r+1;break}}},bt});
--------------------------------------------------------------------------------
/assets/js/custom.js:
--------------------------------------------------------------------------------
1 | var userAgent = navigator.userAgent;
2 | var API_BASE_URL = 'lecdapi.111533.xyz';
3 | var App_Key = '7iudhWquXYN0uToAuxseBFJe'
4 | var App_ID = 'XsJ7yqBSeG6Mu9ItZBjeKmuy-MdYXbMMI'
5 |
6 | // 判断是否在微信内
7 | if (userAgent.indexOf("MicroMessenger") !== -1) {
8 | document.getElementById("wxtips").textContent = "长按图片,点击识别图中二维码/赞赏码"
9 | document.getElementById("alitips").textContent = "点击右上角,选择在(默认)浏览器中打开"
10 | document.getElementById("btctips").textContent = "点击右上角,选择在(默认)浏览器中打开"
11 | }
12 |
13 | // 判断是否为Android设备
14 | else if (userAgent.indexOf("Android") !== -1) {
15 | document.getElementById("myLink").href = "weixin://";
16 | document.getElementById("wxtips").textContent = "长按图片保存本地,点击图片打开微信,点击右上角扫一扫,选择相册并选择刚才保存的图片"
17 | document.getElementById("alitips").textContent = "点击图片一键施舍"
18 | document.getElementById("btctips").textContent = "点击图片一键施舍"
19 | }
20 |
21 | // 判断是否为iOS设备
22 | else if (userAgent.indexOf("iPhone") !== -1 || userAgent.indexOf("iPad") !== -1 || userAgent.indexOf("iPod") !== -1) {
23 | document.getElementById("myLink").href = "weixin://scanqrcode";
24 | document.getElementById("wxtips").textContent = "长按图片保存本地,点击图片打开微信,点击相册并选择刚才保存的图片"
25 | document.getElementById("alitips").textContent = "点击图片一键施舍"
26 | document.getElementById("btctips").textContent = "点击图片一键施舍"
27 | }
28 |
29 | // 其他设备
30 | else {
31 | document.getElementById("myLink").href = window.location.href;
32 | }
33 |
34 | // 获取表单元素
35 | var form = document.getElementById('myForm');
36 |
37 | // 监听表单提交事件
38 | form.addEventListener('submit', function (event) {
39 | event.preventDefault(); // 阻止表单默认提交行为
40 |
41 | // 获取表单字段的值
42 | var name = form.name.value;
43 | var pay = form.pay.value;
44 | var amount = parseFloat(form.amount.value);
45 | var message = form.message.value;
46 |
47 | // 创建一个空的对象来存储错误信息
48 | var errors = {};
49 |
50 | // 校验字段的值
51 | if (name === '') {
52 | errors.name = '请输入您的昵称';
53 | } else if (name.length > 100) {
54 | errors.name = '昵称长度不能超过100个字符';
55 | }
56 |
57 | if (pay === '') {
58 | errors.pay = '请选择微信或支付宝';
59 | }
60 |
61 | if (pay === 'BTC') {
62 | // 如果选择为 BTC,则将金额乘以 10^8 来转换为聪
63 | const satoshiAmount = amount * Math.pow(10, 8);
64 | if (isNaN(amount) || satoshiAmount < 1 || satoshiAmount > 9999999999999) {
65 | errors.amount = '请输入有效的施舍金额(0.00000001 - 99999.99999999 BTC)';
66 | }
67 | } else {
68 | if (isNaN(amount) || amount < 0.01 || amount > 9999999) {
69 | errors.amount = '请输入有效的施舍金额(0.01 - 9999999)';
70 | }
71 | }
72 |
73 | if (message.length > 500) {
74 | errors.message = '留言长度不能超过500个字符';
75 | }
76 |
77 | // 显示错误提示
78 | showErrors(errors);
79 |
80 | // 如果没有错误,则提交表单
81 | if (Object.keys(errors).length === 0) {
82 | submitForm();
83 | }
84 | });
85 |
86 | // 显示错误提示
87 | function showErrors(errors) {
88 | // 清除之前的错误提示
89 | clearErrors();
90 |
91 | // 遍历错误对象,显示错误消息
92 | for (var field in errors) {
93 | if (errors.hasOwnProperty(field)) {
94 | var errorMessage = errors[field];
95 | var errorElement = document.createElement('div');
96 | errorElement.className = 'error-message';
97 | errorElement.textContent = errorMessage;
98 | form[field].classList.add('error');
99 | form[field].parentNode.appendChild(errorElement);
100 | }
101 | }
102 | }
103 |
104 | // 清除错误提示
105 | function clearErrors() {
106 | var errorMessages = form.getElementsByClassName('error-message');
107 | var fields = form.getElementsByClassName('error');
108 |
109 | while (errorMessages.length > 0) {
110 | errorMessages[0].parentNode.removeChild(errorMessages[0]);
111 | }
112 |
113 | for (var i = 0; i < fields.length; i++) {
114 | fields[i].classList.remove('error');
115 | }
116 | }
117 |
118 | // 提交表单
119 | function submitForm() {
120 | // 构建JSON对象
121 | var data = {
122 | name: form.name.value,
123 | pay: form.pay.value,
124 | amount: parseFloat(form.amount.value),
125 | message: form.message.value
126 | };
127 |
128 | // 要计算签名的数据
129 | const timestamp = Date.now();
130 | const md5data = timestamp + App_Key
131 | // 计算MD5签名
132 | const sign = CryptoJS.MD5(md5data).toString();
133 | // 发送POST请求
134 | fetch('https://' + API_BASE_URL + '/1.1/classes/yfdata', {
135 | method: 'POST',
136 | headers: {
137 | 'Content-Type': 'application/json',
138 | 'X-LC-Sign': sign + ',' + timestamp,
139 | 'X-LC-Id': 'XsJ7yqBSeG6Mu9ItZBjeKmuy-MdYXbMMI',
140 | },
141 | body: JSON.stringify(data)
142 | })
143 | .then(function (response) {
144 | // 处理响应
145 | if (response.ok) {
146 | // 请求成功
147 | console.log('表单提交成功');
148 | // showModal("施舍留言成功");
149 | showToast("施舍留言成功", 3000);
150 | refreshPage(3000);
151 | } else {
152 | // 请求失败
153 | console.log('表单提交失败');
154 | // showModal("施舍留言失败");
155 | showToast("施舍留言失败", 3000);
156 | }
157 | })
158 | .catch(function (error) {
159 | // 处理错误
160 | console.log('发生错误:', error);
161 | });
162 | }
163 |
164 | function showToast(message, duration) {
165 | // 创建 Toast 提示框元素
166 | var toast = document.createElement("div");
167 | toast.className = "toast";
168 | toast.textContent = message;
169 |
170 | // 将 Toast 提示框添加到页面
171 | document.body.appendChild(toast);
172 |
173 | // 显示 Toast 提示框
174 | setTimeout(function () {
175 | toast.classList.add("show");
176 | }, 100);
177 |
178 | // 隐藏 Toast 提示框
179 | setTimeout(function () {
180 | toast.classList.remove("show");
181 | setTimeout(function () {
182 | toast.remove();
183 | }, 300);
184 | }, duration || 2000);
185 | }
186 |
187 | function refreshPage(duration) {
188 | // 在提示框隐藏后执行刷新操作
189 | setTimeout(function () {
190 | location.reload();
191 | }, duration || 300);
192 | }
193 |
194 | // 获取接口数据
195 | const fetchData = async () => {
196 | try {
197 | // 要计算签名的数据
198 | const timestamp = Date.now();
199 | const md5data = timestamp + App_Key
200 | // 计算MD5签名
201 | const sign = CryptoJS.MD5(md5data).toString();
202 | const response = await fetch('https://' + API_BASE_URL + '/1.1/classes/yfdata?order=-createdAt', {
203 | method: 'GET',
204 | headers: {
205 | 'Content-Type': 'application/json',
206 | 'X-LC-Sign': sign + ',' + timestamp,
207 | 'X-LC-Id': App_ID,
208 | }
209 | })
210 | const data = await response.json();
211 | renderList(data.results);
212 | analyzeData(data.results);
213 | } catch (error) {
214 | console.error('Error:', error);
215 | }
216 | };
217 |
218 | // 统计分析
219 | const analyzeData = (results) => {
220 | const donorCount = results.length;
221 | const totalAmount = results.reduce((sum, item) => sum + item.amount, 0);
222 | const topDonor = results.reduce((max, item) => {
223 | if (item.amount > max.amount) {
224 | return item;
225 | } else if (item.amount === max.amount) {
226 | return new Date(item.createdAt) < new Date(max.createdAt) ? item : max;
227 | } else {
228 | return max;
229 | }
230 | }, results[0]);
231 |
232 | const summaryElement = document.getElementById('summary');
233 | summaryElement.innerHTML = `截至 ${new Date().toLocaleDateString()},有 ${donorCount} 位大善人共布施了 ${totalAmount.toFixed(2)} 元!其中 ${topDonor.name} 大善人布施最多,为 ${topDonor.amount} 元!Up to ${new Date().toLocaleDateString()}, ${donorCount} philanthropists have contributed a total of ${totalAmount.toFixed(2)} yuan! Among them, the top contributor, ${topDonor.name}, donated ${topDonor.amount} yuan.`;
234 |
235 |
236 | };
237 |
238 | // 渲染列表
239 | const renderList = (results) => {
240 | const listBody = document.getElementById('listBody');
241 |
242 | // 清空列表内容
243 | listBody.innerHTML = '';
244 |
245 | if (results.length === 0) {
246 | const defaultRow = document.createElement('tr');
247 | const defaultCell = document.createElement('td');
248 | defaultCell.setAttribute('colspan', '4');
249 | defaultCell.classList.add('default-text');
250 | defaultCell.textContent = '饿饿,🍚🍚,老板,赏点🍚吧;还没有人施舍,施舍一分钱,成为榜单第一大哥';
251 |
252 | defaultRow.appendChild(defaultCell);
253 | listBody.appendChild(defaultRow);
254 | } else {
255 |
256 | // 遍历接口返回的数据并渲染列表行
257 | results.forEach((item) => {
258 |
259 | const row = document.createElement('tr');
260 |
261 | const nameCell = document.createElement('td');
262 | nameCell.textContent = item.name;
263 | nameCell.classList.add('deep-purple');
264 | nameCell.classList.add('border')
265 | row.appendChild(nameCell);
266 |
267 | const payCell = document.createElement('td');
268 | payCell.textContent = item.pay;
269 | if (item.pay === '微信') {
270 | payCell.classList.add('green');
271 | payCell.textContent += ' (CNY)';
272 | } else if (item.pay === '支付宝') {
273 | payCell.classList.add('blue');
274 | payCell.textContent += ' (CNY)';
275 | } else if (item.pay === 'BTC') {
276 | payCell.classList.add('bitcoin-orange');
277 | }
278 | payCell.classList.add('border');
279 | row.appendChild(payCell);
280 |
281 | const amountCell = document.createElement('td');
282 | let amountText = item.amount.toString(); // 将数值转换为字符串形式
283 | if (amountText.includes('e-')) {
284 | // 判断是否为科学计数法表示的小数
285 | amountText = parseFloat(amountText).toFixed(8); // 将科学计数法转换为常规表示形式,并保留8位小数
286 | }
287 | if (item.pay === '微信' || item.pay === '支付宝') {
288 | amountText = '¥ ' + amountText;
289 | } else if (item.pay === 'BTC') {
290 | amountText = '₿ ' + amountText;
291 | }
292 | amountCell.textContent = amountText;
293 | if (item.pay === '微信' || item.pay === '支付宝') {
294 | if (item.amount > 0 && item.amount <= 5) {
295 | amountCell.classList.add('common');
296 | } else if (item.amount > 5 && item.amount <= 100) {
297 | amountCell.classList.add('uncommon');
298 | } else if (item.amount > 100 && item.amount <= 200) {
299 | amountCell.classList.add('rare');
300 | } else if (item.amount > 200 && item.amount <= 500) {
301 | amountCell.classList.add('epic');
302 | } else if (item.amount > 500) {
303 | amountCell.classList.add('legendary');
304 | }
305 | }
306 | else if (item.pay === 'BTC') {
307 | if (item.amount > 0.00000000 && item.amount <= 0.00000005) {
308 | amountCell.classList.add('common');
309 | } else if (item.amount > 0.00000005 && item.amount <= 0.000001) {
310 | amountCell.classList.add('uncommon');
311 | } else if (item.amount > 0.000001 && item.amount <= 0.000002) {
312 | amountCell.classList.add('rare');
313 | } else if (item.amount > 0.000002 && item.amount <= 0.000005) {
314 | amountCell.classList.add('epic');
315 | } else if (item.amount > 0.000005) {
316 | amountCell.classList.add('legendary');
317 | }
318 | }
319 |
320 | amountCell.classList.add('border');
321 | row.appendChild(amountCell);
322 |
323 | const messageCell = document.createElement('td');
324 | messageCell.textContent = item.message;
325 | messageCell.classList.add('border');
326 | messageCell.classList.add('font-style');
327 | row.appendChild(messageCell);
328 |
329 | listBody.appendChild(row);
330 | });
331 | }
332 | };
333 |
334 | // 调用 fetchData 函数获取数据并渲染列表
335 | fetchData();
336 |
337 | // 复制btc地址
338 | function copyAddress() {
339 | var address = document.querySelector('.btc-address').textContent;
340 |
341 | var tempInput = document.createElement('input');
342 | tempInput.value = address;
343 | document.body.appendChild(tempInput);
344 | tempInput.select();
345 | document.execCommand('copy');
346 | document.body.removeChild(tempInput);
347 |
348 | showToast("复制成功/Success", 3000)
349 | }
350 |
--------------------------------------------------------------------------------
/assets/js/main.js:
--------------------------------------------------------------------------------
1 | /*
2 | Astral by HTML5 UP
3 | html5up.net | @ajlkn
4 | Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
5 | */
6 |
7 | (function($) {
8 |
9 | var $window = $(window),
10 | $body = $('body'),
11 | $wrapper = $('#wrapper'),
12 | $main = $('#main'),
13 | $panels = $main.children('.panel'),
14 | $nav = $('#nav'), $nav_links = $nav.children('a');
15 |
16 | // Breakpoints.
17 | breakpoints({
18 | xlarge: [ '1281px', '1680px' ],
19 | large: [ '981px', '1280px' ],
20 | medium: [ '737px', '980px' ],
21 | small: [ '361px', '736px' ],
22 | xsmall: [ null, '360px' ]
23 | });
24 |
25 | // Play initial animations on page load.
26 | $window.on('load', function() {
27 | window.setTimeout(function() {
28 | $body.removeClass('is-preload');
29 | }, 100);
30 | });
31 |
32 | // Nav.
33 | $nav_links
34 | .on('click', function(event) {
35 |
36 | var href = $(this).attr('href');
37 |
38 | // Not a panel link? Bail.
39 | if (href.charAt(0) != '#'
40 | || $panels.filter(href).length == 0)
41 | return;
42 |
43 | // Prevent default.
44 | event.preventDefault();
45 | event.stopPropagation();
46 |
47 | // Change panels.
48 | if (window.location.hash != href)
49 | window.location.hash = href;
50 |
51 | });
52 |
53 | // Panels.
54 |
55 | // Initialize.
56 | (function() {
57 |
58 | var $panel, $link;
59 |
60 | // Get panel, link.
61 | if (window.location.hash) {
62 |
63 | $panel = $panels.filter(window.location.hash);
64 | $link = $nav_links.filter('[href="' + window.location.hash + '"]');
65 |
66 | }
67 |
68 | // No panel/link? Default to first.
69 | if (!$panel
70 | || $panel.length == 0) {
71 |
72 | $panel = $panels.first();
73 | $link = $nav_links.first();
74 |
75 | }
76 |
77 | // Deactivate all panels except this one.
78 | $panels.not($panel)
79 | .addClass('inactive')
80 | .hide();
81 |
82 | // Activate link.
83 | $link
84 | .addClass('active');
85 |
86 | // Reset scroll.
87 | $window.scrollTop(0);
88 |
89 | })();
90 |
91 | // Hashchange event.
92 | $window.on('hashchange', function(event) {
93 |
94 | var $panel, $link;
95 |
96 | // Get panel, link.
97 | if (window.location.hash) {
98 |
99 | $panel = $panels.filter(window.location.hash);
100 | $link = $nav_links.filter('[href="' + window.location.hash + '"]');
101 |
102 | // No target panel? Bail.
103 | if ($panel.length == 0)
104 | return;
105 |
106 | }
107 |
108 | // No panel/link? Default to first.
109 | else {
110 |
111 | $panel = $panels.first();
112 | $link = $nav_links.first();
113 |
114 | }
115 |
116 | // Deactivate all panels.
117 | $panels.addClass('inactive');
118 |
119 | // Deactivate all links.
120 | $nav_links.removeClass('active');
121 |
122 | // Activate target link.
123 | $link.addClass('active');
124 |
125 | // Set max/min height.
126 | $main
127 | .css('max-height', $main.height() + 'px')
128 | .css('min-height', $main.height() + 'px');
129 |
130 | // Delay.
131 | setTimeout(function() {
132 |
133 | // Hide all panels.
134 | $panels.hide();
135 |
136 | // Show target panel.
137 | $panel.show();
138 |
139 | // Set new max/min height.
140 | $main
141 | .css('max-height', $panel.outerHeight() + 'px')
142 | .css('min-height', $panel.outerHeight() + 'px');
143 |
144 | // Reset scroll.
145 | $window.scrollTop(0);
146 |
147 | // Delay.
148 | window.setTimeout(function() {
149 |
150 | // Activate target panel.
151 | $panel.removeClass('inactive');
152 |
153 | // Clear max/min height.
154 | $main
155 | .css('max-height', '')
156 | .css('min-height', '');
157 |
158 | // IE: Refresh.
159 | $window.triggerHandler('--refresh');
160 |
161 | // Unlock.
162 | locked = false;
163 |
164 | }, (breakpoints.active('small') ? 0 : 500));
165 |
166 | }, 250);
167 |
168 | });
169 |
170 | // IE: Fixes.
171 | if (browser.name == 'ie') {
172 |
173 | // Fix min-height/flexbox.
174 | $window.on('--refresh', function() {
175 |
176 | $wrapper.css('height', 'auto');
177 |
178 | window.setTimeout(function() {
179 |
180 | var h = $wrapper.height(),
181 | wh = $window.height();
182 |
183 | if (h < wh)
184 | $wrapper.css('height', '100vh');
185 |
186 | }, 0);
187 |
188 | });
189 |
190 | $window.on('resize load', function() {
191 | $window.triggerHandler('--refresh');
192 | });
193 |
194 | // Fix intro pic.
195 | $('.panel.intro').each(function() {
196 |
197 | var $pic = $(this).children('.pic'),
198 | $img = $pic.children('img');
199 |
200 | $pic
201 | .css('background-image', 'url(' + $img.attr('src') + ')')
202 | .css('background-size', 'cover')
203 | .css('background-position', 'center');
204 |
205 | $img
206 | .css('visibility', 'hidden');
207 |
208 | });
209 |
210 | }
211 |
212 | })(jQuery);
--------------------------------------------------------------------------------
/assets/js/util.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 |
3 | /**
4 | * Generate an indented list of links from a nav. Meant for use with panel().
5 | * @return {jQuery} jQuery object.
6 | */
7 | $.fn.navList = function() {
8 |
9 | var $this = $(this);
10 | $a = $this.find('a'),
11 | b = [];
12 |
13 | $a.each(function() {
14 |
15 | var $this = $(this),
16 | indent = Math.max(0, $this.parents('li').length - 1),
17 | href = $this.attr('href'),
18 | target = $this.attr('target');
19 |
20 | b.push(
21 | '' +
26 | '' +
27 | $this.text() +
28 | ''
29 | );
30 |
31 | });
32 |
33 | return b.join('');
34 |
35 | };
36 |
37 | /**
38 | * Panel-ify an element.
39 | * @param {object} userConfig User config.
40 | * @return {jQuery} jQuery object.
41 | */
42 | $.fn.panel = function(userConfig) {
43 |
44 | // No elements?
45 | if (this.length == 0)
46 | return $this;
47 |
48 | // Multiple elements?
49 | if (this.length > 1) {
50 |
51 | for (var i=0; i < this.length; i++)
52 | $(this[i]).panel(userConfig);
53 |
54 | return $this;
55 |
56 | }
57 |
58 | // Vars.
59 | var $this = $(this),
60 | $body = $('body'),
61 | $window = $(window),
62 | id = $this.attr('id'),
63 | config;
64 |
65 | // Config.
66 | config = $.extend({
67 |
68 | // Delay.
69 | delay: 0,
70 |
71 | // Hide panel on link click.
72 | hideOnClick: false,
73 |
74 | // Hide panel on escape keypress.
75 | hideOnEscape: false,
76 |
77 | // Hide panel on swipe.
78 | hideOnSwipe: false,
79 |
80 | // Reset scroll position on hide.
81 | resetScroll: false,
82 |
83 | // Reset forms on hide.
84 | resetForms: false,
85 |
86 | // Side of viewport the panel will appear.
87 | side: null,
88 |
89 | // Target element for "class".
90 | target: $this,
91 |
92 | // Class to toggle.
93 | visibleClass: 'visible'
94 |
95 | }, userConfig);
96 |
97 | // Expand "target" if it's not a jQuery object already.
98 | if (typeof config.target != 'jQuery')
99 | config.target = $(config.target);
100 |
101 | // Panel.
102 |
103 | // Methods.
104 | $this._hide = function(event) {
105 |
106 | // Already hidden? Bail.
107 | if (!config.target.hasClass(config.visibleClass))
108 | return;
109 |
110 | // If an event was provided, cancel it.
111 | if (event) {
112 |
113 | event.preventDefault();
114 | event.stopPropagation();
115 |
116 | }
117 |
118 | // Hide.
119 | config.target.removeClass(config.visibleClass);
120 |
121 | // Post-hide stuff.
122 | window.setTimeout(function() {
123 |
124 | // Reset scroll position.
125 | if (config.resetScroll)
126 | $this.scrollTop(0);
127 |
128 | // Reset forms.
129 | if (config.resetForms)
130 | $this.find('form').each(function() {
131 | this.reset();
132 | });
133 |
134 | }, config.delay);
135 |
136 | };
137 |
138 | // Vendor fixes.
139 | $this
140 | .css('-ms-overflow-style', '-ms-autohiding-scrollbar')
141 | .css('-webkit-overflow-scrolling', 'touch');
142 |
143 | // Hide on click.
144 | if (config.hideOnClick) {
145 |
146 | $this.find('a')
147 | .css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
148 |
149 | $this
150 | .on('click', 'a', function(event) {
151 |
152 | var $a = $(this),
153 | href = $a.attr('href'),
154 | target = $a.attr('target');
155 |
156 | if (!href || href == '#' || href == '' || href == '#' + id)
157 | return;
158 |
159 | // Cancel original event.
160 | event.preventDefault();
161 | event.stopPropagation();
162 |
163 | // Hide panel.
164 | $this._hide();
165 |
166 | // Redirect to href.
167 | window.setTimeout(function() {
168 |
169 | if (target == '_blank')
170 | window.open(href);
171 | else
172 | window.location.href = href;
173 |
174 | }, config.delay + 10);
175 |
176 | });
177 |
178 | }
179 |
180 | // Event: Touch stuff.
181 | $this.on('touchstart', function(event) {
182 |
183 | $this.touchPosX = event.originalEvent.touches[0].pageX;
184 | $this.touchPosY = event.originalEvent.touches[0].pageY;
185 |
186 | })
187 |
188 | $this.on('touchmove', function(event) {
189 |
190 | if ($this.touchPosX === null
191 | || $this.touchPosY === null)
192 | return;
193 |
194 | var diffX = $this.touchPosX - event.originalEvent.touches[0].pageX,
195 | diffY = $this.touchPosY - event.originalEvent.touches[0].pageY,
196 | th = $this.outerHeight(),
197 | ts = ($this.get(0).scrollHeight - $this.scrollTop());
198 |
199 | // Hide on swipe?
200 | if (config.hideOnSwipe) {
201 |
202 | var result = false,
203 | boundary = 20,
204 | delta = 50;
205 |
206 | switch (config.side) {
207 |
208 | case 'left':
209 | result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta);
210 | break;
211 |
212 | case 'right':
213 | result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta));
214 | break;
215 |
216 | case 'top':
217 | result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta);
218 | break;
219 |
220 | case 'bottom':
221 | result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta));
222 | break;
223 |
224 | default:
225 | break;
226 |
227 | }
228 |
229 | if (result) {
230 |
231 | $this.touchPosX = null;
232 | $this.touchPosY = null;
233 | $this._hide();
234 |
235 | return false;
236 |
237 | }
238 |
239 | }
240 |
241 | // Prevent vertical scrolling past the top or bottom.
242 | if (($this.scrollTop() < 0 && diffY < 0)
243 | || (ts > (th - 2) && ts < (th + 2) && diffY > 0)) {
244 |
245 | event.preventDefault();
246 | event.stopPropagation();
247 |
248 | }
249 |
250 | });
251 |
252 | // Event: Prevent certain events inside the panel from bubbling.
253 | $this.on('click touchend touchstart touchmove', function(event) {
254 | event.stopPropagation();
255 | });
256 |
257 | // Event: Hide panel if a child anchor tag pointing to its ID is clicked.
258 | $this.on('click', 'a[href="#' + id + '"]', function(event) {
259 |
260 | event.preventDefault();
261 | event.stopPropagation();
262 |
263 | config.target.removeClass(config.visibleClass);
264 |
265 | });
266 |
267 | // Body.
268 |
269 | // Event: Hide panel on body click/tap.
270 | $body.on('click touchend', function(event) {
271 | $this._hide(event);
272 | });
273 |
274 | // Event: Toggle.
275 | $body.on('click', 'a[href="#' + id + '"]', function(event) {
276 |
277 | event.preventDefault();
278 | event.stopPropagation();
279 |
280 | config.target.toggleClass(config.visibleClass);
281 |
282 | });
283 |
284 | // Window.
285 |
286 | // Event: Hide on ESC.
287 | if (config.hideOnEscape)
288 | $window.on('keydown', function(event) {
289 |
290 | if (event.keyCode == 27)
291 | $this._hide(event);
292 |
293 | });
294 |
295 | return $this;
296 |
297 | };
298 |
299 | /**
300 | * Apply "placeholder" attribute polyfill to one or more forms.
301 | * @return {jQuery} jQuery object.
302 | */
303 | $.fn.placeholder = function() {
304 |
305 | // Browser natively supports placeholders? Bail.
306 | if (typeof (document.createElement('input')).placeholder != 'undefined')
307 | return $(this);
308 |
309 | // No elements?
310 | if (this.length == 0)
311 | return $this;
312 |
313 | // Multiple elements?
314 | if (this.length > 1) {
315 |
316 | for (var i=0; i < this.length; i++)
317 | $(this[i]).placeholder();
318 |
319 | return $this;
320 |
321 | }
322 |
323 | // Vars.
324 | var $this = $(this);
325 |
326 | // Text, TextArea.
327 | $this.find('input[type=text],textarea')
328 | .each(function() {
329 |
330 | var i = $(this);
331 |
332 | if (i.val() == ''
333 | || i.val() == i.attr('placeholder'))
334 | i
335 | .addClass('polyfill-placeholder')
336 | .val(i.attr('placeholder'));
337 |
338 | })
339 | .on('blur', function() {
340 |
341 | var i = $(this);
342 |
343 | if (i.attr('name').match(/-polyfill-field$/))
344 | return;
345 |
346 | if (i.val() == '')
347 | i
348 | .addClass('polyfill-placeholder')
349 | .val(i.attr('placeholder'));
350 |
351 | })
352 | .on('focus', function() {
353 |
354 | var i = $(this);
355 |
356 | if (i.attr('name').match(/-polyfill-field$/))
357 | return;
358 |
359 | if (i.val() == i.attr('placeholder'))
360 | i
361 | .removeClass('polyfill-placeholder')
362 | .val('');
363 |
364 | });
365 |
366 | // Password.
367 | $this.find('input[type=password]')
368 | .each(function() {
369 |
370 | var i = $(this);
371 | var x = $(
372 | $('')
373 | .append(i.clone())
374 | .remove()
375 | .html()
376 | .replace(/type="password"/i, 'type="text"')
377 | .replace(/type=password/i, 'type=text')
378 | );
379 |
380 | if (i.attr('id') != '')
381 | x.attr('id', i.attr('id') + '-polyfill-field');
382 |
383 | if (i.attr('name') != '')
384 | x.attr('name', i.attr('name') + '-polyfill-field');
385 |
386 | x.addClass('polyfill-placeholder')
387 | .val(x.attr('placeholder')).insertAfter(i);
388 |
389 | if (i.val() == '')
390 | i.hide();
391 | else
392 | x.hide();
393 |
394 | i
395 | .on('blur', function(event) {
396 |
397 | event.preventDefault();
398 |
399 | var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
400 |
401 | if (i.val() == '') {
402 |
403 | i.hide();
404 | x.show();
405 |
406 | }
407 |
408 | });
409 |
410 | x
411 | .on('focus', function(event) {
412 |
413 | event.preventDefault();
414 |
415 | var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']');
416 |
417 | x.hide();
418 |
419 | i
420 | .show()
421 | .focus();
422 |
423 | })
424 | .on('keypress', function(event) {
425 |
426 | event.preventDefault();
427 | x.val('');
428 |
429 | });
430 |
431 | });
432 |
433 | // Events.
434 | $this
435 | .on('submit', function() {
436 |
437 | $this.find('input[type=text],input[type=password],textarea')
438 | .each(function(event) {
439 |
440 | var i = $(this);
441 |
442 | if (i.attr('name').match(/-polyfill-field$/))
443 | i.attr('name', '');
444 |
445 | if (i.val() == i.attr('placeholder')) {
446 |
447 | i.removeClass('polyfill-placeholder');
448 | i.val('');
449 |
450 | }
451 |
452 | });
453 |
454 | })
455 | .on('reset', function(event) {
456 |
457 | event.preventDefault();
458 |
459 | $this.find('select')
460 | .val($('option:first').val());
461 |
462 | $this.find('input,textarea')
463 | .each(function() {
464 |
465 | var i = $(this),
466 | x;
467 |
468 | i.removeClass('polyfill-placeholder');
469 |
470 | switch (this.type) {
471 |
472 | case 'submit':
473 | case 'reset':
474 | break;
475 |
476 | case 'password':
477 | i.val(i.attr('defaultValue'));
478 |
479 | x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
480 |
481 | if (i.val() == '') {
482 | i.hide();
483 | x.show();
484 | }
485 | else {
486 | i.show();
487 | x.hide();
488 | }
489 |
490 | break;
491 |
492 | case 'checkbox':
493 | case 'radio':
494 | i.attr('checked', i.attr('defaultValue'));
495 | break;
496 |
497 | case 'text':
498 | case 'textarea':
499 | i.val(i.attr('defaultValue'));
500 |
501 | if (i.val() == '') {
502 | i.addClass('polyfill-placeholder');
503 | i.val(i.attr('placeholder'));
504 | }
505 |
506 | break;
507 |
508 | default:
509 | i.val(i.attr('defaultValue'));
510 | break;
511 |
512 | }
513 | });
514 |
515 | });
516 |
517 | return $this;
518 |
519 | };
520 |
521 | /**
522 | * Moves elements to/from the first positions of their respective parents.
523 | * @param {jQuery} $elements Elements (or selector) to move.
524 | * @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations.
525 | */
526 | $.prioritize = function($elements, condition) {
527 |
528 | var key = '__prioritize';
529 |
530 | // Expand $elements if it's not already a jQuery object.
531 | if (typeof $elements != 'jQuery')
532 | $elements = $($elements);
533 |
534 | // Step through elements.
535 | $elements.each(function() {
536 |
537 | var $e = $(this), $p,
538 | $parent = $e.parent();
539 |
540 | // No parent? Bail.
541 | if ($parent.length == 0)
542 | return;
543 |
544 | // Not moved? Move it.
545 | if (!$e.data(key)) {
546 |
547 | // Condition is false? Bail.
548 | if (!condition)
549 | return;
550 |
551 | // Get placeholder (which will serve as our point of reference for when this element needs to move back).
552 | $p = $e.prev();
553 |
554 | // Couldn't find anything? Means this element's already at the top, so bail.
555 | if ($p.length == 0)
556 | return;
557 |
558 | // Move element to top of parent.
559 | $e.prependTo($parent);
560 |
561 | // Mark element as moved.
562 | $e.data(key, $p);
563 |
564 | }
565 |
566 | // Moved already?
567 | else {
568 |
569 | // Condition is true? Bail.
570 | if (condition)
571 | return;
572 |
573 | $p = $e.data(key);
574 |
575 | // Move element back to its original location (using our placeholder).
576 | $e.insertAfter($p);
577 |
578 | // Unmark element as moved.
579 | $e.removeData(key);
580 |
581 | }
582 |
583 | });
584 |
585 | };
586 |
587 | })(jQuery);
--------------------------------------------------------------------------------
/assets/sass/libs/_breakpoints.scss:
--------------------------------------------------------------------------------
1 | // breakpoints.scss v1.0 | @ajlkn | MIT licensed */
2 |
3 | // Vars.
4 |
5 | /// Breakpoints.
6 | /// @var {list}
7 | $breakpoints: () !global;
8 |
9 | // Mixins.
10 |
11 | /// Sets breakpoints.
12 | /// @param {map} $x Breakpoints.
13 | @mixin breakpoints($x: ()) {
14 | $breakpoints: $x !global;
15 | }
16 |
17 | /// Wraps @content in a @media block targeting a specific orientation.
18 | /// @param {string} $orientation Orientation.
19 | @mixin orientation($orientation) {
20 | @media screen and (orientation: #{$orientation}) {
21 | @content;
22 | }
23 | }
24 |
25 | /// Wraps @content in a @media block using a given query.
26 | /// @param {string} $query Query.
27 | @mixin breakpoint($query: null) {
28 |
29 | $breakpoint: null;
30 | $op: null;
31 | $media: null;
32 |
33 | // Determine operator, breakpoint.
34 |
35 | // Greater than or equal.
36 | @if (str-slice($query, 0, 2) == '>=') {
37 |
38 | $op: 'gte';
39 | $breakpoint: str-slice($query, 3);
40 |
41 | }
42 |
43 | // Less than or equal.
44 | @elseif (str-slice($query, 0, 2) == '<=') {
45 |
46 | $op: 'lte';
47 | $breakpoint: str-slice($query, 3);
48 |
49 | }
50 |
51 | // Greater than.
52 | @elseif (str-slice($query, 0, 1) == '>') {
53 |
54 | $op: 'gt';
55 | $breakpoint: str-slice($query, 2);
56 |
57 | }
58 |
59 | // Less than.
60 | @elseif (str-slice($query, 0, 1) == '<') {
61 |
62 | $op: 'lt';
63 | $breakpoint: str-slice($query, 2);
64 |
65 | }
66 |
67 | // Not.
68 | @elseif (str-slice($query, 0, 1) == '!') {
69 |
70 | $op: 'not';
71 | $breakpoint: str-slice($query, 2);
72 |
73 | }
74 |
75 | // Equal.
76 | @else {
77 |
78 | $op: 'eq';
79 | $breakpoint: $query;
80 |
81 | }
82 |
83 | // Build media.
84 | @if ($breakpoint and map-has-key($breakpoints, $breakpoint)) {
85 |
86 | $a: map-get($breakpoints, $breakpoint);
87 |
88 | // Range.
89 | @if (type-of($a) == 'list') {
90 |
91 | $x: nth($a, 1);
92 | $y: nth($a, 2);
93 |
94 | // Max only.
95 | @if ($x == null) {
96 |
97 | // Greater than or equal (>= 0 / anything)
98 | @if ($op == 'gte') {
99 | $media: 'screen';
100 | }
101 |
102 | // Less than or equal (<= y)
103 | @elseif ($op == 'lte') {
104 | $media: 'screen and (max-width: ' + $y + ')';
105 | }
106 |
107 | // Greater than (> y)
108 | @elseif ($op == 'gt') {
109 | $media: 'screen and (min-width: ' + ($y + 1) + ')';
110 | }
111 |
112 | // Less than (< 0 / invalid)
113 | @elseif ($op == 'lt') {
114 | $media: 'screen and (max-width: -1px)';
115 | }
116 |
117 | // Not (> y)
118 | @elseif ($op == 'not') {
119 | $media: 'screen and (min-width: ' + ($y + 1) + ')';
120 | }
121 |
122 | // Equal (<= y)
123 | @else {
124 | $media: 'screen and (max-width: ' + $y + ')';
125 | }
126 |
127 | }
128 |
129 | // Min only.
130 | @else if ($y == null) {
131 |
132 | // Greater than or equal (>= x)
133 | @if ($op == 'gte') {
134 | $media: 'screen and (min-width: ' + $x + ')';
135 | }
136 |
137 | // Less than or equal (<= inf / anything)
138 | @elseif ($op == 'lte') {
139 | $media: 'screen';
140 | }
141 |
142 | // Greater than (> inf / invalid)
143 | @elseif ($op == 'gt') {
144 | $media: 'screen and (max-width: -1px)';
145 | }
146 |
147 | // Less than (< x)
148 | @elseif ($op == 'lt') {
149 | $media: 'screen and (max-width: ' + ($x - 1) + ')';
150 | }
151 |
152 | // Not (< x)
153 | @elseif ($op == 'not') {
154 | $media: 'screen and (max-width: ' + ($x - 1) + ')';
155 | }
156 |
157 | // Equal (>= x)
158 | @else {
159 | $media: 'screen and (min-width: ' + $x + ')';
160 | }
161 |
162 | }
163 |
164 | // Min and max.
165 | @else {
166 |
167 | // Greater than or equal (>= x)
168 | @if ($op == 'gte') {
169 | $media: 'screen and (min-width: ' + $x + ')';
170 | }
171 |
172 | // Less than or equal (<= y)
173 | @elseif ($op == 'lte') {
174 | $media: 'screen and (max-width: ' + $y + ')';
175 | }
176 |
177 | // Greater than (> y)
178 | @elseif ($op == 'gt') {
179 | $media: 'screen and (min-width: ' + ($y + 1) + ')';
180 | }
181 |
182 | // Less than (< x)
183 | @elseif ($op == 'lt') {
184 | $media: 'screen and (max-width: ' + ($x - 1) + ')';
185 | }
186 |
187 | // Not (< x and > y)
188 | @elseif ($op == 'not') {
189 | $media: 'screen and (max-width: ' + ($x - 1) + '), screen and (min-width: ' + ($y + 1) + ')';
190 | }
191 |
192 | // Equal (>= x and <= y)
193 | @else {
194 | $media: 'screen and (min-width: ' + $x + ') and (max-width: ' + $y + ')';
195 | }
196 |
197 | }
198 |
199 | }
200 |
201 | // String.
202 | @else {
203 |
204 | // Missing a media type? Prefix with "screen".
205 | @if (str-slice($a, 0, 1) == '(') {
206 | $media: 'screen and ' + $a;
207 | }
208 |
209 | // Otherwise, use as-is.
210 | @else {
211 | $media: $a;
212 | }
213 |
214 | }
215 |
216 | }
217 |
218 | // Output.
219 | @media #{$media} {
220 | @content;
221 | }
222 |
223 | }
--------------------------------------------------------------------------------
/assets/sass/libs/_functions.scss:
--------------------------------------------------------------------------------
1 | /// Removes a specific item from a list.
2 | /// @author Hugo Giraudel
3 | /// @param {list} $list List.
4 | /// @param {integer} $index Index.
5 | /// @return {list} Updated list.
6 | @function remove-nth($list, $index) {
7 |
8 | $result: null;
9 |
10 | @if type-of($index) != number {
11 | @warn "$index: #{quote($index)} is not a number for `remove-nth`.";
12 | }
13 | @else if $index == 0 {
14 | @warn "List index 0 must be a non-zero integer for `remove-nth`.";
15 | }
16 | @else if abs($index) > length($list) {
17 | @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
18 | }
19 | @else {
20 |
21 | $result: ();
22 | $index: if($index < 0, length($list) + $index + 1, $index);
23 |
24 | @for $i from 1 through length($list) {
25 |
26 | @if $i != $index {
27 | $result: append($result, nth($list, $i));
28 | }
29 |
30 | }
31 |
32 | }
33 |
34 | @return $result;
35 |
36 | }
37 |
38 | /// Gets a value from a map.
39 | /// @author Hugo Giraudel
40 | /// @param {map} $map Map.
41 | /// @param {string} $keys Key(s).
42 | /// @return {string} Value.
43 | @function val($map, $keys...) {
44 |
45 | @if nth($keys, 1) == null {
46 | $keys: remove-nth($keys, 1);
47 | }
48 |
49 | @each $key in $keys {
50 | $map: map-get($map, $key);
51 | }
52 |
53 | @return $map;
54 |
55 | }
56 |
57 | /// Gets a duration value.
58 | /// @param {string} $keys Key(s).
59 | /// @return {string} Value.
60 | @function _duration($keys...) {
61 | @return val($duration, $keys...);
62 | }
63 |
64 | /// Gets a font value.
65 | /// @param {string} $keys Key(s).
66 | /// @return {string} Value.
67 | @function _font($keys...) {
68 | @return val($font, $keys...);
69 | }
70 |
71 | /// Gets a misc value.
72 | /// @param {string} $keys Key(s).
73 | /// @return {string} Value.
74 | @function _misc($keys...) {
75 | @return val($misc, $keys...);
76 | }
77 |
78 | /// Gets a palette value.
79 | /// @param {string} $keys Key(s).
80 | /// @return {string} Value.
81 | @function _palette($keys...) {
82 | @return val($palette, $keys...);
83 | }
84 |
85 | /// Gets a size value.
86 | /// @param {string} $keys Key(s).
87 | /// @return {string} Value.
88 | @function _size($keys...) {
89 | @return val($size, $keys...);
90 | }
--------------------------------------------------------------------------------
/assets/sass/libs/_html-grid.scss:
--------------------------------------------------------------------------------
1 | // html-grid.scss v1.0 | @ajlkn | MIT licensed */
2 |
3 | // Mixins.
4 |
5 | /// Initializes the current element as an HTML grid.
6 | /// @param {mixed} $gutters Gutters (either a single number to set both column/row gutters, or a list to set them individually).
7 | /// @param {mixed} $suffix Column class suffix (optional; either a single suffix or a list).
8 | @mixin html-grid($gutters: 1.5em, $suffix: '') {
9 |
10 | // Initialize.
11 | $cols: 12;
12 | $multipliers: 0, 0.25, 0.5, 1, 1.50, 2.00;
13 | $unit: 100% / $cols;
14 |
15 | // Suffixes.
16 | $suffixes: null;
17 |
18 | @if (type-of($suffix) == 'list') {
19 | $suffixes: $suffix;
20 | }
21 | @else {
22 | $suffixes: ($suffix);
23 | }
24 |
25 | // Gutters.
26 | $guttersCols: null;
27 | $guttersRows: null;
28 |
29 | @if (type-of($gutters) == 'list') {
30 |
31 | $guttersCols: nth($gutters, 1);
32 | $guttersRows: nth($gutters, 2);
33 |
34 | }
35 | @else {
36 |
37 | $guttersCols: $gutters;
38 | $guttersRows: 0;
39 |
40 | }
41 |
42 | // Row.
43 | display: flex;
44 | flex-wrap: wrap;
45 | box-sizing: border-box;
46 | align-items: stretch;
47 |
48 | // Columns.
49 | > * {
50 | box-sizing: border-box;
51 | }
52 |
53 | // Gutters.
54 | &.gtr-uniform {
55 | > * {
56 | > :last-child {
57 | margin-bottom: 0;
58 | }
59 | }
60 | }
61 |
62 | // Alignment.
63 | &.aln-left {
64 | justify-content: flex-start;
65 | }
66 |
67 | &.aln-center {
68 | justify-content: center;
69 | }
70 |
71 | &.aln-right {
72 | justify-content: flex-end;
73 | }
74 |
75 | &.aln-top {
76 | align-items: flex-start;
77 | }
78 |
79 | &.aln-middle {
80 | align-items: center;
81 | }
82 |
83 | &.aln-bottom {
84 | align-items: flex-end;
85 | }
86 |
87 | // Step through suffixes.
88 | @each $suffix in $suffixes {
89 |
90 | // Suffix.
91 | @if ($suffix != '') {
92 | $suffix: '-' + $suffix;
93 | }
94 | @else {
95 | $suffix: '';
96 | }
97 |
98 | // Row.
99 |
100 | // Important.
101 | > .imp#{$suffix} {
102 | order: -1;
103 | }
104 |
105 | // Columns, offsets.
106 | @for $i from 1 through $cols {
107 | > .col-#{$i}#{$suffix} {
108 | width: $unit * $i;
109 | }
110 |
111 | > .off-#{$i}#{$suffix} {
112 | margin-left: $unit * $i;
113 | }
114 | }
115 |
116 | // Step through multipliers.
117 | @each $multiplier in $multipliers {
118 |
119 | // Gutters.
120 | $class: null;
121 |
122 | @if ($multiplier != 1) {
123 | $class: '.gtr-' + ($multiplier * 100);
124 | }
125 |
126 | {$class} {
127 | margin-top: ($guttersRows * $multiplier * -1);
128 | margin-left: ($guttersCols * $multiplier * -1);
129 |
130 | > * {
131 | padding: ($guttersRows * $multiplier) 0 0 ($guttersCols * $multiplier);
132 | }
133 |
134 | // Uniform.
135 | &.gtr-uniform {
136 | margin-top: $guttersCols * $multiplier * -1;
137 |
138 | > * {
139 | padding-top: $guttersCols * $multiplier;
140 | }
141 | }
142 |
143 | }
144 |
145 | }
146 |
147 | }
148 |
149 | }
--------------------------------------------------------------------------------
/assets/sass/libs/_mixins.scss:
--------------------------------------------------------------------------------
1 | /// Makes an element's :before pseudoelement a FontAwesome icon.
2 | /// @param {string} $content Optional content value to use.
3 | /// @param {string} $category Optional category to use.
4 | /// @param {string} $where Optional pseudoelement to target (before or after).
5 | @mixin icon($content: false, $category: regular, $where: before) {
6 |
7 | text-decoration: none;
8 |
9 | &:#{$where} {
10 |
11 | @if $content {
12 | content: $content;
13 | }
14 |
15 | -moz-osx-font-smoothing: grayscale;
16 | -webkit-font-smoothing: antialiased;
17 | display: inline-block;
18 | font-style: normal;
19 | font-variant: normal;
20 | text-rendering: auto;
21 | line-height: 1;
22 | text-transform: none !important;
23 |
24 | @if ($category == brands) {
25 | font-family: 'Font Awesome 5 Brands';
26 | }
27 | @elseif ($category == solid) {
28 | font-family: 'Font Awesome 5 Free';
29 | font-weight: 900;
30 | }
31 | @else {
32 | font-family: 'Font Awesome 5 Free';
33 | font-weight: 400;
34 | }
35 |
36 | }
37 |
38 | }
39 |
40 | /// Applies padding to an element, taking the current element-margin value into account.
41 | /// @param {mixed} $tb Top/bottom padding.
42 | /// @param {mixed} $lr Left/right padding.
43 | /// @param {list} $pad Optional extra padding (in the following order top, right, bottom, left)
44 | /// @param {bool} $important If true, adds !important.
45 | @mixin padding($tb, $lr, $pad: (0,0,0,0), $important: null) {
46 |
47 | @if $important {
48 | $important: '!important';
49 | }
50 |
51 | $x: 0.1em;
52 |
53 | @if unit(_size(element-margin)) == 'rem' {
54 | $x: 0.1rem;
55 | }
56 |
57 | padding: ($tb + nth($pad,1)) ($lr + nth($pad,2)) max($x, $tb - _size(element-margin) + nth($pad,3)) ($lr + nth($pad,4)) #{$important};
58 |
59 | }
60 |
61 | /// Encodes a SVG data URL so IE doesn't choke (via codepen.io/jakob-e/pen/YXXBrp).
62 | /// @param {string} $svg SVG data URL.
63 | /// @return {string} Encoded SVG data URL.
64 | @function svg-url($svg) {
65 |
66 | $svg: str-replace($svg, '"', '\'');
67 | $svg: str-replace($svg, '%', '%25');
68 | $svg: str-replace($svg, '<', '%3C');
69 | $svg: str-replace($svg, '>', '%3E');
70 | $svg: str-replace($svg, '&', '%26');
71 | $svg: str-replace($svg, '#', '%23');
72 | $svg: str-replace($svg, '{', '%7B');
73 | $svg: str-replace($svg, '}', '%7D');
74 | $svg: str-replace($svg, ';', '%3B');
75 |
76 | @return url("data:image/svg+xml;charset=utf8,#{$svg}");
77 |
78 | }
--------------------------------------------------------------------------------
/assets/sass/libs/_vars.scss:
--------------------------------------------------------------------------------
1 | // Misc.
2 | $misc: (
3 | z-index-base: 10000
4 | );
5 |
6 | // Duration.
7 | $duration: (
8 | );
9 |
10 | // Size.
11 | $size: (
12 | );
13 |
14 | // Font.
15 | $font: (
16 | );
17 |
18 | // Palette.
19 | $palette: (
20 | );
--------------------------------------------------------------------------------
/assets/sass/libs/_vendor.scss:
--------------------------------------------------------------------------------
1 | // vendor.scss v1.0 | @ajlkn | MIT licensed */
2 |
3 | // Vars.
4 |
5 | /// Vendor prefixes.
6 | /// @var {list}
7 | $vendor-prefixes: (
8 | '-moz-',
9 | '-webkit-',
10 | '-ms-',
11 | ''
12 | );
13 |
14 | /// Properties that should be vendorized.
15 | /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org
16 | /// @var {list}
17 | $vendor-properties: (
18 |
19 | // Animation.
20 | 'animation',
21 | 'animation-delay',
22 | 'animation-direction',
23 | 'animation-duration',
24 | 'animation-fill-mode',
25 | 'animation-iteration-count',
26 | 'animation-name',
27 | 'animation-play-state',
28 | 'animation-timing-function',
29 |
30 | // Appearance.
31 | 'appearance',
32 |
33 | // Backdrop filter.
34 | 'backdrop-filter',
35 |
36 | // Background image options.
37 | 'background-clip',
38 | 'background-origin',
39 | 'background-size',
40 |
41 | // Box sizing.
42 | 'box-sizing',
43 |
44 | // Clip path.
45 | 'clip-path',
46 |
47 | // Filter effects.
48 | 'filter',
49 |
50 | // Flexbox.
51 | 'align-content',
52 | 'align-items',
53 | 'align-self',
54 | 'flex',
55 | 'flex-basis',
56 | 'flex-direction',
57 | 'flex-flow',
58 | 'flex-grow',
59 | 'flex-shrink',
60 | 'flex-wrap',
61 | 'justify-content',
62 | 'order',
63 |
64 | // Font feature.
65 | 'font-feature-settings',
66 | 'font-language-override',
67 | 'font-variant-ligatures',
68 |
69 | // Font kerning.
70 | 'font-kerning',
71 |
72 | // Fragmented borders and backgrounds.
73 | 'box-decoration-break',
74 |
75 | // Grid layout.
76 | 'grid-column',
77 | 'grid-column-align',
78 | 'grid-column-end',
79 | 'grid-column-start',
80 | 'grid-row',
81 | 'grid-row-align',
82 | 'grid-row-end',
83 | 'grid-row-start',
84 | 'grid-template-columns',
85 | 'grid-template-rows',
86 |
87 | // Hyphens.
88 | 'hyphens',
89 | 'word-break',
90 |
91 | // Masks.
92 | 'mask',
93 | 'mask-border',
94 | 'mask-border-outset',
95 | 'mask-border-repeat',
96 | 'mask-border-slice',
97 | 'mask-border-source',
98 | 'mask-border-width',
99 | 'mask-clip',
100 | 'mask-composite',
101 | 'mask-image',
102 | 'mask-origin',
103 | 'mask-position',
104 | 'mask-repeat',
105 | 'mask-size',
106 |
107 | // Multicolumn.
108 | 'break-after',
109 | 'break-before',
110 | 'break-inside',
111 | 'column-count',
112 | 'column-fill',
113 | 'column-gap',
114 | 'column-rule',
115 | 'column-rule-color',
116 | 'column-rule-style',
117 | 'column-rule-width',
118 | 'column-span',
119 | 'column-width',
120 | 'columns',
121 |
122 | // Object fit.
123 | 'object-fit',
124 | 'object-position',
125 |
126 | // Regions.
127 | 'flow-from',
128 | 'flow-into',
129 | 'region-fragment',
130 |
131 | // Scroll snap points.
132 | 'scroll-snap-coordinate',
133 | 'scroll-snap-destination',
134 | 'scroll-snap-points-x',
135 | 'scroll-snap-points-y',
136 | 'scroll-snap-type',
137 |
138 | // Shapes.
139 | 'shape-image-threshold',
140 | 'shape-margin',
141 | 'shape-outside',
142 |
143 | // Tab size.
144 | 'tab-size',
145 |
146 | // Text align last.
147 | 'text-align-last',
148 |
149 | // Text decoration.
150 | 'text-decoration-color',
151 | 'text-decoration-line',
152 | 'text-decoration-skip',
153 | 'text-decoration-style',
154 |
155 | // Text emphasis.
156 | 'text-emphasis',
157 | 'text-emphasis-color',
158 | 'text-emphasis-position',
159 | 'text-emphasis-style',
160 |
161 | // Text size adjust.
162 | 'text-size-adjust',
163 |
164 | // Text spacing.
165 | 'text-spacing',
166 |
167 | // Transform.
168 | 'transform',
169 | 'transform-origin',
170 |
171 | // Transform 3D.
172 | 'backface-visibility',
173 | 'perspective',
174 | 'perspective-origin',
175 | 'transform-style',
176 |
177 | // Transition.
178 | 'transition',
179 | 'transition-delay',
180 | 'transition-duration',
181 | 'transition-property',
182 | 'transition-timing-function',
183 |
184 | // Unicode bidi.
185 | 'unicode-bidi',
186 |
187 | // User select.
188 | 'user-select',
189 |
190 | // Writing mode.
191 | 'writing-mode',
192 |
193 | );
194 |
195 | /// Values that should be vendorized.
196 | /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org
197 | /// @var {list}
198 | $vendor-values: (
199 |
200 | // Cross fade.
201 | 'cross-fade',
202 |
203 | // Element function.
204 | 'element',
205 |
206 | // Filter function.
207 | 'filter',
208 |
209 | // Flexbox.
210 | 'flex',
211 | 'inline-flex',
212 |
213 | // Grab cursors.
214 | 'grab',
215 | 'grabbing',
216 |
217 | // Gradients.
218 | 'linear-gradient',
219 | 'repeating-linear-gradient',
220 | 'radial-gradient',
221 | 'repeating-radial-gradient',
222 |
223 | // Grid layout.
224 | 'grid',
225 | 'inline-grid',
226 |
227 | // Image set.
228 | 'image-set',
229 |
230 | // Intrinsic width.
231 | 'max-content',
232 | 'min-content',
233 | 'fit-content',
234 | 'fill',
235 | 'fill-available',
236 | 'stretch',
237 |
238 | // Sticky position.
239 | 'sticky',
240 |
241 | // Transform.
242 | 'transform',
243 |
244 | // Zoom cursors.
245 | 'zoom-in',
246 | 'zoom-out',
247 |
248 | );
249 |
250 | // Functions.
251 |
252 | /// Removes a specific item from a list.
253 | /// @author Hugo Giraudel
254 | /// @param {list} $list List.
255 | /// @param {integer} $index Index.
256 | /// @return {list} Updated list.
257 | @function remove-nth($list, $index) {
258 |
259 | $result: null;
260 |
261 | @if type-of($index) != number {
262 | @warn "$index: #{quote($index)} is not a number for `remove-nth`.";
263 | }
264 | @else if $index == 0 {
265 | @warn "List index 0 must be a non-zero integer for `remove-nth`.";
266 | }
267 | @else if abs($index) > length($list) {
268 | @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
269 | }
270 | @else {
271 |
272 | $result: ();
273 | $index: if($index < 0, length($list) + $index + 1, $index);
274 |
275 | @for $i from 1 through length($list) {
276 |
277 | @if $i != $index {
278 | $result: append($result, nth($list, $i));
279 | }
280 |
281 | }
282 |
283 | }
284 |
285 | @return $result;
286 |
287 | }
288 |
289 | /// Replaces a substring within another string.
290 | /// @author Hugo Giraudel
291 | /// @param {string} $string String.
292 | /// @param {string} $search Substring.
293 | /// @param {string} $replace Replacement.
294 | /// @return {string} Updated string.
295 | @function str-replace($string, $search, $replace: '') {
296 |
297 | $index: str-index($string, $search);
298 |
299 | @if $index {
300 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
301 | }
302 |
303 | @return $string;
304 |
305 | }
306 |
307 | /// Replaces a substring within each string in a list.
308 | /// @param {list} $strings List of strings.
309 | /// @param {string} $search Substring.
310 | /// @param {string} $replace Replacement.
311 | /// @return {list} Updated list of strings.
312 | @function str-replace-all($strings, $search, $replace: '') {
313 |
314 | @each $string in $strings {
315 | $strings: set-nth($strings, index($strings, $string), str-replace($string, $search, $replace));
316 | }
317 |
318 | @return $strings;
319 |
320 | }
321 |
322 | // Mixins.
323 |
324 | /// Wraps @content in vendorized keyframe blocks.
325 | /// @param {string} $name Name.
326 | @mixin keyframes($name) {
327 |
328 | @-moz-keyframes #{$name} { @content; }
329 | @-webkit-keyframes #{$name} { @content; }
330 | @-ms-keyframes #{$name} { @content; }
331 | @keyframes #{$name} { @content; }
332 |
333 | }
334 |
335 | /// Vendorizes a declaration's property and/or value(s).
336 | /// @param {string} $property Property.
337 | /// @param {mixed} $value String/list of value(s).
338 | @mixin vendor($property, $value) {
339 |
340 | // Determine if property should expand.
341 | $expandProperty: index($vendor-properties, $property);
342 |
343 | // Determine if value should expand (and if so, add '-prefix-' placeholder).
344 | $expandValue: false;
345 |
346 | @each $x in $value {
347 | @each $y in $vendor-values {
348 | @if $y == str-slice($x, 1, str-length($y)) {
349 |
350 | $value: set-nth($value, index($value, $x), '-prefix-' + $x);
351 | $expandValue: true;
352 |
353 | }
354 | }
355 | }
356 |
357 | // Expand property?
358 | @if $expandProperty {
359 | @each $vendor in $vendor-prefixes {
360 | #{$vendor}#{$property}: #{str-replace-all($value, '-prefix-', $vendor)};
361 | }
362 | }
363 |
364 | // Expand just the value?
365 | @elseif $expandValue {
366 | @each $vendor in $vendor-prefixes {
367 | #{$property}: #{str-replace-all($value, '-prefix-', $vendor)};
368 | }
369 | }
370 |
371 | // Neither? Treat them as a normal declaration.
372 | @else {
373 | #{$property}: #{$value};
374 | }
375 |
376 | }
--------------------------------------------------------------------------------
/assets/sass/main.scss:
--------------------------------------------------------------------------------
1 | @import 'libs/vars';
2 | @import 'libs/functions';
3 | @import 'libs/mixins';
4 | @import 'libs/vendor';
5 | @import 'libs/breakpoints';
6 | @import 'libs/html-grid';
7 | @import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,300italic,400italic');
8 | @import url('fontawesome-all.min.css');
9 |
10 | /*
11 | Astral by HTML5 UP
12 | html5up.net | @ajlkn
13 | Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
14 | */
15 |
16 | // Breakpoints.
17 |
18 | @include breakpoints((
19 | xlarge: ( 1281px, 1680px ),
20 | large: ( 981px, 1280px ),
21 | medium: ( 737px, 980px ),
22 | small: ( 361px, 736px ),
23 | xsmall: ( null, 360px )
24 | ));
25 |
26 | // Reset.
27 | // Based on meyerweb.com/eric/tools/css/reset (v2.0 | 20110126 | License: public domain)
28 |
29 | html, body, div, span, applet, object,
30 | iframe, h1, h2, h3, h4, h5, h6, p, blockquote,
31 | pre, a, abbr, acronym, address, big, cite,
32 | code, del, dfn, em, img, ins, kbd, q, s, samp,
33 | small, strike, strong, sub, sup, tt, var, b,
34 | u, i, center, dl, dt, dd, ol, ul, li, fieldset,
35 | form, label, legend, table, caption, tbody,
36 | tfoot, thead, tr, th, td, article, aside,
37 | canvas, details, embed, figure, figcaption,
38 | footer, header, hgroup, menu, nav, output, ruby,
39 | section, summary, time, mark, audio, video {
40 | margin: 0;
41 | padding: 0;
42 | border: 0;
43 | font-size: 100%;
44 | font: inherit;
45 | vertical-align: baseline;
46 | }
47 |
48 | article, aside, details, figcaption, figure,
49 | footer, header, hgroup, menu, nav, section {
50 | display: block;
51 | }
52 |
53 | body {
54 | line-height: 1;
55 | }
56 |
57 | ol, ul {
58 | list-style: none;
59 | }
60 |
61 | blockquote, q {
62 | quotes: none;
63 |
64 | &:before,
65 | &:after {
66 | content: '';
67 | content: none;
68 | }
69 | }
70 |
71 | table {
72 | border-collapse: collapse;
73 | border-spacing: 0;
74 | }
75 |
76 | body {
77 | -webkit-text-size-adjust: none;
78 | }
79 |
80 | mark {
81 | background-color: transparent;
82 | color: inherit;
83 | }
84 |
85 | input::-moz-focus-inner {
86 | border: 0;
87 | padding: 0;
88 | }
89 |
90 | input, select, textarea {
91 | -moz-appearance: none;
92 | -webkit-appearance: none;
93 | -ms-appearance: none;
94 | appearance: none;
95 | }
96 |
97 | /* Row */
98 |
99 | .row {
100 | @include html-grid((1.25em, 1.25em));
101 |
102 | @include breakpoint('<=xlarge') {
103 | @include html-grid((1.25em, 1.25em), 'xlarge');
104 | }
105 |
106 | @include breakpoint('<=large') {
107 | @include html-grid((1.25em, 1.25em), 'large');
108 | }
109 |
110 | @include breakpoint('<=medium') {
111 | @include html-grid((1.25em, 1.25em), 'medium');
112 | }
113 |
114 | @include breakpoint('<=small') {
115 | @include html-grid((1.25em, 1.25em), 'small');
116 | }
117 | }
118 |
119 | /* Basic */
120 |
121 | // Set box model to border-box.
122 | // Based on css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice
123 | html {
124 | box-sizing: border-box;
125 | }
126 |
127 | *, *:before, *:after {
128 | box-sizing: inherit;
129 | }
130 |
131 | body {
132 | background-image: url('images/overlay.png'), url('images/bg.jpg');
133 | background-repeat: repeat, no-repeat;
134 | background-size: auto, 100% 100%;
135 | background-attachment: fixed;
136 | overflow-y: scroll;
137 |
138 | // Stops initial animations until page loads.
139 | &.is-preload {
140 | *, *:before, *:after {
141 | @include vendor('animation', 'none !important');
142 | @include vendor('transition', 'none !important');
143 | }
144 | }
145 |
146 | }
147 |
148 | body, input, textarea, select {
149 | font-family: 'Source Sans Pro', sans-serif;
150 | font-weight: 300;
151 | color: #777777;
152 | font-size: 20pt;
153 | line-height: 1.75em;
154 |
155 | @include breakpoint('<=xlarge') {
156 | font-size: 15pt;
157 | }
158 |
159 | @include breakpoint('<=large') {
160 | font-size: 14pt;
161 | }
162 |
163 | @include breakpoint('<=small') {
164 | font-size: 12pt;
165 | }
166 |
167 | @include breakpoint('<=xsmall') {
168 | font-size: 11pt;
169 | }
170 | }
171 |
172 | strong, b, h1, h2, h3, h4, h5, h6 {
173 | font-weight: 400;
174 | color: #363636;
175 | }
176 |
177 | h1 {
178 | font-size: 2.4em;
179 | letter-spacing: -0.015em;
180 | }
181 |
182 | h2 {
183 | font-size: 1.8em;
184 | letter-spacing: -0.015em;
185 | }
186 |
187 | h3, h4, h5, h6 {
188 | font-size: 1.25em;
189 | letter-spacing: -0.015em;
190 | }
191 |
192 | @include breakpoint('<=small') {
193 | h1 {
194 | font-size: 1.75em;
195 | }
196 |
197 | h2 {
198 | font-size: 1.375em;
199 | }
200 |
201 | h3, h4, h5, h6 {
202 | font-size: 1em;
203 | }
204 | }
205 |
206 | blockquote {
207 | border-left: solid 0.5em #ddd;
208 | padding: 1em 0 1em 2em;
209 | font-style: italic;
210 | }
211 |
212 | em, i {
213 | font-style: italic;
214 | }
215 |
216 | hr {
217 | border: 0;
218 | border-top: solid 1px #ddd;
219 | padding: 1.5em 0 0 0;
220 | margin: 1.75em 0 0 0;
221 | }
222 |
223 | sub {
224 | position: relative;
225 | top: 0.5em;
226 | font-size: 0.8em;
227 | }
228 |
229 | sup {
230 | position: relative;
231 | top: -0.5em;
232 | font-size: 0.8em;
233 | }
234 |
235 | br.clear {
236 | clear: both;
237 | }
238 |
239 | p, ul, ol, dl, table, blockquote, form {
240 | margin-bottom: 2em;
241 | }
242 |
243 | /* Table */
244 |
245 | table {
246 | width: 100%;
247 |
248 | &.default {
249 | tbody {
250 | tr {
251 | border-bottom: solid 1px #f4f4f4;
252 | }
253 | }
254 |
255 | td {
256 | padding: 0.5em 1em 0.5em 1em;
257 | }
258 |
259 | th {
260 | text-align: left;
261 | font-weight: 400;
262 | padding: 0.5em 1em 0.5em 1em;
263 | }
264 |
265 | thead {
266 | border-bottom: solid 2px #f4f4f4;
267 | }
268 | }
269 | }
270 |
271 | /* Form */
272 |
273 | form {
274 | label {
275 | display: block;
276 | font-weight: 400;
277 | color: #363636;
278 | margin: 0 0 1em 0;
279 | }
280 |
281 | input[type="text"],
282 | input[type="email"],
283 | input[type="password"],
284 | select,
285 | textarea {
286 | -webkit-appearance: none;
287 | border: 0;
288 | background: #f4f4f4;
289 | padding: 0.75em;
290 | width: 100%;
291 | @include vendor('transition', 'background-color .25s ease-in-out');
292 |
293 | &:focus {
294 | background: #f8f8f8;
295 | }
296 | }
297 |
298 | input[type="text"],
299 | input[type="email"],
300 | input[type="password"],
301 | select {
302 | line-height: 1.35em;
303 | }
304 |
305 | ::-webkit-input-placeholder {
306 | color: #999;
307 | }
308 |
309 | :-moz-placeholder {
310 | color: #999;
311 | }
312 |
313 | ::-moz-placeholder {
314 | color: #999;
315 | }
316 |
317 | :-ms-input-placeholder {
318 | color: #999;
319 | }
320 | }
321 |
322 | /* Section/Article */
323 |
324 | section, article {
325 | margin-bottom: 3em;
326 |
327 | > :last-child,
328 | &:last-child {
329 | margin-bottom: 0;
330 | }
331 | }
332 |
333 | header {
334 | margin: 0 0 1.5em 0;
335 |
336 | > p {
337 | margin: 0.5em 0 0 0;
338 | color: #aaa;
339 | }
340 |
341 | @include breakpoint('<=small') {
342 | margin: 0 0 1em 0;
343 | }
344 | }
345 |
346 | /* Image */
347 |
348 | .image {
349 | display: inline-block;
350 |
351 | img {
352 | display: block;
353 | width: 100%;
354 | }
355 |
356 | &.fit {
357 | display: block;
358 | width: 100%;
359 | }
360 |
361 | &.featured {
362 | display: block;
363 | width: 100%;
364 | margin: 0 0 2em 0;
365 | }
366 |
367 | &.left {
368 | float: left;
369 | margin: 0 2em 2em 0;
370 | }
371 |
372 | &.centered {
373 | display: block;
374 | margin: 0 0 2em 0;
375 |
376 | img {
377 | margin: 0 auto;
378 | width: auto;
379 | }
380 | }
381 | }
382 |
383 | /* Button */
384 |
385 | input[type="button"],
386 | input[type="submit"],
387 | input[type="reset"],
388 | button,
389 | .button {
390 | @include vendor('transition', 'background-color .25s ease-in-out');
391 | -webkit-appearance: none;
392 | display: inline-block;
393 | background-color: #222222;
394 | color: #ffffff;
395 | border: 0;
396 | cursor: pointer;
397 | outline: 0;
398 | padding: 0.7em 1.5em 0.7em 1.5em;
399 |
400 | &:hover {
401 | background-color: #333333;
402 | }
403 |
404 | &:active {
405 | background-color: #444444;
406 | }
407 |
408 | &.alt {
409 | background-color: #777777;
410 |
411 | &:hover {
412 | background-color: #888888;
413 | }
414 |
415 | &:active {
416 | background-color: #999999;
417 | }
418 | }
419 |
420 | &.small {
421 | font-size: 0.75em;
422 | }
423 |
424 | &.large {
425 | font-size: 1.25em;
426 | padding: 0.5em 1.25em 0.5em 1.25em;
427 | }
428 |
429 | &.xlarge {
430 | font-size: 1.5em;
431 | padding: 0.5em 1.25em 0.5em 1.25em;
432 | }
433 |
434 | @include breakpoint('<=small') {
435 | width: 100%;
436 | }
437 | }
438 |
439 | /* List */
440 |
441 | ul {
442 | list-style: disc;
443 | padding-left: 1em;
444 |
445 | li {
446 | padding-left: 0.5em;
447 | }
448 |
449 | }
450 |
451 | ol {
452 | list-style: decimal;
453 | padding-left: 1.25em;
454 |
455 | li {
456 | padding-left: 0.25em;
457 | }
458 | }
459 |
460 | /* Actions */
461 |
462 | ul.actions {
463 | list-style: none;
464 | padding-left: 0;
465 |
466 | li {
467 | display: inline-block;
468 | padding-left: 0;
469 | margin: 0 0 0 0.5em;
470 |
471 | &:first-child {
472 | margin-left: 0;
473 | }
474 | }
475 |
476 | @include breakpoint('<=small') {
477 | li {
478 | display: block;
479 | margin: 0.75em 0 0 0;
480 |
481 | &:first-child {
482 | margin-top: 0;
483 | }
484 | }
485 | }
486 | }
487 |
488 | /* Icons */
489 |
490 | .icon {
491 | @include icon;
492 | position: relative;
493 | text-decoration: none;
494 |
495 | &.solid {
496 | &:before {
497 | font-weight: 900;
498 | }
499 | }
500 |
501 | &.brands {
502 | &:before {
503 | font-family: 'Font Awesome 5 Brands';
504 | }
505 | }
506 |
507 | &:before {
508 | line-height: inherit;
509 | }
510 |
511 | > .label {
512 | display: none;
513 | }
514 | }
515 |
516 | /* Nav */
517 |
518 | #nav {
519 | text-align: center;
520 | height: 4.25em;
521 | cursor: default;
522 |
523 | a {
524 | position: relative;
525 | display: inline-block;
526 | color: #ffffff;
527 | width: 1em;
528 | height: 1em;
529 | line-height: 0.9em;
530 | font-size: 2.5em;
531 | margin: 0 0.25em 0 0.25em;
532 | opacity: 0.35;
533 | outline: 0;
534 | @include vendor('transition', 'opacity .25s ease-in-out');
535 |
536 | &.icon:before {
537 | padding-right: 0;
538 | }
539 |
540 | &:before {
541 | font-size: 0.8em;
542 | }
543 |
544 | &:after {
545 | content: '';
546 | display: block;
547 | position: absolute;
548 | left: 50%;
549 | bottom: -0.75em;
550 | margin-left: -0.5em;
551 | border-bottom: solid 0em #ffffff;
552 | border-left: solid 0.5em transparent;
553 | border-right: solid 0.5em transparent;
554 | @include vendor('transition', 'border-bottom-width .25s ease-in-out');
555 | }
556 |
557 | span {
558 | display: block;
559 | position: absolute;
560 | background: #222222;
561 | color: #ffffff;
562 | top: -2.75em;
563 | font-size: 0.3em;
564 | height: 2.25em;
565 | line-height: 2.25em;
566 | left: 50%;
567 | opacity: 0;
568 | @include vendor('transition', 'opacity .25s ease-in-out');
569 | // Labels not wide enough? Increase its width below and set margin-left to ((width / 2) * -1)
570 | width: 5.5em;
571 | margin-left: -2.75em;
572 |
573 | &:after {
574 | content: '';
575 | display: block;
576 | position: absolute;
577 | bottom: -0.4em;
578 | left: 50%;
579 | margin-left: -0.6em;
580 | border-top: solid 0.6em #222222;
581 | border-left: solid 0.6em transparent;
582 | border-right: solid 0.6em transparent;
583 | }
584 | }
585 |
586 | &:hover {
587 | opacity: 1.0;
588 |
589 | span {
590 | opacity: 1.0;
591 | }
592 | }
593 |
594 | &.active {
595 | opacity: 1.0;
596 |
597 | &:after {
598 | border-bottom-width: 0.5em;
599 | }
600 | }
601 | }
602 |
603 | @include breakpoint('<=medium') {
604 | a {
605 | span {
606 | display: none;
607 | }
608 | }
609 | }
610 | }
611 |
612 | /* Wrapper */
613 |
614 | #wrapper {
615 | width: 45em;
616 | margin: 0 auto;
617 | min-height: 100vh;
618 | max-width: 100%;
619 | padding: 4em 0;
620 | @include vendor('display', 'flex');
621 | @include vendor('flex-direction', 'column');
622 | @include vendor('align-items', 'center');
623 | @include vendor('justify-content', 'center');
624 | @include vendor('transition', 'opacity 1s ease-in-out');
625 |
626 | body.is-preload & {
627 | opacity: 0;
628 | }
629 |
630 | @include breakpoint('<=large') {
631 | padding: 3em 0;
632 | max-width: calc(100% - 6em);
633 | }
634 |
635 | @include breakpoint('<=medium') {
636 | padding: 1.5em 0;
637 | max-width: calc(100% - 8em);
638 | }
639 |
640 | @include breakpoint('<=small') {
641 | padding: 1em 0;
642 | max-width: calc(100% - 2em);
643 | }
644 |
645 | @include breakpoint('<=xsmall') {
646 | padding: 1em 0;
647 | max-width: 100%;
648 | }
649 | }
650 |
651 | /* Main */
652 |
653 | #main {
654 | position: relative;
655 | overflow: hidden;
656 | width: 100%;
657 | background: #ffffff;
658 | box-shadow: 0px 1px 0px 0px rgba(0, 0, 0, 0.25);
659 | @include vendor('transition', (
660 | 'min-height 0.5s ease-in-out',
661 | 'max-height 0.5s ease-in-out'
662 | ));
663 |
664 | > .panel {
665 | @include vendor('transition', 'opacity 0.25s ease-in-out');
666 | margin-bottom: 0;
667 | position: relative;
668 | padding: 3.5em 2.5em 2.5em 2.5em;
669 | width: 100%;
670 |
671 | &.inactive {
672 | opacity: 0;
673 | }
674 |
675 | @include breakpoint('<=small') {
676 | padding: 2em 1.5em 1.5em 1.5em;
677 | }
678 |
679 | &.intro {
680 | padding: 0;
681 | height: 20em;
682 | @include vendor('display', 'flex');
683 | @include vendor('flex-direction', 'row');
684 | @include vendor('align-items', 'center');
685 |
686 | .pic {
687 | text-decoration: none;
688 | position: relative;
689 | @include vendor('flex-grow', '0');
690 | @include vendor('flex-shrink', '0');
691 | width: 17em;
692 | height: 100%;
693 |
694 | &:before {
695 | content: '';
696 | position: absolute;
697 | top: 0;
698 | left: 0;
699 | background: url('images/overlay.png');
700 | width: 100%;
701 | height: 100%;
702 | z-index: 1;
703 | }
704 |
705 | img {
706 | position: relative;
707 | display: block;
708 | position: absolute;
709 | top: 0;
710 | left: 0;
711 | width: 100%;
712 | height: 100%;
713 | @include vendor('object-fit', 'cover');
714 | @include vendor('object-position', 'center');
715 | }
716 |
717 | .arrow {
718 | display: block;
719 | position: absolute;
720 | right: 0;
721 | top: 50%;
722 | margin-top: -1.375em;
723 | width: 2.75em;
724 | height: 2.75em;
725 | background: #000;
726 | background: rgba(0, 0, 0, 0.75);
727 | color: #ffffff;
728 | text-align: center;
729 | line-height: 2.75em;
730 | font-size: 1.5em;
731 | z-index: 1;
732 | @include vendor('transition', ('width .15s ease-in-out', 'padding-right .15s ease-in-out'));
733 |
734 | &:before {
735 | position: relative;
736 | padding-right: 0;
737 | top: 0.125em;
738 | }
739 |
740 | span {
741 | display: block;
742 | text-indent: -9999px;
743 | }
744 | }
745 |
746 | &:hover {
747 | .arrow {
748 | width: 3em;
749 | padding-right: 0.25em;
750 | }
751 | }
752 | }
753 |
754 | header {
755 | @include vendor('flex-grow', '1');
756 | @include vendor('flex-shrink', '1');
757 | padding: 3.5em 2.5em;
758 | margin-bottom: 0;
759 | width: 100%;
760 |
761 | h1 {
762 | line-height: 1.25em;
763 | margin-bottom: 0;
764 | }
765 |
766 | p {
767 | letter-spacing: -0.015em;
768 | font-size: 1.25em;
769 | margin: 0.25em 0 0 0;
770 | }
771 | }
772 |
773 | @include breakpoint('<=medium') {
774 | @include vendor('flex-direction', 'column');
775 | height: auto;
776 |
777 | .pic {
778 | height: 25em;
779 | width: 100%;
780 | }
781 |
782 | header {
783 | padding: 4em;
784 | text-align: center;
785 | }
786 | }
787 |
788 | @include breakpoint('<=small') {
789 | .pic {
790 | height: 20em;
791 | }
792 |
793 | header {
794 | padding: 2.75em 2em 2.5em 2em;
795 |
796 | p {
797 | font-size: 1em;
798 | margin: 0.25em 0 0 0;
799 | }
800 | }
801 | }
802 | }
803 | }
804 | }
805 |
806 | /* Footer */
807 |
808 | #footer {
809 | color: rgba(255, 255, 255, 0.45);
810 | text-align: center;
811 | padding: 2em 0 0 0;
812 | font-size: 0.75em;
813 |
814 | a {
815 | color: #ddd;
816 | color: rgba(255, 255, 255, 0.65);
817 | @include vendor('transition', 'color .25s ease-in-out');
818 |
819 | &:hover {
820 | color: rgba(255, 255, 255, 1);
821 | }
822 | }
823 |
824 | .copyright {
825 | list-style: none;
826 | padding-left: 0;
827 |
828 | li {
829 | display: inline-block;
830 | padding-left: 1em;
831 | margin-left: 1em;
832 | border-left: solid 1px rgba(255, 255, 255, 0.25);
833 | line-height: 1;
834 |
835 | &:first-child {
836 | padding-left: 0;
837 | margin-left: 0;
838 | border-left: 0;
839 | }
840 | }
841 | }
842 |
843 | @include breakpoint('<=small') {
844 | .copyright {
845 | li {
846 | padding-left: 0.5em;
847 | margin-left: 0.5em;
848 | }
849 | }
850 | }
851 | }
--------------------------------------------------------------------------------
/assets/sass/noscript.scss:
--------------------------------------------------------------------------------
1 | @import 'libs/vars';
2 | @import 'libs/functions';
3 | @import 'libs/mixins';
4 | @import 'libs/vendor';
5 | @import 'libs/breakpoints';
6 | @import 'libs/html-grid';
7 |
8 | /*
9 | Astral by HTML5 UP
10 | html5up.net | @ajlkn
11 | Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
12 | */
13 |
14 | /* Wrapper */
15 |
16 | #wrapper {
17 | opacity: 1 !important;
18 | }
19 |
20 | /* Nav */
21 |
22 | #nav {
23 | a {
24 | opacity: 1.0;
25 |
26 | &:before,
27 | &:after {
28 | display: none;
29 | }
30 |
31 | span {
32 | top: 0;
33 | opacity: 1.0;
34 |
35 | &:after {
36 | display: none;
37 | }
38 | }
39 | }
40 | }
41 |
42 | /* Main */
43 |
44 | #main {
45 | background: none;
46 | box-shadow: none;
47 |
48 | > .panel {
49 | background: #ffffff;
50 | margin-bottom: 2em;
51 |
52 | &:last-child {
53 | margin-bottom: 0;
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/assets/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/assets/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/assets/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/assets/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/assets/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/assets/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/assets/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/assets/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/assets/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/assets/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/assets/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/assets/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/assets/webfonts/fa-v4compatibility.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-v4compatibility.ttf
--------------------------------------------------------------------------------
/assets/webfonts/fa-v4compatibility.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/fa-v4compatibility.woff2
--------------------------------------------------------------------------------
/assets/webfonts/wencang.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/assets/webfonts/wencang.woff
--------------------------------------------------------------------------------
/images/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/images/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/images/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/images/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/images/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/images/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/images/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/images/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/images/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/images/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/images/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/realzsan3/alms/4c2ca7a5953befd72f4fea8eaaa1d37c4a30e499/images/favicon/favicon.ico
--------------------------------------------------------------------------------
/images/favicon/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------