Добавлены настройки расширения, введена поддержка локализации, изменены и адаптированы иконки приложений
This commit is contained in:
17
extension/_locales/en/messages.json
Normal file
17
extension/_locales/en/messages.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"description": {
|
||||
"message": "Show viewers what song is playing on your broadcast"
|
||||
},
|
||||
"popup_title": {
|
||||
"message": "Connection Parameters"
|
||||
},
|
||||
"server_url_field_label": {
|
||||
"message": "Server URL"
|
||||
},
|
||||
"connect_button": {
|
||||
"message": "Connect"
|
||||
},
|
||||
"default_server_url": {
|
||||
"message": "ws://localhost:8000"
|
||||
}
|
||||
}
|
14
extension/_locales/ru/messages.json
Normal file
14
extension/_locales/ru/messages.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"description": {
|
||||
"message": "Покажите зрителям, какая песня играет на вашей трансляции"
|
||||
},
|
||||
"popup_title": {
|
||||
"message": "Параметры подключения"
|
||||
},
|
||||
"server_url_field_label": {
|
||||
"message": "URL сервера"
|
||||
},
|
||||
"connect_button": {
|
||||
"message": "Подключиться"
|
||||
}
|
||||
}
|
93
extension/fonts/OFL.txt
Normal file
93
extension/fonts/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2013 The Exo 2 Project Authors (https://github.com/NDISCOVER/Exo-2.0)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
extension/fonts/cyrillic-ext.woff2
Normal file
BIN
extension/fonts/cyrillic-ext.woff2
Normal file
Binary file not shown.
BIN
extension/fonts/cyrillic.woff2
Normal file
BIN
extension/fonts/cyrillic.woff2
Normal file
Binary file not shown.
BIN
extension/fonts/latin-ext.woff2
Normal file
BIN
extension/fonts/latin-ext.woff2
Normal file
Binary file not shown.
BIN
extension/fonts/latin.woff2
Normal file
BIN
extension/fonts/latin.woff2
Normal file
Binary file not shown.
BIN
extension/fonts/vietnamese.woff2
Normal file
BIN
extension/fonts/vietnamese.woff2
Normal file
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 3.2 KiB |
BIN
extension/images/icon/128x128.png
Normal file
BIN
extension/images/icon/128x128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
BIN
extension/images/icon/16x16.png
Normal file
BIN
extension/images/icon/16x16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 336 B |
BIN
extension/images/icon/48x48.png
Normal file
BIN
extension/images/icon/48x48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
21
extension/main.html
Normal file
21
extension/main.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>YT Music Live</title>
|
||||
<link rel="stylesheet" href="/styles/main.css" />
|
||||
<script src="/scripts/main.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="popup-title"></h1>
|
||||
<form id="settings-form">
|
||||
<div class="field">
|
||||
<input id="server-url-field" type="url" minlength="0" />
|
||||
<label for="server-url-field"></label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<input id="connect-button" type="submit" value="" />
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
@ -1,43 +0,0 @@
|
||||
const mutationObserverConfig = {
|
||||
attributes: true,
|
||||
childList: false,
|
||||
characterData: false,
|
||||
};
|
||||
|
||||
const connectWebSocket = () => {
|
||||
const ws = new WebSocket('ws://localhost:8000/ws/v1/plugin');
|
||||
const progressElement = document.querySelector('#progress-bar');
|
||||
const mutationObserver = new MutationObserver(() => {
|
||||
const promise = new Promise(resolve => {
|
||||
const playerBarElement = document.querySelector('ytmusic-player-bar');
|
||||
const metadataElement = playerBarElement.querySelector('.middle-controls > .content-info-wrapper');
|
||||
const titleElement = metadataElement.querySelector(`yt-formatted-string.title`);
|
||||
const subtitleElement = metadataElement.querySelector('span.subtitle > yt-formatted-string.byline');
|
||||
const imageElement = playerBarElement.querySelector('img');
|
||||
if (titleElement.textContent === '' || subtitleElement.length === 0) return;
|
||||
const data = {
|
||||
type: 'music',
|
||||
attributes: {
|
||||
title: titleElement.textContent,
|
||||
artists: subtitleElement.title.split('•')[0].trim(),
|
||||
progress: progressElement.ariaValueNow / progressElement.ariaValueMax,
|
||||
image: imageElement.src,
|
||||
},
|
||||
};
|
||||
ws.send(JSON.stringify(data));
|
||||
resolve();
|
||||
});
|
||||
promise.then();
|
||||
});
|
||||
|
||||
ws.onopen = () => {
|
||||
mutationObserver.observe(progressElement, mutationObserverConfig);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
mutationObserver.disconnect();
|
||||
connectWebSocket();
|
||||
};
|
||||
};
|
||||
|
||||
connectWebSocket();
|
@ -1,23 +1,35 @@
|
||||
{
|
||||
"name": "YT Music Live",
|
||||
"description": "YT Music Live",
|
||||
"version": "1.0",
|
||||
"manifest_version": 3,
|
||||
"action": {
|
||||
"default_icon": "icon.png"
|
||||
"name": "YT Music Live",
|
||||
"version": "1.0.0",
|
||||
"description": "__MSG_description__",
|
||||
"icons": {
|
||||
"16": "/images/icon/16x16.png",
|
||||
"48": "/images/icon/48x48.png",
|
||||
"128": "/images/icon/128x128.png"
|
||||
},
|
||||
"action": {
|
||||
"default_popup": "/main.html"
|
||||
},
|
||||
"author": "csasq@csasq.ru",
|
||||
"content_scripts": [
|
||||
{
|
||||
"js": [
|
||||
"main.js"
|
||||
"/scripts/observer.js"
|
||||
],
|
||||
"matches": [
|
||||
"*://music.youtube.com/*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"default_locale": "en",
|
||||
"incognito": "not_allowed",
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"scripting"
|
||||
]
|
||||
"scripting",
|
||||
"storage"
|
||||
],
|
||||
"storage": {
|
||||
"managed_schema": "/storage-schema.json"
|
||||
}
|
||||
}
|
||||
|
41
extension/scripts/main.js
Normal file
41
extension/scripts/main.js
Normal file
@ -0,0 +1,41 @@
|
||||
const updateFields = () => {
|
||||
document.querySelectorAll('input, textarea').forEach(field => {
|
||||
const focus = () => field.classList.add('focus')
|
||||
if (field.value.trim() !== '') focus()
|
||||
field.onfocus = focus
|
||||
field.onblur = () => {
|
||||
if (field.value === '') field.classList.remove('focus')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const popupTitle = document.querySelector('#popup-title')
|
||||
const settingsForm = document.querySelector('#settings-form')
|
||||
const serverURLField = document.querySelector('#server-url-field')
|
||||
const serverURLFieldLabel = document.querySelector('label[for="server-url-field"]')
|
||||
const connectButton = document.querySelector('#connect-button')
|
||||
|
||||
const defaultServerURL = chrome.i18n.getMessage('deafult_server_url')
|
||||
|
||||
popupTitle.textContent = chrome.i18n.getMessage('popup_title')
|
||||
serverURLFieldLabel.textContent = chrome.i18n.getMessage('server_url_field_label')
|
||||
connectButton.value = chrome.i18n.getMessage('connect_button')
|
||||
|
||||
chrome.storage.local.get([
|
||||
'server_url',
|
||||
]).then((data) => {
|
||||
serverURLField.placeholder = defaultServerURL
|
||||
serverURLField.value = data.server_url || defaultServerURL
|
||||
updateFields()
|
||||
})
|
||||
|
||||
settingsForm.addEventListener('submit', (event) => {
|
||||
event.preventDefault()
|
||||
chrome.storage.local.set({
|
||||
'server_url': serverURLField.value.trim() || defaultServerURL,
|
||||
}).then(() => {
|
||||
window.close()
|
||||
})
|
||||
})
|
||||
})
|
71
extension/scripts/observer.js
Normal file
71
extension/scripts/observer.js
Normal file
@ -0,0 +1,71 @@
|
||||
const uiLocale = chrome.i18n.getMessage('@@ui_locale')
|
||||
const defaultServerURL = chrome.i18n.getMessage('default_server_url')
|
||||
|
||||
const getURL = () => {
|
||||
return new Promise(resolve => {
|
||||
chrome.storage.local.get([
|
||||
'server_url',
|
||||
]).then((data) => {
|
||||
const serverURL = data.server_url || defaultServerURL
|
||||
const url = new URL(serverURL)
|
||||
url.pathname = '/ws/v1/server'
|
||||
resolve(url)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const mutationObserverConfig = {
|
||||
attributes: true,
|
||||
childList: false,
|
||||
characterData: false,
|
||||
}
|
||||
|
||||
const connectWebSocket = async () => {
|
||||
const url = await getURL()
|
||||
const ws = new WebSocket(url)
|
||||
const progressElement = document.querySelector('#progress-bar')
|
||||
const mutationObserver = new MutationObserver(() => {
|
||||
const promise = new Promise(resolve => {
|
||||
const playerBarElement = document.querySelector('ytmusic-player-bar')
|
||||
const metadataElement = playerBarElement.querySelector('.middle-controls > .content-info-wrapper')
|
||||
const titleElement = metadataElement.querySelector(`yt-formatted-string.title`)
|
||||
const subtitleElement = metadataElement.querySelector('span.subtitle > yt-formatted-string.byline')
|
||||
const imageElement = playerBarElement.querySelector('img')
|
||||
if (titleElement.textContent === '' || subtitleElement.length === 0) return
|
||||
const data = {
|
||||
type: 'music',
|
||||
attributes: {
|
||||
locale: uiLocale,
|
||||
title: titleElement.textContent,
|
||||
artists: subtitleElement.title.split('•')[0].trim(),
|
||||
progress: progressElement.ariaValueNow / progressElement.ariaValueMax,
|
||||
image: imageElement.src,
|
||||
},
|
||||
}
|
||||
ws.send(JSON.stringify(data))
|
||||
resolve()
|
||||
})
|
||||
promise.then()
|
||||
})
|
||||
|
||||
ws.onopen = () => mutationObserver.observe(progressElement, mutationObserverConfig)
|
||||
|
||||
ws.onclose = () => {
|
||||
mutationObserver.disconnect()
|
||||
wsPromise = connectWebSocket()
|
||||
}
|
||||
|
||||
return ws
|
||||
}
|
||||
|
||||
chrome.storage.onChanged.addListener((changes) => {
|
||||
const settings = {}
|
||||
for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
|
||||
settings[key] = newValue || oldValue
|
||||
}
|
||||
chrome.storage.local.set(settings).then(() => {
|
||||
wsPromise.then(ws => ws.close())
|
||||
})
|
||||
})
|
||||
|
||||
let wsPromise = connectWebSocket()
|
8
extension/storage-schema.json
Normal file
8
extension/storage-schema.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
330
extension/styles/main.css
Normal file
330
extension/styles/main.css
Normal file
@ -0,0 +1,330 @@
|
||||
@font-face {
|
||||
font-family: 'Exo 2';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
src: url('/fonts/cyrillic-ext.woff2') format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Exo 2';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
src: url('/fonts/cyrillic.woff2') format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Exo 2';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
src: url('/fonts/vietnamese.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Exo 2';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
src: url('/fonts/latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Exo 2';
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
src: url('/fonts/latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
:root {
|
||||
--color-1: rgb(150, 15, 38);
|
||||
--color-2: rgb(87, 30, 40);
|
||||
--dark-1: rgba(0, 0, 0, .1);
|
||||
--dark-2: rgba(0, 0, 0, .2);
|
||||
--box-shadow-1:
|
||||
0 .375rem .625rem .25rem rgba(0, 0, 0, .15),
|
||||
0 .1875rem .1875rem rgba(0, 0, 0, .3);
|
||||
--box-shadow-2:
|
||||
0 .5rem .75rem .375rem rgba(0, 0, 0, .15),
|
||||
0 .25rem .25rem rgba(0, 0, 0, .3);
|
||||
--linear-gradient: linear-gradient(to top, var(--color-1), var(--color-2));
|
||||
}
|
||||
|
||||
*:not(input, textarea, label) {
|
||||
color: white;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 24rem;
|
||||
background-image: var(--linear-gradient);
|
||||
background-position: center;
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
font-family: 'Exo 2', sans-serif;
|
||||
font-size: 16px;
|
||||
scroll-behavior: smooth;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
max-width: 100%;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 1.25rem 0;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
div.field {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: white;
|
||||
color: black;
|
||||
box-shadow: var(--box-shadow-2);
|
||||
border-radius: 1rem;
|
||||
font-family: 'Exo 2', sans-serif;
|
||||
font-size: 1rem;
|
||||
transition: box-shadow, font-size .4s;
|
||||
}
|
||||
|
||||
label {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
input:read-only {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
input[type='text'],
|
||||
input[type='email'],
|
||||
input[type='tel'],
|
||||
input[type='url'],
|
||||
input[type='password'],
|
||||
input[type='number'],
|
||||
input[type='search'],
|
||||
input[type='datetime-local'],
|
||||
input[type='date'],
|
||||
input[type='month'],
|
||||
input[type='week'],
|
||||
input[type='time'],
|
||||
textarea {
|
||||
padding: 1.5rem 1rem .75rem 1rem;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 8rem;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
input[type='text'] + label,
|
||||
input[type='email'] + label,
|
||||
input[type='tel'] + label,
|
||||
input[type='url'] + label,
|
||||
input[type='password'] + label,
|
||||
input[type='number'] + label,
|
||||
input[type='search'] + label,
|
||||
input[type='datetime-local'] + label,
|
||||
input[type='date'] + label,
|
||||
input[type='month'] + label,
|
||||
input[type='week'] + label,
|
||||
input[type='time'] + label,
|
||||
textarea + label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 1rem;
|
||||
color: black;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
pointer-events: none;
|
||||
transition: all .1s;
|
||||
}
|
||||
|
||||
input[type='text'].focus + label,
|
||||
input[type='email'].focus + label,
|
||||
input[type='tel'].focus + label,
|
||||
input[type='url'].focus + label,
|
||||
input[type='password'].focus + label,
|
||||
input[type='number'].focus + label,
|
||||
input[type='search'].focus + label,
|
||||
input[type='datetime-local'].focus + label,
|
||||
input[type='date'].focus + label,
|
||||
input[type='month'].focus + label,
|
||||
input[type='week'].focus + label,
|
||||
input[type='time'].focus + label,
|
||||
textarea.focus + label {
|
||||
padding-top: .5rem;
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
input[type='text']:required + label::after,
|
||||
input[type='email']:required + label::after,
|
||||
input[type='tel']:required + label::after,
|
||||
input[type='url']:required + label::after,
|
||||
input[type='password']:required + label::after,
|
||||
input[type='number']:required + label::after,
|
||||
input[type='search']:required + label::after,
|
||||
input[type='datetime-local']:required + label::after,
|
||||
input[type='date']:required + label::after,
|
||||
input[type='month']:required + label::after,
|
||||
input[type='week']:required + label::after,
|
||||
input[type='time']:required + label::after,
|
||||
textarea:required + label::after {
|
||||
content: '*';
|
||||
color: var(--color-1);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input[type='text']::placeholder,
|
||||
input[type='email']::placeholder,
|
||||
input[type='tel']::placeholder,
|
||||
input[type='url']::placeholder,
|
||||
input[type='password']::placeholder,
|
||||
input[type='number']::placeholder,
|
||||
input[type='search']::placeholder,
|
||||
input[type='datetime-local']::placeholder,
|
||||
input[type='date']::placeholder,
|
||||
input[type='month']::placeholder,
|
||||
input[type='week']::placeholder,
|
||||
input[type='time']::placeholder,
|
||||
textarea.focus + label {
|
||||
opacity: 0;
|
||||
transition: all .4s;
|
||||
}
|
||||
|
||||
input[type='text'].focus::placeholder,
|
||||
input[type='email'].focus::placeholder,
|
||||
input[type='tel'].focus::placeholder,
|
||||
input[type='url'].focus::placeholder,
|
||||
input[type='password'].focus::placeholder,
|
||||
input[type='number'].focus::placeholder,
|
||||
input[type='search'].focus::placeholder,
|
||||
input[type='datetime-local'].focus::placeholder,
|
||||
input[type='date'].focus::placeholder,
|
||||
input[type='month'].focus::placeholder,
|
||||
input[type='week'].focus::placeholder,
|
||||
input[type='time'].focus::placeholder,
|
||||
textarea.focus + label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input[type='datetime-local']:not(.focus)::-webkit-datetime-edit-fields-wrapper,
|
||||
input[type='date']:not(.focus)::-webkit-datetime-edit-fields-wrapper,
|
||||
input[type='month']:not(.focus)::-webkit-datetime-edit-fields-wrapper,
|
||||
input[type='week']:not(.focus)::-webkit-datetime-edit-fields-wrapper,
|
||||
input[type='time']:not(.focus)::-webkit-datetime-edit-fields-wrapper {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
input[type='button'],
|
||||
input[type='submit'] {
|
||||
padding: 1.125rem 1rem;
|
||||
background: var(--dark-1);
|
||||
box-shadow: var(--box-shadow-2);
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: all .4s;
|
||||
}
|
||||
|
||||
input[type='button']:not(:disabled):hover,
|
||||
input[type='submit']:not(:disabled):hover {
|
||||
background: var(--dark-2);
|
||||
}
|
||||
|
||||
input[type='button']:not(:disabled):focus,
|
||||
input[type='submit']:not(:disabled):focus {
|
||||
background: var(--dark-2);
|
||||
box-shadow: var(--box-shadow-1);
|
||||
}
|
||||
|
||||
input[type='button']:not(:disabled):active,
|
||||
input[type='submit']:not(:disabled):active {
|
||||
background: var(--dark-2);
|
||||
box-shadow: var(--box-shadow-1);
|
||||
}
|
||||
|
||||
input[type='button']:disabled,
|
||||
input[type='submit']:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
input[type='text'][data-error],
|
||||
input[type='email'][data-error],
|
||||
input[type='number'][data-error],
|
||||
input[type='password'][data-error],
|
||||
textarea[data-error] {
|
||||
background: var(--color-1);
|
||||
}
|
||||
|
||||
input[type='text'][data-error] + label,
|
||||
input[type='email'][data-error] + label,
|
||||
input[type='number'][data-error] + label,
|
||||
input[type='password'][data-error] + label,
|
||||
textarea[data-error] + label {
|
||||
color: white;
|
||||
}
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label,
|
||||
input[type="radio"] + label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label,
|
||||
input[type="radio"]:checked + label {
|
||||
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cpath d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" fill="white" opacity=".3" /%3E%3C/svg%3E');
|
||||
background-repeat: no-repeat no-repeat;
|
||||
background-size: 4rem;
|
||||
background-attachment: local;
|
||||
background-position: right bottom;
|
||||
}
|
||||
|
||||
input[type='checkbox']:disabled + label,
|
||||
input[type='radio']:disabled + label {
|
||||
cursor: not-allowed;
|
||||
}
|
Reference in New Issue
Block a user