updated plugin AudioIgniter
version 1.9.0
This commit is contained in:
parent
b49569de47
commit
8af91729f1
@ -1,155 +1,640 @@
|
|||||||
@charset "UTF-8";
|
@charset "UTF-8";
|
||||||
@keyframes ai-spin { 0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); } }
|
|
||||||
@keyframes backgroundPosition { 0% { background-position: -140px 0; }
|
|
||||||
100% { background-position: 140px 0; } }
|
|
||||||
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; }
|
|
||||||
|
|
||||||
.ai-row { margin-left: -15px; margin-right: -15px; box-sizing: border-box; }
|
@keyframes ai-spin {
|
||||||
.ai-row::after { content: ""; display: table; clear: both; }
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
[class^="ai-col"] { float: left; padding-left: 15px; padding-right: 15px; width: 50%; box-sizing: border-box; }
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ai-btn { display: inline-block; font-weight: normal; margin: 0; line-height: normal; border: 0; box-shadow: none; text-align: center; vertical-align: middle; cursor: pointer; white-space: nowrap; user-select: none; border-radius: 2px; width: auto; height: auto; background-image: none; padding: 11px 20px 11px; font-size: 12px; text-transform: uppercase; background-color: #1c4866; color: #ffffff; text-decoration: none; }
|
@keyframes backgroundPosition {
|
||||||
.ai-btn:hover, .ai-btn:focus { color: #ffffff; background-color: #173a52; }
|
0% {
|
||||||
|
background-position: -140px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-btn-green { background-color: #14b552; }
|
100% {
|
||||||
.ai-btn-green:hover, .ai-btn-green:focus { color: #ffffff; background-color: #119e48; }
|
background-position: 140px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ai-brand-module { background-color: #1c4866; padding: 15px; color: #ffffff; font-size: 12px; }
|
.sr-only {
|
||||||
.ai-brand-module p { font-size: 12px; }
|
position: absolute;
|
||||||
.ai-brand-module a:not(.ai-btn) { color: #ffcc00; text-decoration: none; }
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-brand-module-actions { text-align: right; }
|
.ai-row {
|
||||||
.ai-brand-module-actions p { margin: 0; }
|
margin-left: -15px;
|
||||||
|
margin-right: -15px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-header { margin: 12px 0 -12px; height: 40px; }
|
.ai-row::after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-header-actions { text-align: right; }
|
[class^="ai-col"] {
|
||||||
|
float: left;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
width: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-logo { display: inline-block; position: relative; top: -2px; }
|
.ai-btn {
|
||||||
.ai-logo img { height: 44px; }
|
display: inline-block;
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0;
|
||||||
|
line-height: normal;
|
||||||
|
border: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
border-radius: 2px;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
background-image: none;
|
||||||
|
padding: 11px 20px 11px;
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-color: #1c4866;
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-note { font-style: italic; }
|
.ai-btn:hover,
|
||||||
|
.ai-btn:focus {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #173a52;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-list-inline { margin: 0; padding: 0; list-style: none; }
|
.ai-btn-green {
|
||||||
.ai-list-inline li { display: inline-block; margin: 0; }
|
background-color: #14b552;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-footer-links a::after { content: "\007c"; color: #ffffff; opacity: .5; margin: 0 7px; }
|
.ai-btn-green:hover,
|
||||||
.ai-footer-links li:last-child a::after { display: none; }
|
.ai-btn-green:focus {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #119e48;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-module { border: 1px solid #eeeeee; margin-top: 12px; padding: 15px; }
|
.ai-brand-module {
|
||||||
.ai-module::after { content: ""; display: table; clear: both; }
|
background-color: #1c4866;
|
||||||
|
padding: 15px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-container { margin-top: 12px; }
|
.ai-brand-module p {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-controls-wrap { padding: 15px; border: 1px solid #eeeeee; }
|
.ai-brand-module a:not(.ai-btn) {
|
||||||
.ai-field-controls-wrap::after { content: ""; display: table; clear: both; }
|
color: #ffcc00;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-controls { float: left; }
|
.ai-brand-module-actions {
|
||||||
.ai-field-controls .button { margin-right: 5px; }
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-controls-visibility { float: right; padding-top: 4px; }
|
.ai-brand-module-actions p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-controls-visibility a { text-decoration: none; }
|
.ai-header {
|
||||||
|
margin: 12px 0 -12px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-fields-expand-all { margin-right: 8px; padding-right: 6px; border-right: 1px solid #f1f1f1; }
|
.ai-header-actions {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-fields-container { padding: 15px; border-left: 1px solid #eeeeee; border-right: 1px solid #eeeeee; }
|
.ai-logo {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-repeatable { margin-bottom: 15px; border: 1px solid #d7d7d7; box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.07); }
|
.ai-logo img {
|
||||||
.ai-field-repeatable:last-child { margin-bottom: 0; }
|
height: 44px;
|
||||||
.ai-field-repeatable:only-child .ai-remove-field { display: none; }
|
}
|
||||||
|
|
||||||
.ai-field-container { padding: 15px; background-color: #ffffff; }
|
.ai-note {
|
||||||
.ai-field-container::after { content: ""; display: table; clear: both; }
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-head { padding: 8px 15px 5px; line-height: normal; background-color: #d7d7d7; background: linear-gradient(to bottom, #f1f1f1, #d7d7d7); border-bottom: 1px solid #cccccc; }
|
.ai-list-inline {
|
||||||
.ai-field-head::after { content: ""; display: table; clear: both; }
|
margin: 0;
|
||||||
.ai-field-head .toggle-indicator { border-radius: 50%; }
|
padding: 0;
|
||||||
.ai-fields-sortable .ai-field-head { cursor: move; }
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-sort-handle { position: relative; top: 1px; color: #0073aa; }
|
.ai-list-inline li {
|
||||||
.ai-field-sort-handle .dashicons { font-size: 18px; }
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-title { font-weight: bold; font-size: 1.05em; margin-left: 8px; padding-top: 3px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; max-width: 80%; display: inline-block; }
|
.ai-footer-links a::after {
|
||||||
|
content: "\007c";
|
||||||
|
color: #ffffff;
|
||||||
|
opacity: .5;
|
||||||
|
margin: 0 7px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-toggle { float: right; }
|
.ai-footer-links li:last-child a::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-cover { float: left; width: 100px; height: 100px; margin-right: 15px; background-color: #eeeeee; border: 1px solid #cccccc; }
|
.ai-module {
|
||||||
|
border: 1px solid #eeeeee;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-split { float: left; width: calc(50% - 71px); margin-right: 15px; }
|
.ai-module::after {
|
||||||
.ai-field-split:nth-child(2n + 1) { margin-right: 0; }
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-container .button .dashicons, .ai-module .button .dashicons { font-size: 1.2em; line-height: 1.7em; }
|
.ai-container {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-form-field-group { padding: 15px; border: 1px solid #f1f1f1; margin-bottom: 15px; }
|
.ai-field-controls-wrap {
|
||||||
.ai-form-field-group :last-child { margin-bottom: 0; }
|
padding: 15px;
|
||||||
.ai-form-field-group-title { margin-top: 0; }
|
border: 1px solid #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-form-field { margin-bottom: 15px; }
|
.ai-field-controls-wrap::after {
|
||||||
.ai-form-field label { display: inline-block; font-weight: bold; margin-bottom: 3px; }
|
content: "";
|
||||||
.ai-form-field input[type="text"], .ai-form-field input[type="url"], .ai-form-field input[type="search"], .ai-form-field input[type="email"], .ai-form-field input[type="password"], .ai-form-field input[type="number"], .ai-form-field input[type="tel"], .ai-form-field input[type="date"], .ai-form-field textarea { width: 100%; }
|
display: table;
|
||||||
.ai-form-field input[type="checkbox"], .ai-form-field input[type="radio"] { display: inline-block; position: relative; top: 1px; }
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-module-settings .ai-form-field input[type="text"], .ai-module-settings .ai-form-field input[type="url"], .ai-module-settings .ai-form-field input[type="search"], .ai-module-settings .ai-form-field input[type="email"], .ai-module-settings .ai-form-field input[type="password"], .ai-module-settings .ai-form-field input[type="number"], .ai-module-settings .ai-form-field input[type="tel"], .ai-module-settings .ai-form-field input[type="date"], .ai-module-settings .ai-form-field textarea, .ai-module-settings .ai-form-field select { width: 200px; max-width: 100%; display: block; }
|
.ai-field-controls {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-form-field-addon { position: relative; }
|
.ai-field-controls .button {
|
||||||
.ai-form-field-addon input { padding-right: 80px; }
|
margin-right: 5px;
|
||||||
.ai-form-field-addon button { position: absolute; top: 0; right: -2px; }
|
}
|
||||||
|
|
||||||
.ai-field-help { margin: 5px 0 0; font-style: italic; color: #999; }
|
.ai-field-controls-visibility {
|
||||||
|
float: right;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-remove-field { float: right; }
|
.ai-field-controls-visibility a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-upload-cover { display: block; position: relative; width: 100px; height: 100px; text-decoration: none; color: initial; overflow: hidden; }
|
.ai-fields-expand-all {
|
||||||
.ai-field-upload-cover img { max-width: 100%; display: none; }
|
margin-right: 8px;
|
||||||
|
padding-right: 6px;
|
||||||
|
border-right: 1px solid #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-has-cover .ai-remove-cover { display: block; }
|
.ai-fields-container {
|
||||||
.ai-has-cover .ai-field-cover-placeholder { display: none; }
|
padding: 15px;
|
||||||
.ai-has-cover img { display: inline-block; }
|
border-left: 1px solid #eeeeee;
|
||||||
|
border-right: 1px solid #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-cover-placeholder { text-align: center; font-style: normal; font-size: .9em; opacity: .8; padding-top: 28px; }
|
.ai-field-repeatable {
|
||||||
.ai-field-cover-placeholder::before { content: ""; display: inline-block; font: 400 20px/1 dashicons; speak: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-decoration: none !important; display: block; }
|
margin-bottom: 15px;
|
||||||
.ai-track-loading .ai-field-cover-placeholder::before { content: "\f463"; animation: rotation 1.2s infinite linear; }
|
border: 1px solid #d7d7d7;
|
||||||
|
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.07);
|
||||||
|
}
|
||||||
|
|
||||||
.ai-remove-cover { color: #ffffff; background-color: #ff0000; width: 16px; height: 16px; font-size: 12px; cursor: pointer; position: absolute; top: 0; right: 0; opacity: .9; transition: opacity 0.18s ease-in; display: none; text-align: center; }
|
.ai-field-repeatable:last-child {
|
||||||
.ai-remove-cover:hover { opacity: 1; }
|
margin-bottom: 0;
|
||||||
.ai-remove-cover .dashicons { font-size: 16px; width: 100%; height: 100%; }
|
}
|
||||||
|
|
||||||
.ai-remove-all-fields .dashicons, .ai-remove-field .dashicons { color: #ff0000; }
|
.ai-field-repeatable:only-child .ai-remove-field {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-add-field-batch .dashicons, .ai-add-field .dashicons { color: #0073aa; }
|
.ai-field-container {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-info-box { background: #fffce6; color: #948832; font-size: 12px; border: solid 1px #eeeac9; padding: 15px; margin: 0 0 15px 0; }
|
.ai-field-container::after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-player-type-message { display: none; }
|
.ai-field-container-links {
|
||||||
|
display: flex;
|
||||||
|
grid-gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-drop-placeholder { background-color: #f1f1f1; border: 2px dashed #cccccc; opacity: 0.5; margin-bottom: 15px; }
|
.ai-field-container-links .ai-field-split {
|
||||||
|
width: 50%;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-collapsed .ai-field-container { display: none; }
|
.ai-field-head {
|
||||||
.ai-collapsed .toggle-indicator::before { content: "\f140" !important; }
|
padding: 8px 15px 5px;
|
||||||
|
line-height: normal;
|
||||||
|
background-color: #d7d7d7;
|
||||||
|
background: linear-gradient(to bottom, #f1f1f1, #d7d7d7);
|
||||||
|
border-bottom: 1px solid #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-module-shortcode .code { display: block; width: 100%; margin-top: 3px; padding: 10px 10px 8px; font-weight: bold; background: #f1f1f1; }
|
.ai-field-head::after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-sync-soundcloud.button { display: none; }
|
.ai-field-head .toggle-indicator {
|
||||||
.ai-sync-soundcloud.button::before { content: "\f463"; color: #d54e21; display: inline-block; font: 400 19px/1 dashicons; speak: none; position: relative; left: -1px; top: 4px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; vertical-align: top; }
|
border-radius: 50%;
|
||||||
.ai-track-loading .ai-sync-soundcloud.button::before { animation: rotation 1.2s infinite linear; }
|
}
|
||||||
|
|
||||||
.ai-soundcloud-track .ai-sync-soundcloud { display: inline-block; }
|
.ai-fields-sortable .ai-field-head {
|
||||||
.ai-soundcloud-track .ai-upload { display: none; }
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 1100px) { .ai-field-controls, .ai-field-controls-visibility { margin: 0; float: none; width: 100%; }
|
.ai-field-sort-handle {
|
||||||
.ai-field-controls { margin-bottom: 5px; }
|
position: relative;
|
||||||
.ai-field-split { float: none; width: 100%; }
|
top: 1px;
|
||||||
.ai-field-cover { margin-bottom: 15px; }
|
color: #0073aa;
|
||||||
.ai-footer { text-align: center; }
|
}
|
||||||
.ai-footer .ai-brand-module-actions { text-align: center; margin-top: 10px; }
|
|
||||||
.ai-footer [class^="ai-col"] { width: 100%; } }
|
.ai-field-sort-handle .dashicons {
|
||||||
@media (max-width: 782px) { .ai-container .button .dashicons, .ai-module .button .dashicons { line-height: 1.2em; }
|
font-size: 18px;
|
||||||
.ai-form-field-addon .button { top: 2px; } }
|
}
|
||||||
@media (max-width: 600px) { .ai-field-controls .button { width: 100%; }
|
|
||||||
.ai-header { text-align: center; }
|
.ai-field-title {
|
||||||
.ai-header .ai-brand-module-actions { margin-top: 10px; }
|
font-weight: bold;
|
||||||
.ai-header .ai-btn { display: block; }
|
font-size: 1.05em;
|
||||||
.ai-header [class^="ai-col"] { width: 100%; } }
|
margin-left: 8px;
|
||||||
|
padding-top: 3px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 80%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-toggle {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-cover {
|
||||||
|
float: left;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
margin-right: 15px;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-split {
|
||||||
|
float: left;
|
||||||
|
width: calc(50% - 71px);
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-split:nth-child(2n + 1) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-container .button .dashicons,
|
||||||
|
.ai-module .button .dashicons {
|
||||||
|
font-size: 1.2em;
|
||||||
|
line-height: 1.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-group {
|
||||||
|
padding: 15px;
|
||||||
|
border: 1px solid #f1f1f1;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-group :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-group-title {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field label {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field input[type="text"],
|
||||||
|
.ai-form-field input[type="url"],
|
||||||
|
.ai-form-field input[type="search"],
|
||||||
|
.ai-form-field input[type="email"],
|
||||||
|
.ai-form-field input[type="password"],
|
||||||
|
.ai-form-field input[type="number"],
|
||||||
|
.ai-form-field input[type="tel"],
|
||||||
|
.ai-form-field input[type="date"],
|
||||||
|
.ai-form-field textarea,
|
||||||
|
.ai-form-field select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field input[type="checkbox"],
|
||||||
|
.ai-form-field input[type="radio"] {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-module-settings .ai-form-field input[type="text"],
|
||||||
|
.ai-module-settings .ai-form-field input[type="url"],
|
||||||
|
.ai-module-settings .ai-form-field input[type="search"],
|
||||||
|
.ai-module-settings .ai-form-field input[type="email"],
|
||||||
|
.ai-module-settings .ai-form-field input[type="password"],
|
||||||
|
.ai-module-settings .ai-form-field input[type="number"],
|
||||||
|
.ai-module-settings .ai-form-field input[type="tel"],
|
||||||
|
.ai-module-settings .ai-form-field input[type="date"],
|
||||||
|
.ai-module-settings .ai-form-field textarea,
|
||||||
|
.ai-module-settings .ai-form-field select {
|
||||||
|
width: 200px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-addon {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-addon input {
|
||||||
|
padding-right: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-addon button {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-help {
|
||||||
|
margin: 5px 0 0;
|
||||||
|
font-style: italic;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-checkbox-secondary {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-remove-field {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-upload-cover {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: initial;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-upload-cover img {
|
||||||
|
max-width: 100%;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-has-cover .ai-remove-cover {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-has-cover .ai-field-cover-placeholder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-has-cover img {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-cover-placeholder {
|
||||||
|
text-align: center;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: .9em;
|
||||||
|
opacity: .8;
|
||||||
|
padding-top: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-cover-placeholder::before {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
font: 400 20px/1 dashicons;
|
||||||
|
speak: none;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-decoration: none !important;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-track-loading .ai-field-cover-placeholder::before {
|
||||||
|
content: "\f463";
|
||||||
|
animation: rotation 1.2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-remove-cover {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #ff0000;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
opacity: .9;
|
||||||
|
transition: opacity 0.18s ease-in;
|
||||||
|
display: none;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-remove-cover:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-remove-cover .dashicons {
|
||||||
|
font-size: 16px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-remove-all-fields .dashicons,
|
||||||
|
.ai-remove-field .dashicons {
|
||||||
|
color: #ff0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-add-field-batch .dashicons,
|
||||||
|
.ai-add-field .dashicons {
|
||||||
|
color: #0073aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-info-box {
|
||||||
|
background: #fffce6;
|
||||||
|
color: #948832;
|
||||||
|
font-size: 12px;
|
||||||
|
border: solid 1px #eeeac9;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-player-type-message {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-drop-placeholder {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
border: 2px dashed #cccccc;
|
||||||
|
opacity: 0.5;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-collapsed .ai-field-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-collapsed .toggle-indicator::before {
|
||||||
|
content: "\f140" !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-module-shortcode .code {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 3px;
|
||||||
|
padding: 10px 10px 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-sync-soundcloud.button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-sync-soundcloud.button::before {
|
||||||
|
content: "\f463";
|
||||||
|
color: #d54e21;
|
||||||
|
display: inline-block;
|
||||||
|
font: 400 19px/1 dashicons;
|
||||||
|
speak: none;
|
||||||
|
position: relative;
|
||||||
|
left: -1px;
|
||||||
|
top: 4px;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-track-loading .ai-sync-soundcloud.button::before {
|
||||||
|
animation: rotation 1.2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-soundcloud-track .ai-sync-soundcloud {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-soundcloud-track .ai-upload {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1100px) {
|
||||||
|
.ai-field-controls,
|
||||||
|
.ai-field-controls-visibility {
|
||||||
|
margin: 0;
|
||||||
|
float: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-controls {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-container-links {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-container-links .ai-field-split,
|
||||||
|
.ai-field-split {
|
||||||
|
float: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-cover {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-footer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-footer .ai-brand-module-actions {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-footer [class^="ai-col"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 782px) {
|
||||||
|
.ai-container .button .dashicons,
|
||||||
|
.ai-module .button .dashicons {
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-form-field-addon .button {
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.ai-field-controls .button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-header {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-header .ai-brand-module-actions {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-header .ai-btn {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-header [class^="ai-col"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -241,6 +241,16 @@ $border-color: $lighter-grey !default;
|
|||||||
background-color: $white;
|
background-color: $white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-field-container-links {
|
||||||
|
display: flex;
|
||||||
|
grid-gap: 20px;
|
||||||
|
|
||||||
|
.ai-field-split {
|
||||||
|
width: 50%;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ai-field-head {
|
.ai-field-head {
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
padding: 8px $base-pad 5px;
|
padding: 8px $base-pad 5px;
|
||||||
@ -347,7 +357,8 @@ $border-color: $lighter-grey !default;
|
|||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="tel"],
|
input[type="tel"],
|
||||||
input[type="date"],
|
input[type="date"],
|
||||||
textarea {
|
textarea,
|
||||||
|
select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,6 +409,10 @@ $border-color: $lighter-grey !default;
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-form-field-checkbox-secondary {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
.ai-remove-field {
|
.ai-remove-field {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
@ -595,6 +610,11 @@ $border-color: $lighter-grey !default;
|
|||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-field-container-links {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-field-container-links .ai-field-split,
|
||||||
.ai-field-split {
|
.ai-field-split {
|
||||||
float: none;
|
float: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -19,6 +19,7 @@ jQuery(function($) {
|
|||||||
removeFieldButtonClassName: ".ai-remove-field",
|
removeFieldButtonClassName: ".ai-remove-field",
|
||||||
$removeAllTracksButton: $(".ai-remove-all-fields"),
|
$removeAllTracksButton: $(".ai-remove-all-fields"),
|
||||||
$batchUploadButton: $(".ai-add-field-batch"),
|
$batchUploadButton: $(".ai-add-field-batch"),
|
||||||
|
$trackDownloadUsesTrackUrlButton: $(".ai-use-track-url-download"),
|
||||||
audioUploadButtonClassName: ".ai-upload",
|
audioUploadButtonClassName: ".ai-upload",
|
||||||
coverUploadButtonClassName: ".ai-field-upload-cover",
|
coverUploadButtonClassName: ".ai-field-upload-cover",
|
||||||
coverRemoveClassName: ".ai-remove-cover",
|
coverRemoveClassName: ".ai-remove-cover",
|
||||||
@ -27,6 +28,8 @@ jQuery(function($) {
|
|||||||
trackArtistClassName: ".ai-track-artist",
|
trackArtistClassName: ".ai-track-artist",
|
||||||
trackLyricsClassName: ".ai-track-lyrics",
|
trackLyricsClassName: ".ai-track-lyrics",
|
||||||
trackUrlClassName: ".ai-track-url",
|
trackUrlClassName: ".ai-track-url",
|
||||||
|
trackDownloadUrlClassName: ".ai-track-download-url",
|
||||||
|
trackDownloadUsesTrackUrlClassName: ".ai-track-download-uses-track-url",
|
||||||
hasCoverClass: "ai-has-cover",
|
hasCoverClass: "ai-has-cover",
|
||||||
fieldHeadClassName: ".ai-field-head",
|
fieldHeadClassName: ".ai-field-head",
|
||||||
fieldCollapsedClass: "ai-collapsed",
|
fieldCollapsedClass: "ai-collapsed",
|
||||||
@ -113,7 +116,7 @@ jQuery(function($) {
|
|||||||
|
|
||||||
$field.attr("data-uid", newHash);
|
$field.attr("data-uid", newHash);
|
||||||
$field
|
$field
|
||||||
.find("input, textarea")
|
.find("input, textarea, select")
|
||||||
.not(":button")
|
.not(":button")
|
||||||
.each(function() {
|
.each(function() {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
@ -154,17 +157,20 @@ jQuery(function($) {
|
|||||||
* and appends it back after resetting it
|
* and appends it back after resetting it
|
||||||
*
|
*
|
||||||
* @param {string} [hash] - UUID or random hash
|
* @param {string} [hash] - UUID or random hash
|
||||||
|
* @param {jQuery} [$container] - A jQuery element as the container
|
||||||
*
|
*
|
||||||
* return {Object} - jQuery object
|
* return {Object} - jQuery object
|
||||||
*/
|
*/
|
||||||
function getNewTrackField(hash) {
|
function getNewTrackField(hash, $container) {
|
||||||
var newHash = hash || uuid();
|
var newHash = hash || uuid();
|
||||||
var $clone = el.$trackContainer
|
var $parent = $container || el.$trackContainer;
|
||||||
|
|
||||||
|
var $clone = $parent
|
||||||
.find(el.trackFieldClassName)
|
.find(el.trackFieldClassName)
|
||||||
.first()
|
.first()
|
||||||
.clone()
|
.clone()
|
||||||
.hide()
|
.hide()
|
||||||
.fadeIn();
|
.show();
|
||||||
resetField($clone, newHash);
|
resetField($clone, newHash);
|
||||||
|
|
||||||
return $clone;
|
return $clone;
|
||||||
@ -312,12 +318,22 @@ jQuery(function($) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
el.$expandAllButton.on("click", function(e) {
|
el.$expandAllButton.on("click", function(e) {
|
||||||
expandField(el.$trackContainer.find(el.trackFieldClassName));
|
var $this = $(this);
|
||||||
|
var $container = $this
|
||||||
|
.closest(".ai-container")
|
||||||
|
.find(".ai-fields-container");
|
||||||
|
|
||||||
|
expandField($container.find(el.trackFieldClassName));
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
el.$collapseAllButton.on("click", function(e) {
|
el.$collapseAllButton.on("click", function(e) {
|
||||||
collapseField(el.$trackContainer.find(el.trackFieldClassName));
|
var $this = $(this);
|
||||||
|
var $container = $this
|
||||||
|
.closest(".ai-container")
|
||||||
|
.find(".ai-fields-container");
|
||||||
|
|
||||||
|
collapseField($container.find(el.trackFieldClassName));
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -335,14 +351,23 @@ jQuery(function($) {
|
|||||||
$fieldTitle.text($this.val());
|
$fieldTitle.text($this.val());
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Add Track Top*/
|
/* Add Field Top */
|
||||||
el.$addTrackButtonTop.on("click", function() {
|
el.$addTrackButtonTop.on("click", function() {
|
||||||
el.$trackContainer.prepend(getNewTrackField());
|
var $this = $(this);
|
||||||
|
var $container = $this
|
||||||
|
.closest(".ai-container")
|
||||||
|
.find(".ai-fields-container");
|
||||||
|
$container.prepend(getNewTrackField(undefined, $container));
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Add Track Bottom*/
|
/* Add Field Bottom */
|
||||||
el.$addTrackButtonBottom.on("click", function () {
|
el.$addTrackButtonBottom.on("click", function() {
|
||||||
el.$trackContainer.append(getNewTrackField());
|
var $this = $(this);
|
||||||
|
var $container = $this
|
||||||
|
.closest(".ai-container")
|
||||||
|
.find(".ai-fields-container");
|
||||||
|
|
||||||
|
$container.append(getNewTrackField(undefined, $container));
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Remove Track */
|
/* Remove Track */
|
||||||
@ -353,7 +378,11 @@ jQuery(function($) {
|
|||||||
|
|
||||||
/* Remove All Tracks */
|
/* Remove All Tracks */
|
||||||
el.$removeAllTracksButton.on("click", function() {
|
el.$removeAllTracksButton.on("click", function() {
|
||||||
var $trackFields = el.$trackContainer.find(el.trackFieldClassName);
|
var $this = $(this);
|
||||||
|
var $container = $this
|
||||||
|
.closest(".ai-container")
|
||||||
|
.find(".ai-fields-container");
|
||||||
|
var $trackFields = $container.find(el.trackFieldClassName);
|
||||||
|
|
||||||
if (window.confirm(ai_scripts.messages.confirm_clear_tracks)) {
|
if (window.confirm(ai_scripts.messages.confirm_clear_tracks)) {
|
||||||
if ($trackFields.length > 1) {
|
if ($trackFields.length > 1) {
|
||||||
@ -402,7 +431,9 @@ jQuery(function($) {
|
|||||||
onMediaSelect: function(media) {
|
onMediaSelect: function(media) {
|
||||||
setTrackFieldCover($this.parents(el.trackFieldClassName), {
|
setTrackFieldCover($this.parents(el.trackFieldClassName), {
|
||||||
id: media.id,
|
id: media.id,
|
||||||
url: media.sizes.thumbnail.url,
|
url: media.sizes.thumbnail
|
||||||
|
? media.sizes.thumbnail.url
|
||||||
|
: media.sizes.full.url,
|
||||||
alt: media.alt
|
alt: media.alt
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Description: AudioIgniter lets you create music playlists and embed them in your WordPress posts, pages or custom post types and serve your audio content in style!
|
* Description: AudioIgniter lets you create music playlists and embed them in your WordPress posts, pages or custom post types and serve your audio content in style!
|
||||||
* Author: The CSSIgniter Team
|
* Author: The CSSIgniter Team
|
||||||
* Author URI: https://www.cssigniter.com
|
* Author URI: https://www.cssigniter.com
|
||||||
* Version: 1.7.3
|
* Version: 1.9.0
|
||||||
* Text Domain: audioigniter
|
* Text Domain: audioigniter
|
||||||
* Domain Path: languages
|
* Domain Path: languages
|
||||||
*
|
*
|
||||||
@ -131,7 +131,7 @@ class AudioIgniter {
|
|||||||
|
|
||||||
load_plugin_textdomain( 'audioigniter', false, dirname( self::plugin_basename() ) . '/languages' );
|
load_plugin_textdomain( 'audioigniter', false, dirname( self::plugin_basename() ) . '/languages' );
|
||||||
|
|
||||||
include_once( 'class-audioigniter-sanitizer.php' );
|
require_once 'class-audioigniter-sanitizer.php';
|
||||||
$this->sanitizer = new AudioIgniter_Sanitizer();
|
$this->sanitizer = new AudioIgniter_Sanitizer();
|
||||||
|
|
||||||
// Initialization needed in every request.
|
// Initialization needed in every request.
|
||||||
@ -177,6 +177,9 @@ class AudioIgniter {
|
|||||||
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
|
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
|
||||||
add_action( 'save_post', array( $this, 'save_post' ) );
|
add_action( 'save_post', array( $this, 'save_post' ) );
|
||||||
|
|
||||||
|
add_filter( "manage_{$this->post_type}_posts_columns", array( $this, 'filter_posts_columns' ) );
|
||||||
|
add_action( "manage_{$this->post_type}_posts_custom_column", array( $this, 'add_custom_columns' ), 10, 2 );
|
||||||
|
|
||||||
do_action( 'audioigniter_admin_init' );
|
do_action( 'audioigniter_admin_init' );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +311,7 @@ class AudioIgniter {
|
|||||||
public function add_meta_boxes() {
|
public function add_meta_boxes() {
|
||||||
add_meta_box( 'ai-meta-box-tracks', esc_html__( 'Tracks', 'audioigniter' ), array( $this, 'metabox_tracks' ), $this->post_type, 'normal', 'high' );
|
add_meta_box( 'ai-meta-box-tracks', esc_html__( 'Tracks', 'audioigniter' ), array( $this, 'metabox_tracks' ), $this->post_type, 'normal', 'high' );
|
||||||
add_meta_box( 'ai-meta-box-settings', esc_html__( 'Settings', 'audioigniter' ), array( $this, 'metabox_settings' ), $this->post_type, 'normal', 'high' );
|
add_meta_box( 'ai-meta-box-settings', esc_html__( 'Settings', 'audioigniter' ), array( $this, 'metabox_settings' ), $this->post_type, 'normal', 'high' );
|
||||||
add_meta_box( 'ai-meta-box-shortcode', esc_html__( 'Shortcode', 'audioigniter' ), array( $this, 'metabox_shortcode' ), $this->post_type, 'normal', 'high' );
|
add_meta_box( 'ai-meta-box-shortcode', esc_html__( 'Shortcode', 'audioigniter' ), array( $this, 'metabox_shortcode' ), $this->post_type, 'side', 'default' );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -328,7 +331,7 @@ class AudioIgniter {
|
|||||||
<?php $this->metabox_tracks_header(); ?>
|
<?php $this->metabox_tracks_header(); ?>
|
||||||
|
|
||||||
<div class="ai-container">
|
<div class="ai-container">
|
||||||
<?php $this->metabox_tracks_field_controls( 'top' ); ?>
|
<?php $this->metabox_tracks_field_controls( 'top', $object->ID ); ?>
|
||||||
|
|
||||||
<?php $container_classes = apply_filters( 'audioigniter_metabox_tracks_container_classes', array( 'ai-fields-container' ) ); ?>
|
<?php $container_classes = apply_filters( 'audioigniter_metabox_tracks_container_classes', array( 'ai-fields-container' ) ); ?>
|
||||||
|
|
||||||
@ -344,12 +347,11 @@ class AudioIgniter {
|
|||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php $this->metabox_tracks_field_controls( 'bottom' ); ?>
|
<?php $this->metabox_tracks_field_controls( 'bottom', $object->ID ); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php $this->metabox_tracks_footer(); ?>
|
<?php $this->metabox_tracks_footer(); ?>
|
||||||
|
|
||||||
<input type="hidden" name="ai_nonce" id="ai_nonce" value="<?php echo esc_attr( wp_create_nonce( self::plugin_basename() ) ); ?>"/>
|
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,12 +449,13 @@ class AudioIgniter {
|
|||||||
protected function metabox_tracks_repeatable_track_field( $track = array() ) {
|
protected function metabox_tracks_repeatable_track_field( $track = array() ) {
|
||||||
$track = wp_parse_args( $track, self::get_default_track_values() );
|
$track = wp_parse_args( $track, self::get_default_track_values() );
|
||||||
|
|
||||||
$cover_id = $track['cover_id'];
|
$cover_id = $track['cover_id'];
|
||||||
$title = $track['title'];
|
$title = $track['title'];
|
||||||
$artist = $track['artist'];
|
$artist = $track['artist'];
|
||||||
$track_url = $track['track_url'];
|
$track_url = $track['track_url'];
|
||||||
$buy_link = $track['buy_link'];
|
$buy_link = $track['buy_link'];
|
||||||
$download_url = $track['download_url'];
|
$download_url = $track['download_url'];
|
||||||
|
$download_uses_track_url = (int) $track['download_uses_track_url'];
|
||||||
|
|
||||||
$cover_url = wp_get_attachment_image_src( intval( $cover_id ), 'thumbnail' );
|
$cover_url = wp_get_attachment_image_src( intval( $cover_id ), 'thumbnail' );
|
||||||
if ( ! empty( $cover_url[0] ) ) {
|
if ( ! empty( $cover_url[0] ) ) {
|
||||||
@ -602,7 +605,12 @@ class AudioIgniter {
|
|||||||
name="ai_playlist_tracks[<?php echo esc_attr( $uid ); ?>][download_url]"
|
name="ai_playlist_tracks[<?php echo esc_attr( $uid ); ?>][download_url]"
|
||||||
placeholder="<?php esc_attr_e( 'Download URL', 'audioigniter' ); ?>"
|
placeholder="<?php esc_attr_e( 'Download URL', 'audioigniter' ); ?>"
|
||||||
value="<?php echo esc_url( $download_url ); ?>"
|
value="<?php echo esc_url( $download_url ); ?>"
|
||||||
|
<?php if ( $download_uses_track_url ) : ?>
|
||||||
|
disabled
|
||||||
|
<?php endif; ?>
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<?php do_action( 'audioigniter_metabox_tracks_repeatable_track_field_after_download_url_button', $track, $uid ); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php do_action( 'audioigniter_metabox_tracks_repeatable_track_fields_column_2', $track, $uid ); ?>
|
<?php do_action( 'audioigniter_metabox_tracks_repeatable_track_fields_column_2', $track, $uid ); ?>
|
||||||
@ -618,7 +626,7 @@ class AudioIgniter {
|
|||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function metabox_tracks_field_controls( $location ) {
|
protected function metabox_tracks_field_controls( $location, $post_id ) {
|
||||||
?>
|
?>
|
||||||
<div class="ai-field-controls-wrap">
|
<div class="ai-field-controls-wrap">
|
||||||
<div class="ai-field-controls">
|
<div class="ai-field-controls">
|
||||||
@ -627,7 +635,7 @@ class AudioIgniter {
|
|||||||
<?php esc_html_e( 'Add Track', 'audioigniter' ); ?>
|
<?php esc_html_e( 'Add Track', 'audioigniter' ); ?>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<?php do_action( 'audioigniter_metabox_tracks_field_controls' ); ?>
|
<?php do_action( 'audioigniter_metabox_tracks_field_controls', $location, $post_id ); ?>
|
||||||
|
|
||||||
<button type="button" class="button ai-remove-all-fields">
|
<button type="button" class="button ai-remove-all-fields">
|
||||||
<span class="dashicons dashicons-dismiss"></span>
|
<span class="dashicons dashicons-dismiss"></span>
|
||||||
@ -1078,12 +1086,13 @@ class AudioIgniter {
|
|||||||
|
|
||||||
public static function get_default_track_values() {
|
public static function get_default_track_values() {
|
||||||
return apply_filters( 'audioigniter_default_track_values', array(
|
return apply_filters( 'audioigniter_default_track_values', array(
|
||||||
'cover_id' => '',
|
'cover_id' => '',
|
||||||
'title' => '',
|
'title' => '',
|
||||||
'artist' => '',
|
'artist' => '',
|
||||||
'track_url' => '',
|
'track_url' => '',
|
||||||
'buy_link' => '',
|
'buy_link' => '',
|
||||||
'download_url' => '',
|
'download_url' => '',
|
||||||
|
'download_uses_track_url' => 0,
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1263,7 +1272,7 @@ class AudioIgniter {
|
|||||||
$track_response['subtitle'] = $track['artist'];
|
$track_response['subtitle'] = $track['artist'];
|
||||||
$track_response['audio'] = $track['track_url'];
|
$track_response['audio'] = $track['track_url'];
|
||||||
$track_response['buyUrl'] = $track['buy_link'];
|
$track_response['buyUrl'] = $track['buy_link'];
|
||||||
$track_response['downloadUrl'] = $track['download_url'];
|
$track_response['downloadUrl'] = $track['download_uses_track_url'] ? $track['track_url'] : $track['download_url'];
|
||||||
$track_response['downloadFilename'] = $this->get_filename_from_url( $track['download_url'] );
|
$track_response['downloadFilename'] = $this->get_filename_from_url( $track['download_url'] );
|
||||||
|
|
||||||
if ( ! $track_response['downloadFilename'] ) {
|
if ( ! $track_response['downloadFilename'] ) {
|
||||||
@ -1287,6 +1296,22 @@ class AudioIgniter {
|
|||||||
wp_send_json( $response );
|
wp_send_json( $response );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function filter_posts_columns( $columns ) {
|
||||||
|
$date = $columns['date'];
|
||||||
|
unset( $columns['date'] );
|
||||||
|
|
||||||
|
$columns['shortcode'] = __( 'Shortcode', 'audioigniter' );
|
||||||
|
$columns['date'] = $date;
|
||||||
|
|
||||||
|
return $columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add_custom_columns( $column, $post_id ) {
|
||||||
|
if ( 'shortcode' === $column ) {
|
||||||
|
?><input type="text" class="code" value="<?php echo esc_attr( sprintf( '[ai_playlist id="%s"]', $post_id ) ); ?>"><?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function get_filename_from_url( $url ) {
|
function get_filename_from_url( $url ) {
|
||||||
$struct = wp_parse_url( $url );
|
$struct = wp_parse_url( $url );
|
||||||
|
|
||||||
|
@ -80,12 +80,13 @@ class AudioIgniter_Sanitizer {
|
|||||||
|
|
||||||
$sanitized_track = array();
|
$sanitized_track = array();
|
||||||
|
|
||||||
$sanitized_track['cover_id'] = intval( $track['cover_id'] );
|
$sanitized_track['cover_id'] = intval( $track['cover_id'] );
|
||||||
$sanitized_track['title'] = sanitize_text_field( $track['title'] );
|
$sanitized_track['title'] = sanitize_text_field( $track['title'] );
|
||||||
$sanitized_track['artist'] = sanitize_text_field( $track['artist'] );
|
$sanitized_track['artist'] = sanitize_text_field( $track['artist'] );
|
||||||
$sanitized_track['track_url'] = esc_url_raw( $track['track_url'] );
|
$sanitized_track['track_url'] = esc_url_raw( $track['track_url'] );
|
||||||
$sanitized_track['buy_link'] = esc_url_raw( $track['buy_link'] );
|
$sanitized_track['buy_link'] = esc_url_raw( $track['buy_link'] );
|
||||||
$sanitized_track['download_url'] = esc_url_raw( $track['download_url'] );
|
$sanitized_track['download_url'] = esc_url_raw( $track['download_url'] );
|
||||||
|
$sanitized_track['download_uses_track_url'] = ! empty( $track['download_uses_track_url'] ) ? 1 : 0;
|
||||||
|
|
||||||
$sanitized_track = array_map( 'trim', $sanitized_track );
|
$sanitized_track = array_map( 'trim', $sanitized_track );
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: AudioIgniter\n"
|
"Project-Id-Version: AudioIgniter\n"
|
||||||
"POT-Creation-Date: 2021-12-14 12:04+0200\n"
|
"POT-Creation-Date: 2022-06-28 14:39+0300\n"
|
||||||
"PO-Revision-Date: 2016-08-29 19:22+0300\n"
|
"PO-Revision-Date: 2016-08-29 19:22+0300\n"
|
||||||
"Last-Translator: Anastis Sourgoutsidis <anastis@cssigniter.com>\n"
|
"Last-Translator: Anastis Sourgoutsidis <anastis@cssigniter.com>\n"
|
||||||
"Language-Team: Anastis Sourgoutsidis <anastis@cssigniter.com>\n"
|
"Language-Team: Anastis Sourgoutsidis <anastis@cssigniter.com>\n"
|
||||||
@ -10,7 +10,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
||||||
"X-Generator: Poedit 3.0.1\n"
|
"X-Generator: Poedit 3.1\n"
|
||||||
"X-Poedit-Basepath: ..\n"
|
"X-Poedit-Basepath: ..\n"
|
||||||
"X-Poedit-WPHeader: audioigniter.php\n"
|
"X-Poedit-WPHeader: audioigniter.php\n"
|
||||||
"X-Poedit-SourceCharset: UTF-8\n"
|
"X-Poedit-SourceCharset: UTF-8\n"
|
||||||
@ -22,348 +22,348 @@ msgstr ""
|
|||||||
"X-Poedit-SearchPathExcluded-0: *.js\n"
|
"X-Poedit-SearchPathExcluded-0: *.js\n"
|
||||||
|
|
||||||
#. translators: %s is the track's title.
|
#. translators: %s is the track's title.
|
||||||
#: audioigniter.php:213
|
#: audioigniter.php:216
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "Play %s"
|
msgid "Play %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %s is the track's title.
|
#. translators: %s is the track's title.
|
||||||
#: audioigniter.php:215
|
#: audioigniter.php:218
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "Pause %s"
|
msgid "Pause %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:216
|
#: audioigniter.php:219
|
||||||
msgid "Previous track"
|
msgid "Previous track"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:217
|
#: audioigniter.php:220
|
||||||
msgid "Next track"
|
msgid "Next track"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:218
|
#: audioigniter.php:221
|
||||||
msgid "Toggle track listing repeat"
|
msgid "Toggle track listing repeat"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:219
|
#: audioigniter.php:222
|
||||||
msgid "Toggle track repeat"
|
msgid "Toggle track repeat"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:220
|
#: audioigniter.php:223
|
||||||
msgid "Toggle track listing visibility"
|
msgid "Toggle track listing visibility"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:221
|
#: audioigniter.php:224
|
||||||
msgid "Buy this track"
|
msgid "Buy this track"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:222
|
#: audioigniter.php:225
|
||||||
msgid "Download this track"
|
msgid "Download this track"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:223
|
#: audioigniter.php:226
|
||||||
msgid "Volume Up"
|
msgid "Volume Up"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:224
|
#: audioigniter.php:227
|
||||||
msgid "Volume Down"
|
msgid "Volume Down"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:225
|
#: audioigniter.php:228
|
||||||
msgid "Open track lyrics"
|
msgid "Open track lyrics"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:226
|
#: audioigniter.php:229
|
||||||
msgid "Set playback rate"
|
msgid "Set playback rate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:227
|
#: audioigniter.php:230
|
||||||
msgid "Skip forward"
|
msgid "Skip forward"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:228
|
#: audioigniter.php:231
|
||||||
msgid "Skip backward"
|
msgid "Skip backward"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:229
|
#: audioigniter.php:232
|
||||||
msgid "Shuffle"
|
msgid "Shuffle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:234
|
#: audioigniter.php:237
|
||||||
msgid ""
|
msgid ""
|
||||||
"Do you really want to remove all tracks? (This will not delete your audio "
|
"Do you really want to remove all tracks? (This will not delete your audio "
|
||||||
"files)."
|
"files)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:235
|
#: audioigniter.php:238
|
||||||
msgid "Select or upload audio media"
|
msgid "Select or upload audio media"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:236
|
#: audioigniter.php:239
|
||||||
msgid "Select a cover image"
|
msgid "Select a cover image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:273
|
#: audioigniter.php:276
|
||||||
msgctxt "post type general name"
|
msgctxt "post type general name"
|
||||||
msgid "Playlists"
|
msgid "Playlists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:274 audioigniter.php:289
|
#: audioigniter.php:277 audioigniter.php:292
|
||||||
msgctxt "post type singular name"
|
msgctxt "post type singular name"
|
||||||
msgid "Playlist"
|
msgid "Playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:275
|
#: audioigniter.php:278
|
||||||
msgctxt "admin menu"
|
msgctxt "admin menu"
|
||||||
msgid "Playlists"
|
msgid "Playlists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:276
|
#: audioigniter.php:279
|
||||||
msgctxt "add new on admin bar"
|
msgctxt "add new on admin bar"
|
||||||
msgid "Playlist"
|
msgid "Playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:277 audioigniter.php:278
|
#: audioigniter.php:280 audioigniter.php:281
|
||||||
msgid "Add New Playlist"
|
msgid "Add New Playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:279
|
#: audioigniter.php:282
|
||||||
msgid "Edit Playlist"
|
msgid "Edit Playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:280
|
#: audioigniter.php:283
|
||||||
msgid "New Playlist"
|
msgid "New Playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:281
|
#: audioigniter.php:284
|
||||||
msgid "View Playlist"
|
msgid "View Playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:282
|
#: audioigniter.php:285
|
||||||
msgid "Search Playlists"
|
msgid "Search Playlists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:283
|
#: audioigniter.php:286
|
||||||
msgid "No playlists found"
|
msgid "No playlists found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:284
|
#: audioigniter.php:287
|
||||||
msgid "No playlists found in the trash"
|
msgid "No playlists found in the trash"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:309 audioigniter.php:830
|
#: audioigniter.php:312 audioigniter.php:838
|
||||||
msgid "Tracks"
|
msgid "Tracks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:310
|
#: audioigniter.php:313
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:311
|
#: audioigniter.php:314 audioigniter.php:1303
|
||||||
msgid "Shortcode"
|
msgid "Shortcode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:370
|
#: audioigniter.php:372
|
||||||
msgid "AudioIgniter Logo"
|
msgid "AudioIgniter Logo"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:379
|
#: audioigniter.php:381
|
||||||
msgid "Upgrade to Pro"
|
msgid "Upgrade to Pro"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:403
|
#: audioigniter.php:405
|
||||||
msgid "Support"
|
msgid "Support"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:407
|
#: audioigniter.php:409
|
||||||
msgid "Documentation"
|
msgid "Documentation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:411
|
#: audioigniter.php:413
|
||||||
msgid "Rate this plugin"
|
msgid "Rate this plugin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %s is a URL.
|
#. translators: %s is a URL.
|
||||||
#: audioigniter.php:434
|
#: audioigniter.php:436
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Thank you for creating with <a href=\"%s\" target=\"_blank\">AudioIgniter</a>"
|
"Thank you for creating with <a href=\"%s\" target=\"_blank\">AudioIgniter</a>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:479
|
#: audioigniter.php:482
|
||||||
msgid "Toggle track visibility"
|
msgid "Toggle track visibility"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:490
|
#: audioigniter.php:493
|
||||||
msgid "Remove Cover Image"
|
msgid "Remove Cover Image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:503
|
#: audioigniter.php:506
|
||||||
msgid "Upload Cover"
|
msgid "Upload Cover"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:521 audioigniter.php:528
|
#: audioigniter.php:524 audioigniter.php:531
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:536 audioigniter.php:543
|
#: audioigniter.php:539 audioigniter.php:546
|
||||||
msgid "Artist"
|
msgid "Artist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:552 audioigniter.php:559
|
#: audioigniter.php:555 audioigniter.php:562
|
||||||
msgid "Buy link"
|
msgid "Buy link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:572 audioigniter.php:581
|
#: audioigniter.php:575 audioigniter.php:584
|
||||||
msgid "Audio file or radio stream"
|
msgid "Audio file or radio stream"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:585
|
#: audioigniter.php:588
|
||||||
msgid "Upload"
|
msgid "Upload"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:596 audioigniter.php:603
|
#: audioigniter.php:599 audioigniter.php:606
|
||||||
msgid "Download URL"
|
msgid "Download URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:612
|
#: audioigniter.php:620
|
||||||
msgid "Remove Track"
|
msgid "Remove Track"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:627
|
#: audioigniter.php:635
|
||||||
msgid "Add Track"
|
msgid "Add Track"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:634
|
#: audioigniter.php:642
|
||||||
msgid "Clear Playlist"
|
msgid "Clear Playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:640
|
#: audioigniter.php:648
|
||||||
msgid "Expand All"
|
msgid "Expand All"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:643
|
#: audioigniter.php:651
|
||||||
msgid "Collapse All"
|
msgid "Collapse All"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:682
|
#: audioigniter.php:690
|
||||||
msgid "Player & Track listing"
|
msgid "Player & Track listing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:687
|
#: audioigniter.php:695
|
||||||
msgid "Player Type"
|
msgid "Player Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:718
|
#: audioigniter.php:726
|
||||||
msgid "Show track listing by default"
|
msgid "Show track listing by default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:732
|
#: audioigniter.php:740
|
||||||
msgid "Show track listing visibility toggle button"
|
msgid "Show track listing visibility toggle button"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:746
|
#: audioigniter.php:754
|
||||||
msgid "Reverse track order"
|
msgid "Reverse track order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:752
|
#: audioigniter.php:760
|
||||||
msgid "Starting volume"
|
msgid "Starting volume"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:763
|
#: audioigniter.php:771
|
||||||
msgid "0-100"
|
msgid "0-100"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:768
|
#: audioigniter.php:776
|
||||||
msgid "Enter a value between 0 and 100 in increments of 10"
|
msgid "Enter a value between 0 and 100 in increments of 10"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:782
|
#: audioigniter.php:790
|
||||||
msgid "Limit track listing height"
|
msgid "Limit track listing height"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:788 audioigniter.php:798
|
#: audioigniter.php:796 audioigniter.php:806
|
||||||
msgid "Track listing height"
|
msgid "Track listing height"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:803
|
#: audioigniter.php:811
|
||||||
msgid "Set a number of pixels"
|
msgid "Set a number of pixels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:809
|
#: audioigniter.php:817
|
||||||
msgid "Maximum player width"
|
msgid "Maximum player width"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:817
|
#: audioigniter.php:825
|
||||||
msgid "Automatic width"
|
msgid "Automatic width"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:822
|
#: audioigniter.php:830
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Set a number of pixels, or leave empty to automatically cover 100% of the "
|
"Set a number of pixels, or leave empty to automatically cover 100% of the "
|
||||||
"available area (recommended)."
|
"available area (recommended)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:842
|
#: audioigniter.php:850
|
||||||
msgid "Show track numbers in tracklist"
|
msgid "Show track numbers in tracklist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:856
|
#: audioigniter.php:864
|
||||||
msgid "Show track covers in tracklist"
|
msgid "Show track covers in tracklist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:870
|
#: audioigniter.php:878
|
||||||
msgid "Show active track's cover"
|
msgid "Show active track's cover"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:884
|
#: audioigniter.php:892
|
||||||
msgid "Show artist names"
|
msgid "Show artist names"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:898
|
#: audioigniter.php:906
|
||||||
msgid "Show track extra buttons (buy link, download button etc)"
|
msgid "Show track extra buttons (buy link, download button etc)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:912
|
#: audioigniter.php:920
|
||||||
msgid "Open buy links in new window"
|
msgid "Open buy links in new window"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:920
|
#: audioigniter.php:928
|
||||||
msgid "Track & Track listing repeat"
|
msgid "Track & Track listing repeat"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:932
|
#: audioigniter.php:940
|
||||||
msgid "Repeat track listing enabled by default"
|
msgid "Repeat track listing enabled by default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:946
|
#: audioigniter.php:954
|
||||||
msgid "Show track listing repeat toggle button"
|
msgid "Show track listing repeat toggle button"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:963
|
#: audioigniter.php:971
|
||||||
msgid "Show \"Powered by AudioIgniter\" link"
|
msgid "Show \"Powered by AudioIgniter\" link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:967
|
#: audioigniter.php:975
|
||||||
msgid ""
|
msgid ""
|
||||||
"We've put a great deal of effort into building this plugin. If you feel like "
|
"We've put a great deal of effort into building this plugin. If you feel like "
|
||||||
"it, let others know about it by enabling this option."
|
"it, let others know about it by enabling this option."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:987
|
#: audioigniter.php:995
|
||||||
msgid "Grab the shortcode"
|
msgid "Grab the shortcode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:1021
|
#: audioigniter.php:1029
|
||||||
msgid "Full Player"
|
msgid "Full Player"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:1026
|
#: audioigniter.php:1034
|
||||||
msgid "Simple Player"
|
msgid "Simple Player"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: audioigniter.php:1248
|
#: audioigniter.php:1257
|
||||||
msgid "ID doesn't match a playlist"
|
msgid "ID doesn't match a playlist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1,7 +1,22 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
"es2015",
|
[
|
||||||
"react",
|
"@babel/preset-env",
|
||||||
"stage-2"
|
{
|
||||||
]
|
"targets": {
|
||||||
|
"browsers": [
|
||||||
|
"last 2 versions, >1%"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"modules": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@babel/preset-react"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-proposal-object-rest-spread",
|
||||||
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
|
"@babel/plugin-proposal-nullish-coalescing-operator"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"airbnb",
|
"airbnb",
|
||||||
"plugin:prettier/recommended",
|
"prettier"
|
||||||
"prettier/react"
|
|
||||||
],
|
],
|
||||||
|
"parser": "@babel/eslint-parser",
|
||||||
"plugins": [
|
"plugins": [
|
||||||
|
"babel",
|
||||||
"import"
|
"import"
|
||||||
],
|
],
|
||||||
"globals": {
|
"globals": {
|
||||||
"aiStrings": true
|
"aiStrings": true
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true
|
"browser": true
|
||||||
},
|
},
|
||||||
@ -17,22 +18,36 @@
|
|||||||
"arrow-body-style": 0,
|
"arrow-body-style": 0,
|
||||||
"no-confusing-arrow": 0,
|
"no-confusing-arrow": 0,
|
||||||
"global-require": 0,
|
"global-require": 0,
|
||||||
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}],
|
"import/no-extraneous-dependencies": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"devDependencies": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"import/prefer-default-export": 0,
|
"import/prefer-default-export": 0,
|
||||||
|
"import/no-cycle": 0,
|
||||||
"react/jsx-filename-extension": 0,
|
"react/jsx-filename-extension": 0,
|
||||||
"react/require-default-props": 0,
|
"react/require-default-props": 0,
|
||||||
"react/forbid-prop-types": 0,
|
"react/forbid-prop-types": 0,
|
||||||
"react/default-props-match-prop-types": 0,
|
"react/default-props-match-prop-types": 0,
|
||||||
"react/prefer-stateless-function": 0,
|
"react/prefer-stateless-function": 0,
|
||||||
"react/jsx-curly-spacing": [2, {
|
"react/jsx-curly-spacing": [
|
||||||
"when": "never",
|
2,
|
||||||
"children": true
|
{
|
||||||
}],
|
"when": "never",
|
||||||
|
"children": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"react/no-array-index-key": 0,
|
"react/no-array-index-key": 0,
|
||||||
"jsx-a11y/anchor-is-valid": 0,
|
"jsx-a11y/anchor-is-valid": 0,
|
||||||
"jsx-a11y/no-static-element-interactions": 0,
|
"jsx-a11y/no-static-element-interactions": 0,
|
||||||
"react/destructuring-assignment": 0,
|
"react/destructuring-assignment": 0,
|
||||||
|
"react/function-component-definition": 0,
|
||||||
|
"react/jsx-props-no-spreading": 0,
|
||||||
"react/button-has-type": 0,
|
"react/button-has-type": 0,
|
||||||
"jsx-a11y/label-has-for": 0
|
"react/jsx-fragments": 0,
|
||||||
|
"react/jsx-no-constructed-context-values": 0,
|
||||||
|
"jsx-a11y/label-has-for": 0,
|
||||||
|
"jsx-a11y/click-events-have-key-events": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
v8.12.0
|
16.14.2
|
||||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,66 @@
|
|||||||
|
/*!
|
||||||
|
Copyright (c) 2015 Jed Watson.
|
||||||
|
Based on code that is Copyright 2013-2015, Facebook, Inc.
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Copyright (c) 2018 Jed Watson.
|
||||||
|
Licensed under the MIT License (MIT), see
|
||||||
|
http://jedwatson.github.io/classnames
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Adapted from jQuery UI core
|
||||||
|
*
|
||||||
|
* http://jqueryui.com
|
||||||
|
*
|
||||||
|
* Copyright 2014 jQuery Foundation and other contributors
|
||||||
|
* Released under the MIT license.
|
||||||
|
* http://jquery.org/license
|
||||||
|
*
|
||||||
|
* http://api.jqueryui.com/category/ui-core/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react-dom.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* scheduler.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @license
|
||||||
|
*
|
||||||
|
* SoundManager 2: JavaScript Sound for the Web
|
||||||
|
* ----------------------------------------------
|
||||||
|
* http://schillmania.com/projects/soundmanager2/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Scott Schiller. All rights reserved.
|
||||||
|
* Code provided under the BSD License:
|
||||||
|
* http://schillmania.com/projects/soundmanager2/license.txt
|
||||||
|
*
|
||||||
|
* V2.97a.20170601
|
||||||
|
*/
|
@ -1,100 +1,54 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>AudioIgniter</title><style>body {
|
||||||
<html>
|
padding-bottom: 120px;
|
||||||
<head>
|
}</style><script defer="defer" src="style.js"></script><script defer="defer" src="app.js"></script><link href="style.css" rel="stylesheet"></head><body><div id="audioigniter-2799" class="audioigniter-root" data-player-type="full" data-tracks-url="/dev-tracks.json" data-display-active-cover="true" data-display-tracklist-covers="true" data-display-credits="true" data-display-tracklist="true" data-allow-tracklist-toggle="true" data-allow-tracklist-loop="true" data-allow-track-loop="true" data-allow-playback-rate="true" data-display-track-no="true" data-display-artist-names="true" data-display-buy-buttons="true" data-buy-buttons-target="true" data-volume="50" data-cycle-tracks="true" data-limit-tracklist-height="true" data-tracklist-height="185" data-reverse-track-order="false" data-skip-amount="15" data-max-width="600px" data-initial-track="1" data-stop-on-finish="false" data-tracks-delay="5" data-timer-countdown="false" data-shuffle="true" data-shuffle-default="false" data-soundcloud-client-id="" data-remember-last="true" data-player-buttons='[
|
||||||
<meta charset="UTF-8">
|
{
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
"title": "CSSIgniter",
|
||||||
<title>AudioIgniter</title>
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 35.9789 8.77641 45.908 20.25 47.7084V30.9375H14.1562V24H20.25V18.7125C20.25 12.6975 23.8331 9.375 29.3152 9.375C31.9402 9.375 34.6875 9.84375 34.6875 9.84375V15.75H31.6613C28.68 15.75 27.75 17.6002 27.75 19.5V24H34.4062L33.3422 30.9375H27.75V47.7084C39.2236 45.908 48 35.9789 48 24Z\" fill=\"black\"/>\n</svg>"
|
||||||
<style>
|
},
|
||||||
body {
|
{
|
||||||
padding-bottom: 120px;
|
"title": "",
|
||||||
}
|
"url": "https://cssigniter.com",
|
||||||
</style>
|
"icon": "<svg width=\"48\" height=\"40\" viewBox=\"0 0 48 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15.1003 39.5001C33.2091 39.5001 43.1166 24.4935 43.1166 11.4838C43.1166 11.0619 43.1072 10.6307 43.0884 10.2088C45.0157 8.81501 46.679 7.0886 48 5.11068C46.205 5.90929 44.2993 6.43085 42.3478 6.65756C44.4026 5.4259 45.9411 3.49103 46.6781 1.21162C44.7451 2.3572 42.6312 3.16531 40.4269 3.60131C38.9417 2.02321 36.978 0.97832 34.8394 0.62819C32.7008 0.278059 30.5064 0.642189 28.5955 1.66428C26.6846 2.68637 25.1636 4.3095 24.2677 6.28271C23.3718 8.25592 23.1509 10.4693 23.6391 12.5807C19.725 12.3843 15.8959 11.3675 12.4 9.59628C8.90405 7.82507 5.81939 5.33896 3.34594 2.29912C2.0888 4.46657 1.70411 7.03138 2.27006 9.47227C2.83601 11.9132 4.31013 14.047 6.39281 15.4401C4.82926 15.3904 3.29995 14.9694 1.93125 14.2119V14.3338C1.92985 16.6084 2.7162 18.8133 4.15662 20.5736C5.59704 22.334 7.60265 23.5412 9.8325 23.9901C8.38411 24.3863 6.86396 24.4441 5.38969 24.1588C6.01891 26.115 7.24315 27.8259 8.89154 29.0528C10.5399 30.2796 12.5302 30.9613 14.5847 31.0026C11.0968 33.7423 6.78835 35.2283 2.35313 35.2213C1.56657 35.2201 0.780798 35.1719 0 35.0769C4.50571 37.9676 9.74706 39.5029 15.1003 39.5001Z\" fill=\"black\"/>\n</svg>"
|
||||||
<link href="style.css" rel="stylesheet"></head>
|
},
|
||||||
<body>
|
{
|
||||||
<div
|
"title": "Another title",
|
||||||
class="audioigniter-root"
|
"url": "https://cssigniter.com",
|
||||||
data-player-type="full"
|
"icon": ""
|
||||||
data-tracks-url="/dev-tracks.json"
|
}
|
||||||
data-display-active-cover="true"
|
]
|
||||||
data-display-tracklist-covers="true"
|
'></div><div id="audioigniter-2999" class="audioigniter-root" data-player-type="simple" data-tracks-url="/dev-tracks.json" data-display-credits="true" data-display-track-no="true" data-allow-playback-rate="true" data-display-artist-names="true" data-display-buy-buttons="true" data-buy-buttons-target="true" data-allow-track-loop="true" data-volume="50" data-reverse-track-order="false" data-max-width="600px" data-initial-track="3" data-stop-on-finish="false" data-tracks-delay="0" data-timer-countdown="false" data-shuffle="true" data-soundcloud-client-id="" data-player-buttons='[
|
||||||
data-display-credits="true"
|
{
|
||||||
data-display-tracklist="true"
|
"title": "CSSIgniter",
|
||||||
data-allow-tracklist-toggle="true"
|
"url": "https://cssigniter.com",
|
||||||
data-allow-tracklist-loop="true"
|
"icon": "<svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 35.9789 8.77641 45.908 20.25 47.7084V30.9375H14.1562V24H20.25V18.7125C20.25 12.6975 23.8331 9.375 29.3152 9.375C31.9402 9.375 34.6875 9.84375 34.6875 9.84375V15.75H31.6613C28.68 15.75 27.75 17.6002 27.75 19.5V24H34.4062L33.3422 30.9375H27.75V47.7084C39.2236 45.908 48 35.9789 48 24Z\" fill=\"black\"/>\n</svg>"
|
||||||
data-allow-track-loop="true"
|
},
|
||||||
data-allow-playback-rate="true"
|
{
|
||||||
data-display-track-no="true"
|
"title": "",
|
||||||
data-display-artist-names="true"
|
"url": "https://cssigniter.com",
|
||||||
data-display-buy-buttons="true"
|
"icon": "<svg width=\"48\" height=\"40\" viewBox=\"0 0 48 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15.1003 39.5001C33.2091 39.5001 43.1166 24.4935 43.1166 11.4838C43.1166 11.0619 43.1072 10.6307 43.0884 10.2088C45.0157 8.81501 46.679 7.0886 48 5.11068C46.205 5.90929 44.2993 6.43085 42.3478 6.65756C44.4026 5.4259 45.9411 3.49103 46.6781 1.21162C44.7451 2.3572 42.6312 3.16531 40.4269 3.60131C38.9417 2.02321 36.978 0.97832 34.8394 0.62819C32.7008 0.278059 30.5064 0.642189 28.5955 1.66428C26.6846 2.68637 25.1636 4.3095 24.2677 6.28271C23.3718 8.25592 23.1509 10.4693 23.6391 12.5807C19.725 12.3843 15.8959 11.3675 12.4 9.59628C8.90405 7.82507 5.81939 5.33896 3.34594 2.29912C2.0888 4.46657 1.70411 7.03138 2.27006 9.47227C2.83601 11.9132 4.31013 14.047 6.39281 15.4401C4.82926 15.3904 3.29995 14.9694 1.93125 14.2119V14.3338C1.92985 16.6084 2.7162 18.8133 4.15662 20.5736C5.59704 22.334 7.60265 23.5412 9.8325 23.9901C8.38411 24.3863 6.86396 24.4441 5.38969 24.1588C6.01891 26.115 7.24315 27.8259 8.89154 29.0528C10.5399 30.2796 12.5302 30.9613 14.5847 31.0026C11.0968 33.7423 6.78835 35.2283 2.35313 35.2213C1.56657 35.2201 0.780798 35.1719 0 35.0769C4.50571 37.9676 9.74706 39.5029 15.1003 39.5001Z\" fill=\"black\"/>\n</svg>"
|
||||||
data-buy-buttons-target="true"
|
},
|
||||||
data-volume="50"
|
{
|
||||||
data-cycle-tracks="true"
|
"title": "Another title",
|
||||||
data-limit-tracklist-height="true"
|
"url": "https://cssigniter.com",
|
||||||
data-tracklist-height="185"
|
"icon": ""
|
||||||
data-reverse-track-order="false"
|
}
|
||||||
data-skip-amount="15"
|
]
|
||||||
data-max-width="600px"
|
'></div><div id="audioigniter-2519" class="audioigniter-root" data-track='{"title":"Sunrise","subtitle":"Thoribass","audio":"https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3","buyUrl":"https:\/\/google.com","downloadUrl":"https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3","cover":"https:\/\/www.cssigniter.com\/demos\/audioigniter\/wp-content\/uploads\/sites\/48\/2016\/08\/CyberSDF-Flame-and-Go.jpg","lyrics":"Some lyrics"}' data-display-active-cover="false" data-display-credits="true" data-allow-playback-rate="false" data-display-buy-buttons="true" data-volume="100" data-skip-amount="0" data-stop-on-finish="true" data-timer-countdown="false" data-player-type="full" data-tracks-url="" data-display-tracklist="false" data-allow-tracklist-toggle="true" data-allow-tracklist-loop="true" data-allow-track-loop="true" data-display-track-no="false" data-display-artist-names="true" data-buy-buttons-target="true" data-cycle-tracks="false" data-limit-tracklist-height="false" data-tracklist-height="185" data-reverse-track-order="false" data-max-width="600px" data-initial-track="1" data-tracks-delay="0" data-shuffle="false" data-shuffle-default="false" data-remember-last="false"></div><div id="audioigniter-8999" class="audioigniter-root" data-player-type="global-footer" data-tracks-url="/dev-tracks.json" data-display-active-cover="true" data-display-tracklist-covers="true" data-display-credits="true" data-display-tracklist="false" data-allow-tracklist-toggle="true" data-allow-tracklist-loop="true" data-allow-track-loop="true" data-display-track-no="true" data-allow-playback-rate="true" data-display-artist-names="true" data-display-buy-buttons="true" data-buy-buttons-target="true" data-volume="50" data-skip-amount="15" data-cycle-tracks="false" data-limit-tracklist-height="true" data-tracklist-height="185" data-reverse-track-order="false" data-max-width="600px" data-initial-track="1" data-stop-on-finish="false" data-tracks-delay="0" data-timer-countdown="true" data-shuffle="true" data-soundcloud-client-id="" data-player-buttons='[
|
||||||
data-initial-track="1"
|
{
|
||||||
data-stop-on-finish="false"
|
"title": "CSSIgniter",
|
||||||
data-tracks-delay="5"
|
"url": "https://cssigniter.com",
|
||||||
data-timer-countdown="false"
|
"icon": "<svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 35.9789 8.77641 45.908 20.25 47.7084V30.9375H14.1562V24H20.25V18.7125C20.25 12.6975 23.8331 9.375 29.3152 9.375C31.9402 9.375 34.6875 9.84375 34.6875 9.84375V15.75H31.6613C28.68 15.75 27.75 17.6002 27.75 19.5V24H34.4062L33.3422 30.9375H27.75V47.7084C39.2236 45.908 48 35.9789 48 24Z\" fill=\"black\"/>\n</svg>"
|
||||||
data-shuffle="true"
|
},
|
||||||
data-shuffle-default="false"
|
{
|
||||||
data-soundcloud-client-id=""
|
"title": "",
|
||||||
></div>
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"40\" viewBox=\"0 0 48 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15.1003 39.5001C33.2091 39.5001 43.1166 24.4935 43.1166 11.4838C43.1166 11.0619 43.1072 10.6307 43.0884 10.2088C45.0157 8.81501 46.679 7.0886 48 5.11068C46.205 5.90929 44.2993 6.43085 42.3478 6.65756C44.4026 5.4259 45.9411 3.49103 46.6781 1.21162C44.7451 2.3572 42.6312 3.16531 40.4269 3.60131C38.9417 2.02321 36.978 0.97832 34.8394 0.62819C32.7008 0.278059 30.5064 0.642189 28.5955 1.66428C26.6846 2.68637 25.1636 4.3095 24.2677 6.28271C23.3718 8.25592 23.1509 10.4693 23.6391 12.5807C19.725 12.3843 15.8959 11.3675 12.4 9.59628C8.90405 7.82507 5.81939 5.33896 3.34594 2.29912C2.0888 4.46657 1.70411 7.03138 2.27006 9.47227C2.83601 11.9132 4.31013 14.047 6.39281 15.4401C4.82926 15.3904 3.29995 14.9694 1.93125 14.2119V14.3338C1.92985 16.6084 2.7162 18.8133 4.15662 20.5736C5.59704 22.334 7.60265 23.5412 9.8325 23.9901C8.38411 24.3863 6.86396 24.4441 5.38969 24.1588C6.01891 26.115 7.24315 27.8259 8.89154 29.0528C10.5399 30.2796 12.5302 30.9613 14.5847 31.0026C11.0968 33.7423 6.78835 35.2283 2.35313 35.2213C1.56657 35.2201 0.780798 35.1719 0 35.0769C4.50571 37.9676 9.74706 39.5029 15.1003 39.5001Z\" fill=\"black\"/>\n</svg>"
|
||||||
<div
|
},
|
||||||
class="audioigniter-root"
|
{
|
||||||
data-player-type="simple"
|
"title": "Another title",
|
||||||
data-tracks-url="/dev-tracks.json"
|
"url": "https://cssigniter.com",
|
||||||
data-display-credits="true"
|
"icon": ""
|
||||||
data-display-track-no="true"
|
}
|
||||||
data-allow-playback-rate="true"
|
]
|
||||||
data-display-artist-names="true"
|
'></div></body></html>
|
||||||
data-display-buy-buttons="true"
|
|
||||||
data-buy-buttons-target="true"
|
|
||||||
data-allow-track-loop="true"
|
|
||||||
data-volume="50"
|
|
||||||
data-reverse-track-order="false"
|
|
||||||
data-max-width="600px"
|
|
||||||
data-initial-track="3"
|
|
||||||
data-stop-on-finish="false"
|
|
||||||
data-tracks-delay="0"
|
|
||||||
data-timer-countdown="false"
|
|
||||||
data-shuffle="true"
|
|
||||||
data-soundcloud-client-id=""
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="audioigniter-root"
|
|
||||||
data-player-type="global-footer"
|
|
||||||
data-tracks-url="/dev-tracks.json"
|
|
||||||
data-display-active-cover="true"
|
|
||||||
data-display-tracklist-covers="true"
|
|
||||||
data-display-credits="true"
|
|
||||||
data-display-tracklist="false"
|
|
||||||
data-allow-tracklist-toggle="true"
|
|
||||||
data-allow-tracklist-loop="true"
|
|
||||||
data-allow-track-loop="true"
|
|
||||||
data-display-track-no="true"
|
|
||||||
data-allow-playback-rate="true"
|
|
||||||
data-display-artist-names="true"
|
|
||||||
data-display-buy-buttons="true"
|
|
||||||
data-buy-buttons-target="true"
|
|
||||||
data-volume="50"
|
|
||||||
data-skip-amount="15"
|
|
||||||
data-cycle-tracks="false"
|
|
||||||
data-limit-tracklist-height="true"
|
|
||||||
data-tracklist-height="185"
|
|
||||||
data-reverse-track-order="false"
|
|
||||||
data-max-width="600px"
|
|
||||||
data-initial-track="1"
|
|
||||||
data-stop-on-finish="false"
|
|
||||||
data-tracks-delay="0"
|
|
||||||
data-timer-countdown="true"
|
|
||||||
data-shuffle="true"
|
|
||||||
data-soundcloud-client-id=""
|
|
||||||
></div>
|
|
||||||
<script type="text/javascript" src="app.js"></script><script type="text/javascript" src="style.js"></script></body>
|
|
||||||
</html>
|
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
|||||||
!function(n){function r(e){if(t[e])return t[e].exports;var o=t[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var t={};r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e})},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,r){return Object.prototype.hasOwnProperty.call(n,r)},r.p="",r(r.s=28)}({28:function(n,r){}});
|
|
@ -5,7 +5,7 @@
|
|||||||
"audio": "https://www.cssigniter.com/assets/audioigniter/sunrise.mp3",
|
"audio": "https://www.cssigniter.com/assets/audioigniter/sunrise.mp3",
|
||||||
"buyUrl": "https://www.cssigniter.com",
|
"buyUrl": "https://www.cssigniter.com",
|
||||||
"downloadUrl": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3",
|
"downloadUrl": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3",
|
||||||
"cover": "https:\/\/www.cssigniter.com\/preview\/audioigniter\/files\/2016\/08\/Thoribass-Sunrise.jpg",
|
"cover": "https://www.cssigniter.com/demos/audioigniter/wp-content/uploads/sites/48/2016/08/CyberSDF-Flame-and-Go.jpg",
|
||||||
"lyrics": "Here in my mind\nYou know you might find\nSomething that you\n\nYou thought you once knew\nBut now it's all gone\nAnd you know it's no fun\n\nYeah I know it's no fun\nOh I know it's no fun\nI'm free to be whatever I\nWhatever I choose\nAnd I'll sing the blues if I want\nI'm free to be whatever I\nWhatever I choose\nAnd I'll sing the blues if I want\nWhatever you do\nWhatever you say\nYeah I know it's alright"
|
"lyrics": "Here in my mind\nYou know you might find\nSomething that you\n\nYou thought you once knew\nBut now it's all gone\nAnd you know it's no fun\n\nYeah I know it's no fun\nOh I know it's no fun\nI'm free to be whatever I\nWhatever I choose\nAnd I'll sing the blues if I want\nI'm free to be whatever I\nWhatever I choose\nAnd I'll sing the blues if I want\nWhatever you do\nWhatever you say\nYeah I know it's alright"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -14,14 +14,14 @@
|
|||||||
"audio": "https://www.cssigniter.com/assets/audioigniter/sunrise.mp3",
|
"audio": "https://www.cssigniter.com/assets/audioigniter/sunrise.mp3",
|
||||||
"buyUrl": "https://www.cssigniter.com",
|
"buyUrl": "https://www.cssigniter.com",
|
||||||
"downloadUrl": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3",
|
"downloadUrl": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3",
|
||||||
"cover": "https:\/\/www.cssigniter.com\/preview\/audioigniter\/files\/2016\/08\/The-Fisherman-Another-Day.jpg"
|
"cover": "https://www.cssigniter.com/demos/audioigniter/wp-content/uploads/sites/48/2016/08/Thoribass-Sunrise.jpg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Remix Safety Guide",
|
"title": "Remix Safety Guide",
|
||||||
"subtitle": "Rocavaco",
|
"subtitle": "Rocavaco",
|
||||||
"audio": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/remix.mp3",
|
"audio": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/remix.mp3",
|
||||||
"buyUrl": "https://www.cssigniter.com",
|
"buyUrl": "https://www.cssigniter.com",
|
||||||
"cover": "https:\/\/www.cssigniter.com\/preview\/audioigniter\/files\/2016\/08\/Rocavaco-Remix-Safety-Guide.jpg",
|
"cover": "https://www.cssigniter.com/demos/audioigniter/wp-content/uploads/sites/48/2016/08/The-Fisherman-Another-Day.jpg",
|
||||||
"lyrics": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. At eius hic illo natus vitae. Assumenda commodi eaque eos est eum excepturi fugiat provident, quidem saepe? Aut doloremque, unde? Delectus, dolorum."
|
"lyrics": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. At eius hic illo natus vitae. Assumenda commodi eaque eos est eum excepturi fugiat provident, quidem saepe? Aut doloremque, unde? Delectus, dolorum."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -37,28 +37,28 @@
|
|||||||
"subtitle": "Syl Johnson (SoundCloud)",
|
"subtitle": "Syl Johnson (SoundCloud)",
|
||||||
"audio": "https://soundcloud.com/enterofficial/maceo-plex-b2b-richie-hawtin-enterweek-11-sake-bar-space-ibiza-september-10th-2015",
|
"audio": "https://soundcloud.com/enterofficial/maceo-plex-b2b-richie-hawtin-enterweek-11-sake-bar-space-ibiza-september-10th-2015",
|
||||||
"buyUrl": "",
|
"buyUrl": "",
|
||||||
"cover": "https://www.cssigniter.com/preview/audioigniter/files/2016/08/artworks-000103551140-ez6k4x-t500x500.jpg"
|
"cover": "https://www.cssigniter.com/demos/audioigniter/wp-content/uploads/sites/48/2016/08/Rocavaco-Remix-Safety-Guide.jpg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Deep House Radio",
|
"title": "Deep House Radio",
|
||||||
"subtitle": "",
|
"subtitle": "",
|
||||||
"audio": "https://deephouseradio.radioca.st/stream/1/",
|
"audio": "https://deephouseradio.radioca.st/stream/1/",
|
||||||
"buyUrl": "https://www.cssigniter.com",
|
"buyUrl": "https://www.cssigniter.com",
|
||||||
"cover": "https://www.cssigniter.com/preview/audioigniter/files/2016/08/Rocavaco-Remix-Safety-Guide.jpg"
|
"cover": "https://www.cssigniter.com/demos/audioigniter/wp-content/uploads/sites/48/2016/08/MegaEnx-Tomorrow.jpg"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Flash of Light",
|
"title": "Flash of Light",
|
||||||
"subtitle": "Kxmode",
|
"subtitle": "Kxmode",
|
||||||
"audio": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/flashlight.mp3",
|
"audio": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/flashlight.mp3",
|
||||||
"buyUrl": "https://www.cssigniter.com",
|
"buyUrl": "https://www.cssigniter.com",
|
||||||
"cover": "https:\/\/www.cssigniter.com\/preview\/audioigniter\/files\/2016\/08\/Kxmode-Flash-of-Light.jpg",
|
"cover": "https://www.cssigniter.com/demos/audioigniter/wp-content/uploads/sites/48/2016/08/BitBurner-We-Get-Mental.jpg",
|
||||||
"lyrics": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. At eius hic illo natus vitae. Assumenda commodi eaque eos est eum excepturi fugiat provident, quidem saepe? Aut doloremque, unde? Delectus, dolorum."
|
"lyrics": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. At eius hic illo natus vitae. Assumenda commodi eaque eos est eum excepturi fugiat provident, quidem saepe? Aut doloremque, unde? Delectus, dolorum."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "We Get Mental",
|
"title": "We Get Mental",
|
||||||
"subtitle": "BitBurner",
|
"subtitle": "BitBurner",
|
||||||
"audio": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/mental.mp3",
|
"audio": "https:\/\/www.cssigniter.com\/assets\/audioigniter\/mental.mp3",
|
||||||
"buyUrl": "",
|
"buyUrl": "",
|
||||||
"cover": "https:\/\/www.cssigniter.com\/preview\/audioigniter\/files\/2016\/08\/BitBurner-We-Get-Mental.jpg"
|
"cover": "https://www.cssigniter.com/demos/audioigniter/wp-content/uploads/sites/48/2016/08/Kxmode-Flash-of-Light.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
"start": "webpack-dev-server",
|
"start": "webpack-dev-server",
|
||||||
"build": "rm -rf ./build && webpack",
|
"build": "rm -rf ./build && webpack",
|
||||||
"lint": "eslint ./src --ext .js --ext .jsx --cache || true",
|
"lint": "eslint ./src --ext .js --ext .jsx --cache || true",
|
||||||
|
"webpack-profile": "webpack --json > stats.json",
|
||||||
|
"babel-lala": "babel --plugins transform-react-remove-prop-types build/app.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -17,46 +19,53 @@
|
|||||||
"author": "vmasto",
|
"author": "vmasto",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.17.10",
|
||||||
|
"@babel/core": "^7.18.5",
|
||||||
|
"@babel/eslint-parser": "^7.18.2",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.17.12",
|
||||||
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12",
|
||||||
|
"@babel/plugin-proposal-object-rest-spread": "^7.18.0",
|
||||||
|
"@babel/plugin-proposal-optional-chaining": "^7.17.12",
|
||||||
|
"@babel/preset-env": "^7.18.2",
|
||||||
|
"@babel/preset-react": "^7.17.12",
|
||||||
"autoprefixer": "^7.1.2",
|
"autoprefixer": "^7.1.2",
|
||||||
"babel-core": "^6.25.0",
|
"babel-loader": "^8.2.5",
|
||||||
"babel-loader": "^7.1.1",
|
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"css-loader": "^6.7.1",
|
||||||
"babel-preset-react": "^6.24.1",
|
"eslint": "^8.18.0",
|
||||||
"babel-preset-react-hmre": "1.1.1",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"babel-preset-stage-1": "^6.24.1",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"babel-preset-stage-2": "^6.24.1",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"css-loader": "^0.28.4",
|
"eslint-plugin-babel": "^5.3.1",
|
||||||
"eslint": "3.19.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-config-airbnb": "15.0.2",
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||||
"eslint-config-airbnb-base": "^11.2.0",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-config-prettier": "^4.1.0",
|
"eslint-plugin-react": "^7.30.0",
|
||||||
"eslint-plugin-import": "2.7.0",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"eslint-plugin-jsx-a11y": "5.1.1",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"eslint-plugin-prettier": "^3.0.1",
|
"mini-css-extract-plugin": "^2.6.1",
|
||||||
"eslint-plugin-react": "7.1.0",
|
"postcss-loader": "^7.0.0",
|
||||||
"extract-text-webpack-plugin": "^3.0.0",
|
"precss": "^4.0.0",
|
||||||
"html-webpack-plugin": "^2.29.0",
|
|
||||||
"node-sass": "^4.5.3",
|
|
||||||
"postcss-loader": "^2.0.6",
|
|
||||||
"precss": "^2.0.0",
|
|
||||||
"prettier": "^1.16.4",
|
"prettier": "^1.16.4",
|
||||||
"sass-loader": "^6.0.6",
|
"sass": "^1.52.3",
|
||||||
"style-loader": "^0.18.2",
|
"sass-loader": "11.0.1",
|
||||||
"webpack": "^3.2.0",
|
"style-loader": "^3.3.1",
|
||||||
"webpack-dev-server": "^2.5.1",
|
"terser-webpack-plugin": "^5.3.3",
|
||||||
|
"webpack": "5.72.1",
|
||||||
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
|
"webpack-cli": "^4.10.0",
|
||||||
|
"webpack-dev-server": "^4.9.2",
|
||||||
"webpack-merge": "^4.1.0"
|
"webpack-merge": "^4.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classnames": "2.3.0",
|
"classnames": "2.3.0",
|
||||||
"es6-promise": "^4.1.1",
|
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^16.8.3",
|
"react": "^18.2.0",
|
||||||
"react-custom-scrollbars": "^4.1.2",
|
"react-custom-scrollbars": "^4.1.2",
|
||||||
"react-dom": "^16.8.3",
|
"react-dom": "^18.2.0",
|
||||||
"react-modal": "^3.8.1",
|
"react-modal": "^3.8.1",
|
||||||
"react-sound": "^1.2.0",
|
"react-sound": "^1.2.0",
|
||||||
"soundmanager2": "^2.97.20170602",
|
"soundmanager2": "^2.97.20170602",
|
||||||
"sprintf-js": "1.1.1",
|
"sprintf-js": "1.1.1"
|
||||||
"whatwg-fetch": "0.11.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,14 @@
|
|||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
padding-bottom: 120px;
|
padding-bottom: 120px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div
|
<div
|
||||||
|
id="audioigniter-2799"
|
||||||
class="audioigniter-root"
|
class="audioigniter-root"
|
||||||
data-player-type="full"
|
data-player-type="full"
|
||||||
data-tracks-url="/dev-tracks.json"
|
data-tracks-url="/dev-tracks.json"
|
||||||
@ -42,9 +43,29 @@
|
|||||||
data-shuffle="true"
|
data-shuffle="true"
|
||||||
data-shuffle-default="false"
|
data-shuffle-default="false"
|
||||||
data-soundcloud-client-id=""
|
data-soundcloud-client-id=""
|
||||||
|
data-remember-last="true"
|
||||||
|
data-player-buttons='[
|
||||||
|
{
|
||||||
|
"title": "CSSIgniter",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 35.9789 8.77641 45.908 20.25 47.7084V30.9375H14.1562V24H20.25V18.7125C20.25 12.6975 23.8331 9.375 29.3152 9.375C31.9402 9.375 34.6875 9.84375 34.6875 9.84375V15.75H31.6613C28.68 15.75 27.75 17.6002 27.75 19.5V24H34.4062L33.3422 30.9375H27.75V47.7084C39.2236 45.908 48 35.9789 48 24Z\" fill=\"black\"/>\n</svg>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"40\" viewBox=\"0 0 48 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15.1003 39.5001C33.2091 39.5001 43.1166 24.4935 43.1166 11.4838C43.1166 11.0619 43.1072 10.6307 43.0884 10.2088C45.0157 8.81501 46.679 7.0886 48 5.11068C46.205 5.90929 44.2993 6.43085 42.3478 6.65756C44.4026 5.4259 45.9411 3.49103 46.6781 1.21162C44.7451 2.3572 42.6312 3.16531 40.4269 3.60131C38.9417 2.02321 36.978 0.97832 34.8394 0.62819C32.7008 0.278059 30.5064 0.642189 28.5955 1.66428C26.6846 2.68637 25.1636 4.3095 24.2677 6.28271C23.3718 8.25592 23.1509 10.4693 23.6391 12.5807C19.725 12.3843 15.8959 11.3675 12.4 9.59628C8.90405 7.82507 5.81939 5.33896 3.34594 2.29912C2.0888 4.46657 1.70411 7.03138 2.27006 9.47227C2.83601 11.9132 4.31013 14.047 6.39281 15.4401C4.82926 15.3904 3.29995 14.9694 1.93125 14.2119V14.3338C1.92985 16.6084 2.7162 18.8133 4.15662 20.5736C5.59704 22.334 7.60265 23.5412 9.8325 23.9901C8.38411 24.3863 6.86396 24.4441 5.38969 24.1588C6.01891 26.115 7.24315 27.8259 8.89154 29.0528C10.5399 30.2796 12.5302 30.9613 14.5847 31.0026C11.0968 33.7423 6.78835 35.2283 2.35313 35.2213C1.56657 35.2201 0.780798 35.1719 0 35.0769C4.50571 37.9676 9.74706 39.5029 15.1003 39.5001Z\" fill=\"black\"/>\n</svg>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Another title",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
id="audioigniter-2999"
|
||||||
class="audioigniter-root"
|
class="audioigniter-root"
|
||||||
data-player-type="simple"
|
data-player-type="simple"
|
||||||
data-tracks-url="/dev-tracks.json"
|
data-tracks-url="/dev-tracks.json"
|
||||||
@ -64,9 +85,63 @@
|
|||||||
data-timer-countdown="false"
|
data-timer-countdown="false"
|
||||||
data-shuffle="true"
|
data-shuffle="true"
|
||||||
data-soundcloud-client-id=""
|
data-soundcloud-client-id=""
|
||||||
|
data-player-buttons='[
|
||||||
|
{
|
||||||
|
"title": "CSSIgniter",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 35.9789 8.77641 45.908 20.25 47.7084V30.9375H14.1562V24H20.25V18.7125C20.25 12.6975 23.8331 9.375 29.3152 9.375C31.9402 9.375 34.6875 9.84375 34.6875 9.84375V15.75H31.6613C28.68 15.75 27.75 17.6002 27.75 19.5V24H34.4062L33.3422 30.9375H27.75V47.7084C39.2236 45.908 48 35.9789 48 24Z\" fill=\"black\"/>\n</svg>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"40\" viewBox=\"0 0 48 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15.1003 39.5001C33.2091 39.5001 43.1166 24.4935 43.1166 11.4838C43.1166 11.0619 43.1072 10.6307 43.0884 10.2088C45.0157 8.81501 46.679 7.0886 48 5.11068C46.205 5.90929 44.2993 6.43085 42.3478 6.65756C44.4026 5.4259 45.9411 3.49103 46.6781 1.21162C44.7451 2.3572 42.6312 3.16531 40.4269 3.60131C38.9417 2.02321 36.978 0.97832 34.8394 0.62819C32.7008 0.278059 30.5064 0.642189 28.5955 1.66428C26.6846 2.68637 25.1636 4.3095 24.2677 6.28271C23.3718 8.25592 23.1509 10.4693 23.6391 12.5807C19.725 12.3843 15.8959 11.3675 12.4 9.59628C8.90405 7.82507 5.81939 5.33896 3.34594 2.29912C2.0888 4.46657 1.70411 7.03138 2.27006 9.47227C2.83601 11.9132 4.31013 14.047 6.39281 15.4401C4.82926 15.3904 3.29995 14.9694 1.93125 14.2119V14.3338C1.92985 16.6084 2.7162 18.8133 4.15662 20.5736C5.59704 22.334 7.60265 23.5412 9.8325 23.9901C8.38411 24.3863 6.86396 24.4441 5.38969 24.1588C6.01891 26.115 7.24315 27.8259 8.89154 29.0528C10.5399 30.2796 12.5302 30.9613 14.5847 31.0026C11.0968 33.7423 6.78835 35.2283 2.35313 35.2213C1.56657 35.2201 0.780798 35.1719 0 35.0769C4.50571 37.9676 9.74706 39.5029 15.1003 39.5001Z\" fill=\"black\"/>\n</svg>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Another title",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
id="audioigniter-2519"
|
||||||
|
class="audioigniter-root"
|
||||||
|
|
||||||
|
data-track='{"title":"Sunrise","subtitle":"Thoribass","audio":"https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3","buyUrl":"https:\/\/google.com","downloadUrl":"https:\/\/www.cssigniter.com\/assets\/audioigniter\/sunrise.mp3","cover":"https:\/\/www.cssigniter.com\/demos\/audioigniter\/wp-content\/uploads\/sites\/48\/2016\/08\/CyberSDF-Flame-and-Go.jpg","lyrics":"Some lyrics"}'
|
||||||
|
data-display-active-cover="false"
|
||||||
|
data-display-credits="true"
|
||||||
|
data-allow-playback-rate="false"
|
||||||
|
data-display-buy-buttons="true"
|
||||||
|
data-volume="100"
|
||||||
|
data-skip-amount="0"
|
||||||
|
data-stop-on-finish="true"
|
||||||
|
data-timer-countdown="false"
|
||||||
|
|
||||||
|
data-player-type="full"
|
||||||
|
data-tracks-url=""
|
||||||
|
data-display-tracklist="false"
|
||||||
|
data-allow-tracklist-toggle="true"
|
||||||
|
data-allow-tracklist-loop="true"
|
||||||
|
data-allow-track-loop="true"
|
||||||
|
data-display-track-no="false"
|
||||||
|
data-display-artist-names="true"
|
||||||
|
data-buy-buttons-target="true"
|
||||||
|
data-cycle-tracks="false"
|
||||||
|
data-limit-tracklist-height="false"
|
||||||
|
data-tracklist-height="185"
|
||||||
|
data-reverse-track-order="false"
|
||||||
|
data-max-width="600px"
|
||||||
|
data-initial-track="1"
|
||||||
|
data-tracks-delay="0"
|
||||||
|
data-shuffle="false"
|
||||||
|
data-shuffle-default="false"
|
||||||
|
data-remember-last="false"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="audioigniter-8999"
|
||||||
class="audioigniter-root"
|
class="audioigniter-root"
|
||||||
data-player-type="global-footer"
|
data-player-type="global-footer"
|
||||||
data-tracks-url="/dev-tracks.json"
|
data-tracks-url="/dev-tracks.json"
|
||||||
@ -95,6 +170,24 @@
|
|||||||
data-timer-countdown="true"
|
data-timer-countdown="true"
|
||||||
data-shuffle="true"
|
data-shuffle="true"
|
||||||
data-soundcloud-client-id=""
|
data-soundcloud-client-id=""
|
||||||
|
data-player-buttons='[
|
||||||
|
{
|
||||||
|
"title": "CSSIgniter",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 35.9789 8.77641 45.908 20.25 47.7084V30.9375H14.1562V24H20.25V18.7125C20.25 12.6975 23.8331 9.375 29.3152 9.375C31.9402 9.375 34.6875 9.84375 34.6875 9.84375V15.75H31.6613C28.68 15.75 27.75 17.6002 27.75 19.5V24H34.4062L33.3422 30.9375H27.75V47.7084C39.2236 45.908 48 35.9789 48 24Z\" fill=\"black\"/>\n</svg>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": "<svg width=\"48\" height=\"40\" viewBox=\"0 0 48 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15.1003 39.5001C33.2091 39.5001 43.1166 24.4935 43.1166 11.4838C43.1166 11.0619 43.1072 10.6307 43.0884 10.2088C45.0157 8.81501 46.679 7.0886 48 5.11068C46.205 5.90929 44.2993 6.43085 42.3478 6.65756C44.4026 5.4259 45.9411 3.49103 46.6781 1.21162C44.7451 2.3572 42.6312 3.16531 40.4269 3.60131C38.9417 2.02321 36.978 0.97832 34.8394 0.62819C32.7008 0.278059 30.5064 0.642189 28.5955 1.66428C26.6846 2.68637 25.1636 4.3095 24.2677 6.28271C23.3718 8.25592 23.1509 10.4693 23.6391 12.5807C19.725 12.3843 15.8959 11.3675 12.4 9.59628C8.90405 7.82507 5.81939 5.33896 3.34594 2.29912C2.0888 4.46657 1.70411 7.03138 2.27006 9.47227C2.83601 11.9132 4.31013 14.047 6.39281 15.4401C4.82926 15.3904 3.29995 14.9694 1.93125 14.2119V14.3338C1.92985 16.6084 2.7162 18.8133 4.15662 20.5736C5.59704 22.334 7.60265 23.5412 9.8325 23.9901C8.38411 24.3863 6.86396 24.4441 5.38969 24.1588C6.01891 26.115 7.24315 27.8259 8.89154 29.0528C10.5399 30.2796 12.5302 30.9613 14.5847 31.0026C11.0968 33.7423 6.78835 35.2283 2.35313 35.2213C1.56657 35.2201 0.780798 35.1719 0 35.0769C4.50571 37.9676 9.74706 39.5029 15.1003 39.5001Z\" fill=\"black\"/>\n</svg>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Another title",
|
||||||
|
"url": "https://cssigniter.com",
|
||||||
|
"icon": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'
|
||||||
></div>
|
></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { createRoot } from 'react-dom/client';
|
||||||
import 'es6-promise/auto';
|
|
||||||
import 'whatwg-fetch';
|
|
||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
@ -35,7 +33,9 @@ function renderApp(node) {
|
|||||||
const type = node.getAttribute('data-player-type');
|
const type = node.getAttribute('data-player-type');
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
|
playerId: node.getAttribute('id'),
|
||||||
tracksUrl: node.getAttribute('data-tracks-url'),
|
tracksUrl: node.getAttribute('data-tracks-url'),
|
||||||
|
track: node.getAttribute('data-track'),
|
||||||
displayTracklistCovers: JSON.parse(
|
displayTracklistCovers: JSON.parse(
|
||||||
node.getAttribute('data-display-tracklist-covers'),
|
node.getAttribute('data-display-tracklist-covers'),
|
||||||
),
|
),
|
||||||
@ -82,9 +82,12 @@ function renderApp(node) {
|
|||||||
countdownTimerByDefault: JSON.parse(
|
countdownTimerByDefault: JSON.parse(
|
||||||
node.getAttribute('data-timer-countdown'),
|
node.getAttribute('data-timer-countdown'),
|
||||||
),
|
),
|
||||||
|
rememberLastPosition: JSON.parse(node.getAttribute('data-remember-last')),
|
||||||
|
playerButtons: JSON.parse(node.getAttribute('data-player-buttons')),
|
||||||
};
|
};
|
||||||
|
|
||||||
render(<App type={type} {...props} />, node);
|
const root = createRoot(node);
|
||||||
|
root.render(<App type={type} {...props} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.prototype.slice.call(nodes).forEach(node => {
|
Array.prototype.slice.call(nodes).forEach(node => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Sound from 'react-sound';
|
import Sound from 'react-sound';
|
||||||
import { sprintf } from 'sprintf-js';
|
import { sprintf } from 'sprintf-js';
|
||||||
@ -22,269 +22,9 @@ import {
|
|||||||
} from './components/Icons';
|
} from './components/Icons';
|
||||||
import { AppContext } from '../App';
|
import { AppContext } from '../App';
|
||||||
import typographyDisabled from '../utils/typography-disabled';
|
import typographyDisabled from '../utils/typography-disabled';
|
||||||
|
import PlayerButtons from './components/PlayerButtons';
|
||||||
|
|
||||||
class GlobalFooterPlayer extends React.Component {
|
const propTypes = {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isTrackListOpen: this.props.displayTracklist,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.toggleTracklist = this.toggleTracklist.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleTracklist() {
|
|
||||||
this.setState(state => ({
|
|
||||||
isTrackListOpen: !state.isTrackListOpen,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { isTrackListOpen } = this.state;
|
|
||||||
|
|
||||||
const {
|
|
||||||
tracks,
|
|
||||||
playStatus,
|
|
||||||
activeIndex,
|
|
||||||
volume,
|
|
||||||
position,
|
|
||||||
duration,
|
|
||||||
playbackRate,
|
|
||||||
|
|
||||||
currentTrack,
|
|
||||||
playTrack,
|
|
||||||
togglePlay,
|
|
||||||
nextTrack,
|
|
||||||
prevTrack,
|
|
||||||
setPosition,
|
|
||||||
setVolume,
|
|
||||||
toggleTracklistCycling,
|
|
||||||
cycleTracks,
|
|
||||||
setTrackCycling,
|
|
||||||
setPlaybackRate,
|
|
||||||
|
|
||||||
allowPlaybackRate,
|
|
||||||
allowTracklistToggle,
|
|
||||||
allowTracklistLoop,
|
|
||||||
allowTrackLoop,
|
|
||||||
reverseTrackOrder,
|
|
||||||
displayTrackNo,
|
|
||||||
displayTracklistCovers,
|
|
||||||
displayActiveCover,
|
|
||||||
limitTracklistHeight,
|
|
||||||
tracklistHeight,
|
|
||||||
displayBuyButtons,
|
|
||||||
buyButtonsTarget,
|
|
||||||
displayArtistNames,
|
|
||||||
repeatingTrackIndex,
|
|
||||||
skipAmount,
|
|
||||||
skipPosition,
|
|
||||||
countdownTimerByDefault,
|
|
||||||
buffering,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const classes = classNames({
|
|
||||||
'ai-wrap': true,
|
|
||||||
'ai-type-global-footer': true,
|
|
||||||
'ai-is-loading': !tracks.length,
|
|
||||||
'ai-with-typography': !typographyDisabled(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const audioControlClasses = classNames({
|
|
||||||
'ai-audio-control': true,
|
|
||||||
'ai-audio-playing': playStatus === Sound.status.PLAYING,
|
|
||||||
'ai-audio-loading': buffering,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={ref => (this.root = ref)} // eslint-disable-line no-return-assign
|
|
||||||
className={classes}
|
|
||||||
>
|
|
||||||
<div className="ai-control-wrap">
|
|
||||||
{displayActiveCover && (
|
|
||||||
<Cover
|
|
||||||
className="ai-thumb ai-control-wrap-thumb"
|
|
||||||
src={currentTrack.cover}
|
|
||||||
alt={currentTrack.title}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="ai-control-wrap-controls">
|
|
||||||
<ProgressBar
|
|
||||||
setPosition={setPosition}
|
|
||||||
duration={duration}
|
|
||||||
position={position}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="ai-audio-controls-main">
|
|
||||||
<Button
|
|
||||||
onClick={togglePlay}
|
|
||||||
className={audioControlClasses}
|
|
||||||
ariaLabel={
|
|
||||||
playStatus === Sound.status.PLAYING
|
|
||||||
? sprintf(aiStrings.pause_title, currentTrack.title)
|
|
||||||
: sprintf(aiStrings.play_title, currentTrack.title)
|
|
||||||
}
|
|
||||||
ariaPressed={playStatus === Sound.status.PLAYING}
|
|
||||||
>
|
|
||||||
{playStatus === Sound.status.PLAYING ? (
|
|
||||||
<PauseIcon />
|
|
||||||
) : (
|
|
||||||
<PlayIcon />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<span className="ai-control-spinner" />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<div className="ai-audio-controls-meta">
|
|
||||||
{tracks.length > 1 && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-tracklist-prev"
|
|
||||||
onClick={prevTrack}
|
|
||||||
ariaLabel={aiStrings.previous}
|
|
||||||
>
|
|
||||||
<PreviousIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{tracks.length > 1 && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-tracklist-next"
|
|
||||||
onClick={nextTrack}
|
|
||||||
ariaLabel={aiStrings.next}
|
|
||||||
>
|
|
||||||
<NextIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<VolumeControl
|
|
||||||
volume={volume}
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
setVolume={setVolume}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{allowTracklistLoop && (
|
|
||||||
<Button
|
|
||||||
className={`ai-btn ai-btn-repeat ${cycleTracks &&
|
|
||||||
'ai-btn-active'}`}
|
|
||||||
onClick={toggleTracklistCycling}
|
|
||||||
ariaLabel={aiStrings.toggle_list_repeat}
|
|
||||||
>
|
|
||||||
<RefreshIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{allowPlaybackRate && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-btn-playback-rate"
|
|
||||||
onClick={setPlaybackRate}
|
|
||||||
ariaLabel={aiStrings.set_playback_rate}
|
|
||||||
>
|
|
||||||
<Fragment>×{playbackRate}</Fragment>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{skipAmount > 0 && (
|
|
||||||
<Fragment>
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-btn-skip-position"
|
|
||||||
onClick={() => skipPosition(-1)}
|
|
||||||
ariaLabel={aiStrings.skip_backward}
|
|
||||||
>
|
|
||||||
-{skipAmount}s
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-btn-skip-position"
|
|
||||||
onClick={() => skipPosition(1)}
|
|
||||||
ariaLabel={aiStrings.skip_forward}
|
|
||||||
>
|
|
||||||
+{skipAmount}s
|
|
||||||
</Button>
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{currentTrack && currentTrack.lyrics && !isTrackListOpen && (
|
|
||||||
<AppContext.Consumer>
|
|
||||||
{({ toggleLyricsModal }) => (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-lyrics"
|
|
||||||
onClick={() => toggleLyricsModal(true, currentTrack)}
|
|
||||||
ariaLabel={aiStrings.open_track_lyrics}
|
|
||||||
title={aiStrings.open_track_lyrics}
|
|
||||||
>
|
|
||||||
<LyricsIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</AppContext.Consumer>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="ai-track-info">
|
|
||||||
<p className="ai-track-title">
|
|
||||||
<span>{currentTrack.title}</span>
|
|
||||||
</p>
|
|
||||||
{(tracks.length === 0 || currentTrack.subtitle) &&
|
|
||||||
displayArtistNames && (
|
|
||||||
<p className="ai-track-subtitle">
|
|
||||||
<span>{currentTrack.subtitle}</span>
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="ai-audio-controls-meta-right">
|
|
||||||
<Time
|
|
||||||
duration={duration}
|
|
||||||
position={position}
|
|
||||||
countdown={countdownTimerByDefault}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{allowTracklistToggle && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-tracklist-toggle"
|
|
||||||
onClick={this.toggleTracklist}
|
|
||||||
ariaLabel={aiStrings.toggle_list_visible}
|
|
||||||
>
|
|
||||||
<PlaylistIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`ai-tracklist-wrap ${
|
|
||||||
isTrackListOpen ? 'ai-tracklist-open' : ''
|
|
||||||
}`}
|
|
||||||
style={{ display: isTrackListOpen ? 'block' : 'none' }}
|
|
||||||
>
|
|
||||||
<TracklistWrap
|
|
||||||
className="ai-tracklist"
|
|
||||||
trackClassName="ai-track"
|
|
||||||
tracks={tracks}
|
|
||||||
activeTrackIndex={activeIndex}
|
|
||||||
isOpen={isTrackListOpen}
|
|
||||||
displayTrackNo={displayTrackNo}
|
|
||||||
displayCovers={displayTracklistCovers}
|
|
||||||
displayBuyButtons={displayBuyButtons}
|
|
||||||
buyButtonsTarget={buyButtonsTarget}
|
|
||||||
displayArtistNames={displayArtistNames}
|
|
||||||
reverseTrackOrder={reverseTrackOrder}
|
|
||||||
limitTracklistHeight={limitTracklistHeight}
|
|
||||||
tracklistHeight={tracklistHeight}
|
|
||||||
onTrackClick={playTrack}
|
|
||||||
onTrackLoop={allowTrackLoop ? setTrackCycling : undefined}
|
|
||||||
repeatingTrackIndex={repeatingTrackIndex}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalFooterPlayer.propTypes = {
|
|
||||||
tracks: PropTypes.arrayOf(PropTypes.object),
|
tracks: PropTypes.arrayOf(PropTypes.object),
|
||||||
playStatus: PropTypes.oneOf([
|
playStatus: PropTypes.oneOf([
|
||||||
Sound.status.PLAYING,
|
Sound.status.PLAYING,
|
||||||
@ -304,11 +44,11 @@ GlobalFooterPlayer.propTypes = {
|
|||||||
setVolume: PropTypes.func.isRequired,
|
setVolume: PropTypes.func.isRequired,
|
||||||
toggleTracklistCycling: PropTypes.func.isRequired,
|
toggleTracklistCycling: PropTypes.func.isRequired,
|
||||||
cycleTracks: PropTypes.bool.isRequired,
|
cycleTracks: PropTypes.bool.isRequired,
|
||||||
displayTracklist: PropTypes.bool,
|
|
||||||
allowTracklistToggle: PropTypes.bool,
|
allowTracklistToggle: PropTypes.bool,
|
||||||
allowTracklistLoop: PropTypes.bool,
|
allowTracklistLoop: PropTypes.bool,
|
||||||
reverseTrackOrder: PropTypes.bool,
|
reverseTrackOrder: PropTypes.bool,
|
||||||
displayTrackNo: PropTypes.bool,
|
displayTrackNo: PropTypes.bool,
|
||||||
|
displayTracklist: PropTypes.bool,
|
||||||
displayActiveCover: PropTypes.bool,
|
displayActiveCover: PropTypes.bool,
|
||||||
displayTracklistCovers: PropTypes.bool,
|
displayTracklistCovers: PropTypes.bool,
|
||||||
limitTracklistHeight: PropTypes.bool,
|
limitTracklistHeight: PropTypes.bool,
|
||||||
@ -326,8 +66,262 @@ GlobalFooterPlayer.propTypes = {
|
|||||||
countdownTimerByDefault: PropTypes.bool,
|
countdownTimerByDefault: PropTypes.bool,
|
||||||
allowPlaybackRate: PropTypes.bool,
|
allowPlaybackRate: PropTypes.bool,
|
||||||
buffering: PropTypes.bool,
|
buffering: PropTypes.bool,
|
||||||
|
playerButtons: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
title: PropTypes.string,
|
||||||
|
url: PropTypes.string,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const GlobalFooterPlayer = ({
|
||||||
|
tracks,
|
||||||
|
playStatus,
|
||||||
|
activeIndex,
|
||||||
|
volume,
|
||||||
|
position,
|
||||||
|
duration,
|
||||||
|
playbackRate,
|
||||||
|
|
||||||
|
currentTrack,
|
||||||
|
playTrack,
|
||||||
|
togglePlay,
|
||||||
|
nextTrack,
|
||||||
|
prevTrack,
|
||||||
|
setPosition,
|
||||||
|
setVolume,
|
||||||
|
toggleTracklistCycling,
|
||||||
|
cycleTracks,
|
||||||
|
setTrackCycling,
|
||||||
|
setPlaybackRate,
|
||||||
|
|
||||||
|
allowPlaybackRate,
|
||||||
|
allowTracklistToggle,
|
||||||
|
allowTracklistLoop,
|
||||||
|
allowTrackLoop,
|
||||||
|
reverseTrackOrder,
|
||||||
|
displayTracklist,
|
||||||
|
displayTrackNo,
|
||||||
|
displayTracklistCovers,
|
||||||
|
displayActiveCover,
|
||||||
|
limitTracklistHeight,
|
||||||
|
tracklistHeight,
|
||||||
|
displayBuyButtons,
|
||||||
|
buyButtonsTarget,
|
||||||
|
displayArtistNames,
|
||||||
|
repeatingTrackIndex,
|
||||||
|
skipAmount,
|
||||||
|
skipPosition,
|
||||||
|
countdownTimerByDefault,
|
||||||
|
buffering,
|
||||||
|
playerButtons,
|
||||||
|
}) => {
|
||||||
|
const [isTrackListOpen, setTracklistOpen] = useState(displayTracklist);
|
||||||
|
const toggleTracklist = () => {
|
||||||
|
setTracklistOpen(x => !x);
|
||||||
|
};
|
||||||
|
|
||||||
|
const classes = classNames({
|
||||||
|
'ai-wrap': true,
|
||||||
|
'ai-type-global-footer': true,
|
||||||
|
'ai-is-loading': !tracks.length,
|
||||||
|
'ai-with-typography': !typographyDisabled(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const audioControlClasses = classNames({
|
||||||
|
'ai-audio-control': true,
|
||||||
|
'ai-audio-playing': playStatus === Sound.status.PLAYING,
|
||||||
|
'ai-audio-loading': buffering,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes}>
|
||||||
|
<div className="ai-control-wrap">
|
||||||
|
{displayActiveCover && (
|
||||||
|
<Cover
|
||||||
|
className="ai-thumb ai-control-wrap-thumb"
|
||||||
|
src={currentTrack.cover}
|
||||||
|
alt={currentTrack.title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="ai-control-wrap-controls">
|
||||||
|
<ProgressBar
|
||||||
|
setPosition={setPosition}
|
||||||
|
duration={duration}
|
||||||
|
position={position}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="ai-audio-controls-main">
|
||||||
|
<Button
|
||||||
|
onClick={togglePlay}
|
||||||
|
className={audioControlClasses}
|
||||||
|
ariaLabel={
|
||||||
|
playStatus === Sound.status.PLAYING
|
||||||
|
? sprintf(aiStrings.pause_title, currentTrack.title)
|
||||||
|
: sprintf(aiStrings.play_title, currentTrack.title)
|
||||||
|
}
|
||||||
|
ariaPressed={playStatus === Sound.status.PLAYING}
|
||||||
|
>
|
||||||
|
{playStatus === Sound.status.PLAYING ? (
|
||||||
|
<PauseIcon />
|
||||||
|
) : (
|
||||||
|
<PlayIcon />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<span className="ai-control-spinner" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<div className="ai-audio-controls-meta">
|
||||||
|
{tracks.length > 1 && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-tracklist-prev"
|
||||||
|
onClick={prevTrack}
|
||||||
|
ariaLabel={aiStrings.previous}
|
||||||
|
>
|
||||||
|
<PreviousIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tracks.length > 1 && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-tracklist-next"
|
||||||
|
onClick={nextTrack}
|
||||||
|
ariaLabel={aiStrings.next}
|
||||||
|
>
|
||||||
|
<NextIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<VolumeControl
|
||||||
|
volume={volume}
|
||||||
|
// eslint-disable-next-line no-shadow
|
||||||
|
setVolume={setVolume}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{allowTracklistLoop && (
|
||||||
|
<Button
|
||||||
|
className={`ai-btn ai-btn-repeat ${cycleTracks &&
|
||||||
|
'ai-btn-active'}`}
|
||||||
|
onClick={toggleTracklistCycling}
|
||||||
|
ariaLabel={aiStrings.toggle_list_repeat}
|
||||||
|
>
|
||||||
|
<RefreshIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{allowPlaybackRate && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-btn-playback-rate"
|
||||||
|
onClick={setPlaybackRate}
|
||||||
|
ariaLabel={aiStrings.set_playback_rate}
|
||||||
|
>
|
||||||
|
<Fragment>×{playbackRate}</Fragment>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{skipAmount > 0 && (
|
||||||
|
<Fragment>
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-btn-skip-position"
|
||||||
|
onClick={() => skipPosition(-1)}
|
||||||
|
ariaLabel={aiStrings.skip_backward}
|
||||||
|
>
|
||||||
|
-{skipAmount}s
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-btn-skip-position"
|
||||||
|
onClick={() => skipPosition(1)}
|
||||||
|
ariaLabel={aiStrings.skip_forward}
|
||||||
|
>
|
||||||
|
+{skipAmount}s
|
||||||
|
</Button>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{currentTrack && currentTrack.lyrics && !isTrackListOpen && (
|
||||||
|
<AppContext.Consumer>
|
||||||
|
{({ toggleLyricsModal }) => (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-lyrics"
|
||||||
|
onClick={() => toggleLyricsModal(true, currentTrack)}
|
||||||
|
ariaLabel={aiStrings.open_track_lyrics}
|
||||||
|
title={aiStrings.open_track_lyrics}
|
||||||
|
>
|
||||||
|
<LyricsIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</AppContext.Consumer>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ai-track-info">
|
||||||
|
<p className="ai-track-title">
|
||||||
|
<span>{currentTrack.title}</span>
|
||||||
|
</p>
|
||||||
|
{(tracks.length === 0 || currentTrack.subtitle) &&
|
||||||
|
displayArtistNames && (
|
||||||
|
<p className="ai-track-subtitle">
|
||||||
|
<span>{currentTrack.subtitle}</span>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ai-audio-controls-meta-right">
|
||||||
|
<Time
|
||||||
|
duration={duration}
|
||||||
|
position={position}
|
||||||
|
countdown={countdownTimerByDefault}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{allowTracklistToggle && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-tracklist-toggle"
|
||||||
|
onClick={toggleTracklist}
|
||||||
|
ariaLabel={aiStrings.toggle_list_visible}
|
||||||
|
>
|
||||||
|
<PlaylistIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`ai-tracklist-wrap ${
|
||||||
|
isTrackListOpen ? 'ai-tracklist-open' : ''
|
||||||
|
}`}
|
||||||
|
style={{ display: isTrackListOpen ? 'block' : 'none' }}
|
||||||
|
>
|
||||||
|
<TracklistWrap
|
||||||
|
className="ai-tracklist"
|
||||||
|
trackClassName="ai-track"
|
||||||
|
tracks={tracks}
|
||||||
|
activeTrackIndex={activeIndex}
|
||||||
|
isOpen={isTrackListOpen}
|
||||||
|
displayTrackNo={displayTrackNo}
|
||||||
|
displayCovers={displayTracklistCovers}
|
||||||
|
displayBuyButtons={displayBuyButtons}
|
||||||
|
buyButtonsTarget={buyButtonsTarget}
|
||||||
|
displayArtistNames={displayArtistNames}
|
||||||
|
reverseTrackOrder={reverseTrackOrder}
|
||||||
|
limitTracklistHeight={limitTracklistHeight}
|
||||||
|
tracklistHeight={tracklistHeight}
|
||||||
|
onTrackClick={playTrack}
|
||||||
|
onTrackLoop={allowTrackLoop ? setTrackCycling : undefined}
|
||||||
|
repeatingTrackIndex={repeatingTrackIndex}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{playerButtons?.length > 0 && <PlayerButtons buttons={playerButtons} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
GlobalFooterPlayer.propTypes = propTypes;
|
||||||
|
|
||||||
export default soundProvider(GlobalFooterPlayer, {
|
export default soundProvider(GlobalFooterPlayer, {
|
||||||
onFinishedPlaying(props) {
|
onFinishedPlaying(props) {
|
||||||
const {
|
const {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment, useState, useRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Sound from 'react-sound';
|
import Sound from 'react-sound';
|
||||||
import { sprintf } from 'sprintf-js';
|
import { sprintf } from 'sprintf-js';
|
||||||
@ -23,309 +23,10 @@ import {
|
|||||||
import soundProvider from './soundProvider';
|
import soundProvider from './soundProvider';
|
||||||
import { AppContext } from '../App';
|
import { AppContext } from '../App';
|
||||||
import typographyDisabled from '../utils/typography-disabled';
|
import typographyDisabled from '../utils/typography-disabled';
|
||||||
|
import useComponentSize from '../utils/useComponentSize';
|
||||||
|
import PlayerButtons from './components/PlayerButtons';
|
||||||
|
|
||||||
class Player extends React.Component {
|
const propTypes = {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isTrackListOpen: this.props.displayTracklist,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.toggleTracklist = this.toggleTracklist.bind(this);
|
|
||||||
this.isNarrowContext = this.isNarrowContext.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
isNarrowContext() {
|
|
||||||
return this.root && this.root.offsetWidth < 480 && window.innerWidth > 480;
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleTracklist() {
|
|
||||||
this.setState(state => ({
|
|
||||||
isTrackListOpen: !state.isTrackListOpen,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { isTrackListOpen } = this.state;
|
|
||||||
|
|
||||||
const {
|
|
||||||
tracks,
|
|
||||||
playStatus,
|
|
||||||
activeIndex,
|
|
||||||
volume,
|
|
||||||
position,
|
|
||||||
duration,
|
|
||||||
playbackRate,
|
|
||||||
shuffle,
|
|
||||||
shuffleEnabled,
|
|
||||||
|
|
||||||
currentTrack,
|
|
||||||
playTrack,
|
|
||||||
togglePlay,
|
|
||||||
nextTrack,
|
|
||||||
prevTrack,
|
|
||||||
setPosition,
|
|
||||||
setVolume,
|
|
||||||
setPlaybackRate,
|
|
||||||
toggleTracklistCycling,
|
|
||||||
cycleTracks,
|
|
||||||
toggleShuffle,
|
|
||||||
|
|
||||||
allowTracklistToggle,
|
|
||||||
allowTracklistLoop,
|
|
||||||
allowPlaybackRate,
|
|
||||||
allowTrackLoop,
|
|
||||||
setTrackCycling,
|
|
||||||
reverseTrackOrder,
|
|
||||||
displayTrackNo,
|
|
||||||
displayTracklistCovers,
|
|
||||||
displayActiveCover,
|
|
||||||
displayCredits,
|
|
||||||
limitTracklistHeight,
|
|
||||||
tracklistHeight,
|
|
||||||
displayBuyButtons,
|
|
||||||
buyButtonsTarget,
|
|
||||||
displayArtistNames,
|
|
||||||
maxWidth,
|
|
||||||
repeatingTrackIndex,
|
|
||||||
skipAmount,
|
|
||||||
skipPosition,
|
|
||||||
countdownTimerByDefault,
|
|
||||||
buffering,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const classes = classNames({
|
|
||||||
'ai-wrap': true,
|
|
||||||
'ai-type-full': true,
|
|
||||||
'ai-is-loading': !tracks.length,
|
|
||||||
'ai-narrow': this.isNarrowContext(),
|
|
||||||
'ai-with-typography': !typographyDisabled(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const audioControlClasses = classNames({
|
|
||||||
'ai-audio-control': true,
|
|
||||||
'ai-audio-playing': playStatus === Sound.status.PLAYING,
|
|
||||||
'ai-audio-loading': buffering,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={ref => (this.root = ref)} // eslint-disable-line no-return-assign
|
|
||||||
className={classes}
|
|
||||||
style={{ maxWidth }}
|
|
||||||
>
|
|
||||||
<div className="ai-control-wrap">
|
|
||||||
{displayActiveCover && (
|
|
||||||
<Cover
|
|
||||||
className="ai-thumb ai-control-wrap-thumb"
|
|
||||||
src={currentTrack.cover}
|
|
||||||
alt={currentTrack.title}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="ai-control-wrap-controls">
|
|
||||||
<div className="ai-audio-controls-main">
|
|
||||||
<Button
|
|
||||||
onClick={togglePlay}
|
|
||||||
className={audioControlClasses}
|
|
||||||
ariaLabel={
|
|
||||||
playStatus === Sound.status.PLAYING
|
|
||||||
? sprintf(aiStrings.pause_title, currentTrack.title)
|
|
||||||
: sprintf(aiStrings.play_title, currentTrack.title)
|
|
||||||
}
|
|
||||||
ariaPressed={playStatus === Sound.status.PLAYING}
|
|
||||||
>
|
|
||||||
{playStatus === Sound.status.PLAYING ? (
|
|
||||||
<PauseIcon />
|
|
||||||
) : (
|
|
||||||
<PlayIcon />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<span className="ai-control-spinner" />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<div className="ai-track-info">
|
|
||||||
<p className="ai-track-title">
|
|
||||||
<span>{currentTrack.title}</span>
|
|
||||||
</p>
|
|
||||||
{(tracks.length === 0 || currentTrack.subtitle) &&
|
|
||||||
displayArtistNames && (
|
|
||||||
<p className="ai-track-subtitle">
|
|
||||||
<span>{currentTrack.subtitle}</span>
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="ai-audio-controls-progress">
|
|
||||||
<ProgressBar
|
|
||||||
setPosition={setPosition}
|
|
||||||
duration={duration}
|
|
||||||
position={position}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Time
|
|
||||||
duration={duration}
|
|
||||||
position={position}
|
|
||||||
countdown={countdownTimerByDefault}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="ai-audio-controls-meta">
|
|
||||||
{tracks.length > 1 && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-tracklist-prev"
|
|
||||||
onClick={prevTrack}
|
|
||||||
ariaLabel={aiStrings.previous}
|
|
||||||
title={aiStrings.previous}
|
|
||||||
>
|
|
||||||
<PreviousIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{tracks.length > 1 && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-tracklist-next"
|
|
||||||
onClick={nextTrack}
|
|
||||||
ariaLabel={aiStrings.next}
|
|
||||||
title={aiStrings.next}
|
|
||||||
>
|
|
||||||
<NextIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<VolumeControl
|
|
||||||
volume={volume}
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
setVolume={setVolume}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{allowTracklistLoop && (
|
|
||||||
<Button
|
|
||||||
className={`ai-btn ai-btn-repeat ${cycleTracks &&
|
|
||||||
'ai-btn-active'}`}
|
|
||||||
onClick={toggleTracklistCycling}
|
|
||||||
ariaLabel={aiStrings.toggle_list_repeat}
|
|
||||||
>
|
|
||||||
<RefreshIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{shuffleEnabled && (
|
|
||||||
<Button
|
|
||||||
className={`ai-btn ai-btn-shuffle ${shuffle &&
|
|
||||||
'ai-btn-active'}`}
|
|
||||||
onClick={toggleShuffle}
|
|
||||||
ariaLabel={aiStrings.shuffle}
|
|
||||||
>
|
|
||||||
<ShuffleIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{allowPlaybackRate && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-btn-playback-rate"
|
|
||||||
onClick={setPlaybackRate}
|
|
||||||
ariaLabel={aiStrings.set_playback_rate}
|
|
||||||
>
|
|
||||||
<Fragment>×{playbackRate}</Fragment>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{skipAmount > 0 && (
|
|
||||||
<Fragment>
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-btn-skip-position"
|
|
||||||
onClick={() => skipPosition(-1)}
|
|
||||||
ariaLabel={aiStrings.skip_backward}
|
|
||||||
>
|
|
||||||
-{skipAmount}s
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-btn-skip-position"
|
|
||||||
onClick={() => skipPosition(1)}
|
|
||||||
ariaLabel={aiStrings.skip_forward}
|
|
||||||
>
|
|
||||||
+{skipAmount}s
|
|
||||||
</Button>
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{currentTrack && currentTrack.lyrics && !isTrackListOpen && (
|
|
||||||
<AppContext.Consumer>
|
|
||||||
{({ toggleLyricsModal }) => (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-lyrics"
|
|
||||||
onClick={() => toggleLyricsModal(true, currentTrack)}
|
|
||||||
ariaLabel={aiStrings.open_track_lyrics}
|
|
||||||
title={aiStrings.open_track_lyrics}
|
|
||||||
>
|
|
||||||
<LyricsIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</AppContext.Consumer>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{allowTracklistToggle && (
|
|
||||||
<Button
|
|
||||||
className="ai-btn ai-tracklist-toggle"
|
|
||||||
onClick={this.toggleTracklist}
|
|
||||||
ariaLabel={aiStrings.toggle_list_visible}
|
|
||||||
ariaExpanded={isTrackListOpen}
|
|
||||||
>
|
|
||||||
<PlaylistIcon />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`ai-tracklist-wrap ${
|
|
||||||
isTrackListOpen ? 'ai-tracklist-open' : ''
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<TracklistWrap
|
|
||||||
className="ai-tracklist"
|
|
||||||
trackClassName="ai-track"
|
|
||||||
tracks={tracks}
|
|
||||||
activeTrackIndex={activeIndex}
|
|
||||||
isOpen={isTrackListOpen}
|
|
||||||
displayTrackNo={displayTrackNo}
|
|
||||||
displayCovers={displayTracklistCovers}
|
|
||||||
displayBuyButtons={displayBuyButtons}
|
|
||||||
buyButtonsTarget={buyButtonsTarget}
|
|
||||||
displayArtistNames={displayArtistNames}
|
|
||||||
reverseTrackOrder={reverseTrackOrder}
|
|
||||||
limitTracklistHeight={limitTracklistHeight}
|
|
||||||
tracklistHeight={tracklistHeight}
|
|
||||||
onTrackClick={playTrack}
|
|
||||||
onTrackLoop={allowTrackLoop ? setTrackCycling : undefined}
|
|
||||||
repeatingTrackIndex={repeatingTrackIndex}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{displayCredits && (
|
|
||||||
<div className="ai-footer">
|
|
||||||
<p>
|
|
||||||
Powered by{' '}
|
|
||||||
<a
|
|
||||||
href="https://www.cssigniter.com/plugins/audioigniter?utm_source=player&utm_medium=link&utm_content=audioigniter&utm_campaign=footer-link"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
AudioIgniter
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Player.propTypes = {
|
|
||||||
tracks: PropTypes.arrayOf(PropTypes.object),
|
tracks: PropTypes.arrayOf(PropTypes.object),
|
||||||
playStatus: PropTypes.oneOf([
|
playStatus: PropTypes.oneOf([
|
||||||
Sound.status.PLAYING,
|
Sound.status.PLAYING,
|
||||||
@ -372,8 +73,303 @@ Player.propTypes = {
|
|||||||
shuffleEnabled: PropTypes.bool,
|
shuffleEnabled: PropTypes.bool,
|
||||||
shuffle: PropTypes.bool,
|
shuffle: PropTypes.bool,
|
||||||
toggleShuffle: PropTypes.func.isRequired,
|
toggleShuffle: PropTypes.func.isRequired,
|
||||||
|
playerButtons: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
title: PropTypes.string,
|
||||||
|
url: PropTypes.string,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Player = ({
|
||||||
|
tracks,
|
||||||
|
playStatus,
|
||||||
|
activeIndex,
|
||||||
|
volume,
|
||||||
|
position,
|
||||||
|
duration,
|
||||||
|
playbackRate,
|
||||||
|
shuffle,
|
||||||
|
shuffleEnabled,
|
||||||
|
|
||||||
|
currentTrack,
|
||||||
|
playTrack,
|
||||||
|
togglePlay,
|
||||||
|
nextTrack,
|
||||||
|
prevTrack,
|
||||||
|
setPosition,
|
||||||
|
setVolume,
|
||||||
|
setPlaybackRate,
|
||||||
|
toggleTracklistCycling,
|
||||||
|
cycleTracks,
|
||||||
|
toggleShuffle,
|
||||||
|
|
||||||
|
allowTracklistToggle,
|
||||||
|
allowTracklistLoop,
|
||||||
|
allowPlaybackRate,
|
||||||
|
allowTrackLoop,
|
||||||
|
setTrackCycling,
|
||||||
|
reverseTrackOrder,
|
||||||
|
displayTrackNo,
|
||||||
|
displayTracklist,
|
||||||
|
displayTracklistCovers,
|
||||||
|
displayActiveCover,
|
||||||
|
displayCredits,
|
||||||
|
limitTracklistHeight,
|
||||||
|
tracklistHeight,
|
||||||
|
displayBuyButtons,
|
||||||
|
buyButtonsTarget,
|
||||||
|
displayArtistNames,
|
||||||
|
maxWidth,
|
||||||
|
repeatingTrackIndex,
|
||||||
|
skipAmount,
|
||||||
|
skipPosition,
|
||||||
|
countdownTimerByDefault,
|
||||||
|
buffering,
|
||||||
|
playerButtons,
|
||||||
|
}) => {
|
||||||
|
const ref = useRef(null);
|
||||||
|
const [isTrackListOpen, setTracklistOpen] = useState(displayTracklist);
|
||||||
|
const { width } = useComponentSize(ref);
|
||||||
|
|
||||||
|
const isNarrowContext = () => {
|
||||||
|
return width != null && width < 480 && window.innerWidth > 480;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleTracklist = () => {
|
||||||
|
setTracklistOpen(x => !x);
|
||||||
|
};
|
||||||
|
|
||||||
|
const classes = classNames({
|
||||||
|
'ai-wrap': true,
|
||||||
|
'ai-type-full': true,
|
||||||
|
'ai-is-loading': !tracks.length,
|
||||||
|
'ai-narrow': isNarrowContext(),
|
||||||
|
'ai-with-typography': !typographyDisabled(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const audioControlClasses = classNames({
|
||||||
|
'ai-audio-control': true,
|
||||||
|
'ai-audio-playing': playStatus === Sound.status.PLAYING,
|
||||||
|
'ai-audio-loading': buffering,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ref} className={classes} style={{ maxWidth }}>
|
||||||
|
<div className="ai-control-wrap">
|
||||||
|
{displayActiveCover && (
|
||||||
|
<Cover
|
||||||
|
className="ai-thumb ai-control-wrap-thumb"
|
||||||
|
src={currentTrack.cover}
|
||||||
|
alt={currentTrack.title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="ai-control-wrap-controls">
|
||||||
|
<div className="ai-audio-controls-main">
|
||||||
|
<Button
|
||||||
|
onClick={togglePlay}
|
||||||
|
className={audioControlClasses}
|
||||||
|
ariaLabel={
|
||||||
|
playStatus === Sound.status.PLAYING
|
||||||
|
? sprintf(aiStrings.pause_title, currentTrack.title)
|
||||||
|
: sprintf(aiStrings.play_title, currentTrack.title)
|
||||||
|
}
|
||||||
|
ariaPressed={playStatus === Sound.status.PLAYING}
|
||||||
|
>
|
||||||
|
{playStatus === Sound.status.PLAYING ? (
|
||||||
|
<PauseIcon />
|
||||||
|
) : (
|
||||||
|
<PlayIcon />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<span className="ai-control-spinner" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<div className="ai-track-info">
|
||||||
|
<p className="ai-track-title">
|
||||||
|
<span>{currentTrack.title}</span>
|
||||||
|
</p>
|
||||||
|
{(tracks.length === 0 || currentTrack.subtitle) &&
|
||||||
|
displayArtistNames && (
|
||||||
|
<p className="ai-track-subtitle">
|
||||||
|
<span>{currentTrack.subtitle}</span>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ai-audio-controls-progress">
|
||||||
|
<ProgressBar
|
||||||
|
setPosition={setPosition}
|
||||||
|
duration={duration}
|
||||||
|
position={position}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Time
|
||||||
|
duration={duration}
|
||||||
|
position={position}
|
||||||
|
countdown={countdownTimerByDefault}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ai-audio-controls-meta">
|
||||||
|
{tracks.length > 1 && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-tracklist-prev"
|
||||||
|
onClick={prevTrack}
|
||||||
|
ariaLabel={aiStrings.previous}
|
||||||
|
title={aiStrings.previous}
|
||||||
|
>
|
||||||
|
<PreviousIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tracks.length > 1 && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-tracklist-next"
|
||||||
|
onClick={nextTrack}
|
||||||
|
ariaLabel={aiStrings.next}
|
||||||
|
title={aiStrings.next}
|
||||||
|
>
|
||||||
|
<NextIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<VolumeControl
|
||||||
|
volume={volume}
|
||||||
|
// eslint-disable-next-line no-shadow
|
||||||
|
setVolume={setVolume}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{allowTracklistLoop && (
|
||||||
|
<Button
|
||||||
|
className={`ai-btn ai-btn-repeat ${cycleTracks &&
|
||||||
|
'ai-btn-active'}`}
|
||||||
|
onClick={toggleTracklistCycling}
|
||||||
|
ariaLabel={aiStrings.toggle_list_repeat}
|
||||||
|
>
|
||||||
|
<RefreshIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{shuffleEnabled && (
|
||||||
|
<Button
|
||||||
|
className={`ai-btn ai-btn-shuffle ${shuffle &&
|
||||||
|
'ai-btn-active'}`}
|
||||||
|
onClick={toggleShuffle}
|
||||||
|
ariaLabel={aiStrings.shuffle}
|
||||||
|
>
|
||||||
|
<ShuffleIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{allowPlaybackRate && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-btn-playback-rate"
|
||||||
|
onClick={setPlaybackRate}
|
||||||
|
ariaLabel={aiStrings.set_playback_rate}
|
||||||
|
>
|
||||||
|
<Fragment>×{playbackRate}</Fragment>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{skipAmount > 0 && (
|
||||||
|
<Fragment>
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-btn-skip-position"
|
||||||
|
onClick={() => skipPosition(-1)}
|
||||||
|
ariaLabel={aiStrings.skip_backward}
|
||||||
|
>
|
||||||
|
-{skipAmount}s
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-btn-skip-position"
|
||||||
|
onClick={() => skipPosition(1)}
|
||||||
|
ariaLabel={aiStrings.skip_forward}
|
||||||
|
>
|
||||||
|
+{skipAmount}s
|
||||||
|
</Button>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{currentTrack && currentTrack.lyrics && !isTrackListOpen && (
|
||||||
|
<AppContext.Consumer>
|
||||||
|
{({ toggleLyricsModal }) => (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-lyrics"
|
||||||
|
onClick={() => toggleLyricsModal(true, currentTrack)}
|
||||||
|
ariaLabel={aiStrings.open_track_lyrics}
|
||||||
|
title={aiStrings.open_track_lyrics}
|
||||||
|
>
|
||||||
|
<LyricsIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</AppContext.Consumer>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{allowTracklistToggle && (
|
||||||
|
<Button
|
||||||
|
className="ai-btn ai-tracklist-toggle"
|
||||||
|
onClick={toggleTracklist}
|
||||||
|
ariaLabel={aiStrings.toggle_list_visible}
|
||||||
|
ariaExpanded={isTrackListOpen}
|
||||||
|
>
|
||||||
|
<PlaylistIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`ai-tracklist-wrap ${
|
||||||
|
isTrackListOpen ? 'ai-tracklist-open' : ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<TracklistWrap
|
||||||
|
className="ai-tracklist"
|
||||||
|
trackClassName="ai-track"
|
||||||
|
tracks={tracks}
|
||||||
|
activeTrackIndex={activeIndex}
|
||||||
|
isOpen={isTrackListOpen}
|
||||||
|
displayTrackNo={displayTrackNo}
|
||||||
|
displayCovers={displayTracklistCovers}
|
||||||
|
displayBuyButtons={displayBuyButtons}
|
||||||
|
buyButtonsTarget={buyButtonsTarget}
|
||||||
|
displayArtistNames={displayArtistNames}
|
||||||
|
reverseTrackOrder={reverseTrackOrder}
|
||||||
|
limitTracklistHeight={limitTracklistHeight}
|
||||||
|
tracklistHeight={tracklistHeight}
|
||||||
|
onTrackClick={playTrack}
|
||||||
|
onTrackLoop={allowTrackLoop ? setTrackCycling : undefined}
|
||||||
|
repeatingTrackIndex={repeatingTrackIndex}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{playerButtons?.length > 0 && <PlayerButtons buttons={playerButtons} />}
|
||||||
|
|
||||||
|
{displayCredits && (
|
||||||
|
<div className="ai-footer">
|
||||||
|
<p>
|
||||||
|
Powered by{' '}
|
||||||
|
<a
|
||||||
|
href="https://www.cssigniter.com/plugins/audioigniter?utm_source=player&utm_medium=link&utm_content=audioigniter&utm_campaign=footer-link"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
AudioIgniter
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.propTypes = propTypes;
|
||||||
|
|
||||||
export default soundProvider(Player, {
|
export default soundProvider(Player, {
|
||||||
onFinishedPlaying(props) {
|
onFinishedPlaying(props) {
|
||||||
const {
|
const {
|
||||||
|
@ -6,6 +6,43 @@ import classNames from 'classnames';
|
|||||||
import soundProvider from './soundProvider';
|
import soundProvider from './soundProvider';
|
||||||
import Tracklist from './components/Tracklist';
|
import Tracklist from './components/Tracklist';
|
||||||
import typographyDisabled from '../utils/typography-disabled';
|
import typographyDisabled from '../utils/typography-disabled';
|
||||||
|
import PlayerButtons from './components/PlayerButtons';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
tracks: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
playStatus: PropTypes.oneOf([
|
||||||
|
Sound.status.PLAYING,
|
||||||
|
Sound.status.PAUSED,
|
||||||
|
Sound.status.STOPPED,
|
||||||
|
]),
|
||||||
|
activeIndex: PropTypes.number,
|
||||||
|
position: PropTypes.number,
|
||||||
|
duration: PropTypes.number,
|
||||||
|
setPosition: PropTypes.func.isRequired,
|
||||||
|
togglePlay: PropTypes.func.isRequired,
|
||||||
|
setTrackCycling: PropTypes.func.isRequired,
|
||||||
|
allowTrackLoop: PropTypes.bool,
|
||||||
|
|
||||||
|
maxWidth: PropTypes.string,
|
||||||
|
reverseTrackOrder: PropTypes.bool,
|
||||||
|
displayTrackNo: PropTypes.bool,
|
||||||
|
buyButtonsTarget: PropTypes.bool,
|
||||||
|
displayArtistNames: PropTypes.bool,
|
||||||
|
displayBuyButtons: PropTypes.bool,
|
||||||
|
displayCredits: PropTypes.bool,
|
||||||
|
repeatingTrackIndex: PropTypes.number,
|
||||||
|
playbackRate: PropTypes.number,
|
||||||
|
setPlaybackRate: PropTypes.func,
|
||||||
|
allowPlaybackRate: PropTypes.bool,
|
||||||
|
buffering: PropTypes.bool,
|
||||||
|
playerButtons: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
title: PropTypes.string,
|
||||||
|
url: PropTypes.string,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
const SimplePlayer = props => {
|
const SimplePlayer = props => {
|
||||||
const { playStatus } = props;
|
const { playStatus } = props;
|
||||||
@ -48,6 +85,10 @@ const SimplePlayer = props => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{props.playerButtons?.length > 0 && (
|
||||||
|
<PlayerButtons buttons={props.playerButtons} />
|
||||||
|
)}
|
||||||
|
|
||||||
{props.displayCredits && (
|
{props.displayCredits && (
|
||||||
<div className="ai-footer">
|
<div className="ai-footer">
|
||||||
<p>
|
<p>
|
||||||
@ -66,34 +107,7 @@ const SimplePlayer = props => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
SimplePlayer.propTypes = {
|
SimplePlayer.propTypes = propTypes;
|
||||||
tracks: PropTypes.arrayOf(PropTypes.object),
|
|
||||||
playStatus: PropTypes.oneOf([
|
|
||||||
Sound.status.PLAYING,
|
|
||||||
Sound.status.PAUSED,
|
|
||||||
Sound.status.STOPPED,
|
|
||||||
]),
|
|
||||||
activeIndex: PropTypes.number,
|
|
||||||
position: PropTypes.number,
|
|
||||||
duration: PropTypes.number,
|
|
||||||
setPosition: PropTypes.func.isRequired,
|
|
||||||
togglePlay: PropTypes.func.isRequired,
|
|
||||||
setTrackCycling: PropTypes.func.isRequired,
|
|
||||||
allowTrackLoop: PropTypes.bool,
|
|
||||||
|
|
||||||
maxWidth: PropTypes.string,
|
|
||||||
reverseTrackOrder: PropTypes.bool,
|
|
||||||
displayTrackNo: PropTypes.bool,
|
|
||||||
buyButtonsTarget: PropTypes.bool,
|
|
||||||
displayArtistNames: PropTypes.bool,
|
|
||||||
displayBuyButtons: PropTypes.bool,
|
|
||||||
displayCredits: PropTypes.bool,
|
|
||||||
repeatingTrackIndex: PropTypes.number,
|
|
||||||
playbackRate: PropTypes.number,
|
|
||||||
setPlaybackRate: PropTypes.func,
|
|
||||||
allowPlaybackRate: PropTypes.bool,
|
|
||||||
buffering: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default soundProvider(SimplePlayer, {
|
export default soundProvider(SimplePlayer, {
|
||||||
onFinishedPlaying(props) {
|
onFinishedPlaying(props) {
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
children: PropTypes.node,
|
||||||
|
ariaLabel: PropTypes.string,
|
||||||
|
ariaPressed: PropTypes.bool,
|
||||||
|
ariaExpanded: PropTypes.bool,
|
||||||
|
ariaControls: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
const Button = ({
|
const Button = ({
|
||||||
className,
|
className,
|
||||||
onClick,
|
onClick,
|
||||||
@ -22,14 +32,6 @@ const Button = ({
|
|||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.propTypes = {
|
Button.propTypes = propTypes;
|
||||||
className: PropTypes.string,
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
children: PropTypes.node,
|
|
||||||
ariaLabel: PropTypes.string,
|
|
||||||
ariaPressed: PropTypes.bool,
|
|
||||||
ariaExpanded: PropTypes.bool,
|
|
||||||
ariaControls: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Button;
|
export default Button;
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { MusicNoteIcon } from './Icons';
|
import { MusicNoteIcon } from './Icons';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
title: PropTypes.string,
|
||||||
|
src: PropTypes.string,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
const Cover = ({ className, title, src, onClick }) => (
|
const Cover = ({ className, title, src, onClick }) => (
|
||||||
<div
|
<div
|
||||||
className={className + (src ? '' : ' ai-track-no-thumb')}
|
className={className + (src ? '' : ' ai-track-no-thumb')}
|
||||||
@ -11,11 +19,6 @@ const Cover = ({ className, title, src, onClick }) => (
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
Cover.propTypes = {
|
Cover.propTypes = propTypes;
|
||||||
className: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
src: PropTypes.string,
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Cover;
|
export default Cover;
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
button: PropTypes.shape({
|
||||||
|
title: PropTypes.string,
|
||||||
|
url: PropTypes.string,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlayerButton = ({ className, button }) => {
|
||||||
|
const classes = classNames({
|
||||||
|
'ai-btn': true,
|
||||||
|
'ai-player-button': true,
|
||||||
|
'ai-player-button-icon-only': !button.title,
|
||||||
|
[className]: !!className,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href={button.url}
|
||||||
|
className={classes}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{button.icon && (
|
||||||
|
<span
|
||||||
|
className="ai-player-button-icon"
|
||||||
|
dangerouslySetInnerHTML={{ __html: button.icon }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{button.title && (
|
||||||
|
<span className="ai-player-button-title">{button.title}</span>
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
PlayerButton.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default PlayerButton;
|
@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import PlayerButton from './PlayerButton';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
buttons: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
title: PropTypes.string,
|
||||||
|
url: PropTypes.string,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlayerButtons = ({ className, buttons }) => {
|
||||||
|
const classes = classNames({
|
||||||
|
'ai-player-buttons': true,
|
||||||
|
[className]: !!className,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes}>
|
||||||
|
{buttons.map((button, index) => {
|
||||||
|
return <PlayerButton key={index} button={button} />;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
PlayerButtons.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default PlayerButtons;
|
@ -1,15 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class ProgressBar extends React.Component {
|
const propTypes = {
|
||||||
constructor() {
|
setPosition: PropTypes.func,
|
||||||
super();
|
position: PropTypes.number.isRequired,
|
||||||
this.handleClick = this.handleClick.bind(this);
|
duration: PropTypes.number.isRequired,
|
||||||
}
|
};
|
||||||
|
|
||||||
handleClick(event) {
|
|
||||||
const { duration, setPosition } = this.props;
|
|
||||||
|
|
||||||
|
const ProgressBar = ({ position, duration, setPosition }) => {
|
||||||
|
const handleClick = event => {
|
||||||
if (setPosition == null) {
|
if (setPosition == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -19,24 +18,18 @@ export default class ProgressBar extends React.Component {
|
|||||||
const posX = offsetX / event.currentTarget.offsetWidth;
|
const posX = offsetX / event.currentTarget.offsetWidth;
|
||||||
|
|
||||||
setPosition(posX * duration);
|
setPosition(posX * duration);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { position, duration } = this.props;
|
<span onClick={handleClick} className="ai-track-progress-bar">
|
||||||
|
<span
|
||||||
return (
|
className="ai-track-progress"
|
||||||
<span onClick={this.handleClick} className="ai-track-progress-bar">
|
style={{ width: `${(position * 100) / duration}%` }}
|
||||||
<span
|
/>
|
||||||
className="ai-track-progress"
|
</span>
|
||||||
style={{ width: `${(position * 100) / duration}%` }}
|
);
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgressBar.propTypes = {
|
|
||||||
setPosition: PropTypes.func,
|
|
||||||
position: PropTypes.number.isRequired,
|
|
||||||
duration: PropTypes.number.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ProgressBar.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default ProgressBar;
|
||||||
|
@ -1,28 +1,21 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class Time extends React.Component {
|
const propTypes = {
|
||||||
constructor(props) {
|
position: PropTypes.number.isRequired,
|
||||||
super(props);
|
duration: PropTypes.number.isRequired,
|
||||||
|
countdown: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
const { countdown } = this.props;
|
const Time = ({ countdown, position, duration }) => {
|
||||||
|
const [showRemaining, setShowRemaining] = useState(countdown || false);
|
||||||
this.state = {
|
|
||||||
showRemaining: countdown || false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleClick = this.handleClick.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pretty prints time remaining/elapsed
|
* Pretty prints time remaining/elapsed
|
||||||
*
|
*
|
||||||
* @param {number} position - Track position in milliseconds
|
|
||||||
* @param {number} duration - Track duration in milliseconds
|
|
||||||
* @returns {string} - Time pretty formatted
|
* @returns {string} - Time pretty formatted
|
||||||
*/
|
*/
|
||||||
formatTime(position, duration) {
|
const renderFormattedTime = () => {
|
||||||
const { showRemaining } = this.state;
|
|
||||||
const positionInSeconds = showRemaining
|
const positionInSeconds = showRemaining
|
||||||
? (duration - position) / 1000
|
? (duration - position) / 1000
|
||||||
: position / 1000;
|
: position / 1000;
|
||||||
@ -34,7 +27,7 @@ export default class Time extends React.Component {
|
|||||||
min = min >= 10 ? min : `0${min}`;
|
min = min >= 10 ? min : `0${min}`;
|
||||||
sec = sec >= 10 ? sec : `0${sec}`;
|
sec = sec >= 10 ? sec : `0${sec}`;
|
||||||
|
|
||||||
if (!isNaN(sec)) {
|
if (!Number.isNaN(sec)) {
|
||||||
if (hours) {
|
if (hours) {
|
||||||
time = `${hours}:${min}:${sec}`;
|
time = `${hours}:${min}:${sec}`;
|
||||||
} else {
|
} else {
|
||||||
@ -43,26 +36,19 @@ export default class Time extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return showRemaining ? `-${time}` : time;
|
return showRemaining ? `-${time}` : time;
|
||||||
}
|
};
|
||||||
|
|
||||||
handleClick() {
|
const handleClick = () => {
|
||||||
const { showRemaining } = this.state;
|
setShowRemaining(x => !x);
|
||||||
this.setState({ showRemaining: !showRemaining });
|
};
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { position, duration } = this.props;
|
<span className="ai-track-time" onClick={handleClick}>
|
||||||
|
{renderFormattedTime()}
|
||||||
return (
|
</span>
|
||||||
<span className="ai-track-time" onClick={this.handleClick}>
|
);
|
||||||
{this.formatTime(position, duration)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Time.propTypes = {
|
|
||||||
position: PropTypes.number.isRequired,
|
|
||||||
duration: PropTypes.number.isRequired,
|
|
||||||
countdown: PropTypes.bool.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Time.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default Time;
|
||||||
|
@ -11,6 +11,43 @@ import ProgressBar from './ProgressBar';
|
|||||||
import { PlayIcon, PauseIcon } from './Icons';
|
import { PlayIcon, PauseIcon } from './Icons';
|
||||||
import { AppContext } from '../../App';
|
import { AppContext } from '../../App';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
track: PropTypes.shape({
|
||||||
|
audio: PropTypes.string,
|
||||||
|
buyUrl: PropTypes.string,
|
||||||
|
cover: PropTypes.string,
|
||||||
|
title: PropTypes.string,
|
||||||
|
subtitle: PropTypes.string,
|
||||||
|
lyrics: PropTypes.string,
|
||||||
|
downloadUrl: PropTypes.string,
|
||||||
|
downloadFilename: PropTypes.string,
|
||||||
|
}),
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
trackNo: PropTypes.number,
|
||||||
|
isActive: PropTypes.bool,
|
||||||
|
position: PropTypes.number,
|
||||||
|
duration: PropTypes.number,
|
||||||
|
setPosition: PropTypes.func,
|
||||||
|
playStatus: PropTypes.oneOf([
|
||||||
|
Sound.status.PLAYING,
|
||||||
|
Sound.status.PAUSED,
|
||||||
|
Sound.status.STOPPED,
|
||||||
|
]),
|
||||||
|
onTrackClick: PropTypes.func.isRequired,
|
||||||
|
onTrackLoop: PropTypes.func,
|
||||||
|
className: PropTypes.string.isRequired,
|
||||||
|
isStandalone: PropTypes.bool,
|
||||||
|
buyButtonsTarget: PropTypes.bool,
|
||||||
|
displayArtistNames: PropTypes.bool,
|
||||||
|
displayCovers: PropTypes.bool,
|
||||||
|
displayBuyButtons: PropTypes.bool,
|
||||||
|
isLooping: PropTypes.bool,
|
||||||
|
playbackRate: PropTypes.number,
|
||||||
|
setPlaybackRate: PropTypes.func,
|
||||||
|
allowPlaybackRate: PropTypes.bool,
|
||||||
|
buffering: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
const Track = ({
|
const Track = ({
|
||||||
track,
|
track,
|
||||||
index,
|
index,
|
||||||
@ -114,40 +151,6 @@ const Track = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Track.propTypes = {
|
Track.propTypes = propTypes;
|
||||||
track: PropTypes.shape({
|
|
||||||
audio: PropTypes.string,
|
|
||||||
buyUrl: PropTypes.string,
|
|
||||||
cover: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
subtitle: PropTypes.string,
|
|
||||||
lyrics: PropTypes.string,
|
|
||||||
downloadUrl: PropTypes.string,
|
|
||||||
}),
|
|
||||||
index: PropTypes.number.isRequired,
|
|
||||||
trackNo: PropTypes.number,
|
|
||||||
isActive: PropTypes.bool,
|
|
||||||
position: PropTypes.number,
|
|
||||||
duration: PropTypes.number,
|
|
||||||
setPosition: PropTypes.func,
|
|
||||||
playStatus: PropTypes.oneOf([
|
|
||||||
Sound.status.PLAYING,
|
|
||||||
Sound.status.PAUSED,
|
|
||||||
Sound.status.STOPPED,
|
|
||||||
]),
|
|
||||||
onTrackClick: PropTypes.func.isRequired,
|
|
||||||
onTrackLoop: PropTypes.func,
|
|
||||||
className: PropTypes.string.isRequired,
|
|
||||||
isStandalone: PropTypes.bool,
|
|
||||||
buyButtonsTarget: PropTypes.bool,
|
|
||||||
displayArtistNames: PropTypes.bool,
|
|
||||||
displayCovers: PropTypes.bool,
|
|
||||||
displayBuyButtons: PropTypes.bool,
|
|
||||||
isLooping: PropTypes.bool,
|
|
||||||
playbackRate: PropTypes.number,
|
|
||||||
setPlaybackRate: PropTypes.func,
|
|
||||||
allowPlaybackRate: PropTypes.bool,
|
|
||||||
buffering: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Track;
|
export default Track;
|
||||||
|
@ -1,7 +1,23 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { CartIcon, DownloadIcon, LyricsIcon, RefreshIcon } from './Icons';
|
import { CartIcon, DownloadIcon, LyricsIcon, RefreshIcon } from './Icons';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
buyButtonsTarget: PropTypes.bool,
|
||||||
|
buyUrl: PropTypes.string,
|
||||||
|
downloadUrl: PropTypes.string,
|
||||||
|
downloadFilename: PropTypes.string,
|
||||||
|
onTrackLoop: PropTypes.func,
|
||||||
|
isLooping: PropTypes.bool,
|
||||||
|
displayBuyButtons: PropTypes.bool,
|
||||||
|
onOpenTrackLyrics: PropTypes.func,
|
||||||
|
playbackRate: PropTypes.number,
|
||||||
|
setPlaybackRate: PropTypes.func,
|
||||||
|
allowPlaybackRate: PropTypes.bool,
|
||||||
|
isPlaying: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
const TrackButtons = ({
|
const TrackButtons = ({
|
||||||
buyButtonsTarget,
|
buyButtonsTarget,
|
||||||
buyUrl,
|
buyUrl,
|
||||||
@ -28,6 +44,7 @@ const TrackButtons = ({
|
|||||||
return (
|
return (
|
||||||
<div className="ai-track-control-buttons">
|
<div className="ai-track-control-buttons">
|
||||||
{buyUrl && displayBuyButtons && (
|
{buyUrl && displayBuyButtons && (
|
||||||
|
// eslint-disable-next-line react/jsx-no-target-blank
|
||||||
<a
|
<a
|
||||||
href={buyUrl}
|
href={buyUrl}
|
||||||
className="ai-track-btn"
|
className="ai-track-btn"
|
||||||
@ -83,7 +100,7 @@ const TrackButtons = ({
|
|||||||
setPlaybackRate();
|
setPlaybackRate();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Fragment>×{playbackRate}</Fragment>
|
×{playbackRate}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -113,19 +130,6 @@ const TrackButtons = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
TrackButtons.propTypes = {
|
TrackButtons.propTypes = propTypes;
|
||||||
buyButtonsTarget: PropTypes.bool,
|
|
||||||
buyUrl: PropTypes.string,
|
|
||||||
downloadUrl: PropTypes.string,
|
|
||||||
downloadFilename: PropTypes.string,
|
|
||||||
onTrackLoop: PropTypes.func,
|
|
||||||
isLooping: PropTypes.bool,
|
|
||||||
displayBuyButtons: PropTypes.bool,
|
|
||||||
onOpenTrackLyrics: PropTypes.func,
|
|
||||||
playbackRate: PropTypes.number,
|
|
||||||
setPlaybackRate: PropTypes.func,
|
|
||||||
allowPlaybackRate: PropTypes.bool,
|
|
||||||
isPlaying: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TrackButtons;
|
export default TrackButtons;
|
||||||
|
@ -6,6 +6,12 @@ if (document.querySelector('.audioigniter-root')) {
|
|||||||
Modal.setAppElement('.audioigniter-root');
|
Modal.setAppElement('.audioigniter-root');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
isOpen: PropTypes.bool,
|
||||||
|
closeModal: PropTypes.func.isRequired,
|
||||||
|
children: PropTypes.any,
|
||||||
|
};
|
||||||
|
|
||||||
const TrackLyricsModal = ({ isOpen, closeModal, children }) => {
|
const TrackLyricsModal = ({ isOpen, closeModal, children }) => {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -32,12 +38,6 @@ const TrackLyricsModal = ({ isOpen, closeModal, children }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
isOpen: PropTypes.bool,
|
|
||||||
closeModal: PropTypes.func.isRequired,
|
|
||||||
children: PropTypes.any,
|
|
||||||
};
|
|
||||||
|
|
||||||
TrackLyricsModal.propTypes = propTypes;
|
TrackLyricsModal.propTypes = propTypes;
|
||||||
|
|
||||||
export default TrackLyricsModal;
|
export default TrackLyricsModal;
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
track: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||||
|
trackNo: PropTypes.number,
|
||||||
|
style: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||||
|
className: PropTypes.string,
|
||||||
|
displayArtistNames: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
const TrackTitle = ({
|
const TrackTitle = ({
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
@ -25,12 +33,6 @@ const TrackTitle = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
TrackTitle.propTypes = {
|
TrackTitle.propTypes = propTypes;
|
||||||
track: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
|
||||||
trackNo: PropTypes.number,
|
|
||||||
style: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
|
||||||
className: PropTypes.string,
|
|
||||||
displayArtistNames: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TrackTitle;
|
export default TrackTitle;
|
||||||
|
@ -1,13 +1,43 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Sound from 'react-sound';
|
import Sound from 'react-sound';
|
||||||
|
|
||||||
import Track from './Track';
|
import Track from './Track';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
tracks: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
playStatus: PropTypes.oneOf([
|
||||||
|
Sound.status.PLAYING,
|
||||||
|
Sound.status.PAUSED,
|
||||||
|
Sound.status.STOPPED,
|
||||||
|
]),
|
||||||
|
activeTrackIndex: PropTypes.number,
|
||||||
|
position: PropTypes.number,
|
||||||
|
duration: PropTypes.number,
|
||||||
|
setPosition: PropTypes.func,
|
||||||
|
standaloneTracks: PropTypes.bool,
|
||||||
|
onTrackClick: PropTypes.func.isRequired,
|
||||||
|
onTrackLoop: PropTypes.func,
|
||||||
|
className: PropTypes.string,
|
||||||
|
trackClassName: PropTypes.string,
|
||||||
|
reverseTrackOrder: PropTypes.bool,
|
||||||
|
displayTrackNo: PropTypes.bool,
|
||||||
|
displayBuyButtons: PropTypes.bool,
|
||||||
|
buyButtonsTarget: PropTypes.bool,
|
||||||
|
displayCovers: PropTypes.bool,
|
||||||
|
displayArtistNames: PropTypes.bool,
|
||||||
|
playbackRate: PropTypes.number,
|
||||||
|
setPlaybackRate: PropTypes.func,
|
||||||
|
allowPlaybackRate: PropTypes.bool,
|
||||||
|
buffering: PropTypes.bool,
|
||||||
|
repeatingTrackIndex: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
const Tracklist = ({ ...props }) => {
|
const Tracklist = ({ ...props }) => {
|
||||||
const { tracks } = props;
|
const { tracks } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className={props.className} aria-expanded="true">
|
<ul className={props.className}>
|
||||||
{tracks &&
|
{tracks &&
|
||||||
tracks.map((track, index) => {
|
tracks.map((track, index) => {
|
||||||
const trackNo = props.reverseTrackOrder
|
const trackNo = props.reverseTrackOrder
|
||||||
@ -46,32 +76,6 @@ const Tracklist = ({ ...props }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Tracklist.propTypes = {
|
Tracklist.propTypes = propTypes;
|
||||||
tracks: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
playStatus: PropTypes.oneOf([
|
|
||||||
Sound.status.PLAYING,
|
|
||||||
Sound.status.PAUSED,
|
|
||||||
Sound.status.STOPPED,
|
|
||||||
]),
|
|
||||||
activeTrackIndex: PropTypes.number,
|
|
||||||
position: PropTypes.number,
|
|
||||||
duration: PropTypes.number,
|
|
||||||
setPosition: PropTypes.func,
|
|
||||||
standaloneTracks: PropTypes.bool,
|
|
||||||
onTrackClick: PropTypes.func.isRequired,
|
|
||||||
onTrackLoop: PropTypes.func,
|
|
||||||
className: PropTypes.string,
|
|
||||||
trackClassName: PropTypes.string,
|
|
||||||
reverseTrackOrder: PropTypes.bool,
|
|
||||||
displayTrackNo: PropTypes.bool,
|
|
||||||
displayBuyButtons: PropTypes.bool,
|
|
||||||
buyButtonsTarget: PropTypes.bool,
|
|
||||||
displayCovers: PropTypes.bool,
|
|
||||||
displayArtistNames: PropTypes.bool,
|
|
||||||
playbackRate: PropTypes.number,
|
|
||||||
setPlaybackRate: PropTypes.func,
|
|
||||||
allowPlaybackRate: PropTypes.bool,
|
|
||||||
buffering: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Tracklist;
|
export default Tracklist;
|
||||||
|
@ -1,81 +1,10 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Scrollbars } from 'react-custom-scrollbars';
|
import { Scrollbars } from 'react-custom-scrollbars';
|
||||||
|
|
||||||
import Tracklist from './Tracklist';
|
import Tracklist from './Tracklist';
|
||||||
|
|
||||||
export default class TracklistWrap extends React.Component {
|
const propTypes = {
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
const { activeTrackIndex, limitTracklistHeight } = this.props;
|
|
||||||
|
|
||||||
if (
|
|
||||||
activeTrackIndex !== nextProps.activeTrackIndex &&
|
|
||||||
limitTracklistHeight
|
|
||||||
) {
|
|
||||||
this.scrollToTrack(nextProps.activeTrackIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollToTrack(trackIndex) {
|
|
||||||
const { tracks } = this.props;
|
|
||||||
const trackHeight = this.scrollbarsRef.getScrollHeight() / tracks.length;
|
|
||||||
|
|
||||||
if (!this.isTrackVisible(trackIndex)) {
|
|
||||||
this.scrollbarsRef.scrollTop(trackHeight * trackIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isTrackVisible(trackIndex) {
|
|
||||||
const { tracks } = this.props;
|
|
||||||
const trackHeight = this.scrollbarsRef.getScrollHeight() / tracks.length;
|
|
||||||
const trackPosition = trackHeight * trackIndex;
|
|
||||||
const scrollTop = this.scrollbarsRef.getScrollTop();
|
|
||||||
const scrollBottom = scrollTop + this.scrollbarsRef.getClientHeight();
|
|
||||||
|
|
||||||
return !(trackPosition < scrollTop || trackPosition > scrollBottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTracklist() {
|
|
||||||
return (
|
|
||||||
<Tracklist
|
|
||||||
tracks={this.props.tracks}
|
|
||||||
activeTrackIndex={this.props.activeTrackIndex}
|
|
||||||
onTrackClick={this.props.onTrackClick}
|
|
||||||
className={this.props.className}
|
|
||||||
trackClassName={this.props.trackClassName}
|
|
||||||
reverseTrackOrder={this.props.reverseTrackOrder}
|
|
||||||
displayTrackNo={this.props.displayTrackNo}
|
|
||||||
displayBuyButtons={this.props.displayBuyButtons}
|
|
||||||
buyButtonsTarget={this.props.buyButtonsTarget}
|
|
||||||
displayCovers={this.props.displayCovers}
|
|
||||||
displayArtistNames={this.props.displayArtistNames}
|
|
||||||
onTrackLoop={this.props.onTrackLoop}
|
|
||||||
repeatingTrackIndex={this.props.repeatingTrackIndex}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { isOpen, limitTracklistHeight, tracklistHeight } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div id="tracklisting" style={{ display: isOpen ? 'block' : 'none' }}>
|
|
||||||
{limitTracklistHeight ? (
|
|
||||||
<Scrollbars
|
|
||||||
className="ai-scroll-wrap"
|
|
||||||
ref={ref => (this.scrollbarsRef = ref)} // eslint-disable-line no-return-assign
|
|
||||||
style={{ height: tracklistHeight }}
|
|
||||||
>
|
|
||||||
{this.renderTracklist()}
|
|
||||||
</Scrollbars>
|
|
||||||
) : (
|
|
||||||
this.renderTracklist()
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TracklistWrap.propTypes = {
|
|
||||||
tracks: PropTypes.arrayOf(PropTypes.object).isRequired,
|
tracks: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
activeTrackIndex: PropTypes.number.isRequired,
|
activeTrackIndex: PropTypes.number.isRequired,
|
||||||
onTrackClick: PropTypes.func.isRequired,
|
onTrackClick: PropTypes.func.isRequired,
|
||||||
@ -93,3 +22,87 @@ TracklistWrap.propTypes = {
|
|||||||
onTrackLoop: PropTypes.func,
|
onTrackLoop: PropTypes.func,
|
||||||
repeatingTrackIndex: PropTypes.number,
|
repeatingTrackIndex: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TracklistWrap = ({
|
||||||
|
isOpen,
|
||||||
|
limitTracklistHeight,
|
||||||
|
tracklistHeight,
|
||||||
|
tracks,
|
||||||
|
activeTrackIndex,
|
||||||
|
onTrackClick,
|
||||||
|
onTrackLoop,
|
||||||
|
className,
|
||||||
|
reverseTrackOrder,
|
||||||
|
trackClassName,
|
||||||
|
displayTrackNo,
|
||||||
|
displayBuyButtons,
|
||||||
|
buyButtonsTarget,
|
||||||
|
displayCovers,
|
||||||
|
displayArtistNames,
|
||||||
|
repeatingTrackIndex,
|
||||||
|
}) => {
|
||||||
|
const scrollbarRef = useRef(null);
|
||||||
|
|
||||||
|
const isTrackVisible = trackIndex => {
|
||||||
|
const trackHeight = scrollbarRef.current.getScrollHeight() / tracks.length;
|
||||||
|
const trackPosition = trackHeight * trackIndex;
|
||||||
|
const scrollTop = scrollbarRef.current.getScrollTop();
|
||||||
|
const scrollBottom = scrollTop + scrollbarRef.current.getClientHeight();
|
||||||
|
|
||||||
|
return !(trackPosition < scrollTop || trackPosition > scrollBottom);
|
||||||
|
};
|
||||||
|
|
||||||
|
const scrollToTrack = trackIndex => {
|
||||||
|
const trackHeight = scrollbarRef.current.getScrollHeight() / tracks.length;
|
||||||
|
|
||||||
|
if (!isTrackVisible(trackIndex)) {
|
||||||
|
scrollbarRef.current.scrollTop(trackHeight * trackIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (limitTracklistHeight) {
|
||||||
|
scrollToTrack(activeTrackIndex);
|
||||||
|
}
|
||||||
|
}, [activeTrackIndex, limitTracklistHeight]);
|
||||||
|
|
||||||
|
const renderTracklist = () => {
|
||||||
|
return (
|
||||||
|
<Tracklist
|
||||||
|
tracks={tracks}
|
||||||
|
activeTrackIndex={activeTrackIndex}
|
||||||
|
onTrackClick={onTrackClick}
|
||||||
|
className={className}
|
||||||
|
trackClassName={trackClassName}
|
||||||
|
reverseTrackOrder={reverseTrackOrder}
|
||||||
|
displayTrackNo={displayTrackNo}
|
||||||
|
displayBuyButtons={displayBuyButtons}
|
||||||
|
buyButtonsTarget={buyButtonsTarget}
|
||||||
|
displayCovers={displayCovers}
|
||||||
|
displayArtistNames={displayArtistNames}
|
||||||
|
onTrackLoop={onTrackLoop}
|
||||||
|
repeatingTrackIndex={repeatingTrackIndex}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="tracklisting" style={{ display: isOpen ? 'block' : 'none' }}>
|
||||||
|
{limitTracklistHeight ? (
|
||||||
|
<Scrollbars
|
||||||
|
className="ai-scroll-wrap"
|
||||||
|
ref={scrollbarRef} // eslint-disable-line no-return-assign
|
||||||
|
style={{ height: tracklistHeight }}
|
||||||
|
>
|
||||||
|
{renderTracklist()}
|
||||||
|
</Scrollbars>
|
||||||
|
) : (
|
||||||
|
renderTracklist()
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
TracklistWrap.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default TracklistWrap;
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import { VolumeUpIcon, VolumeDownIcon } from './Icons';
|
import { VolumeUpIcon, VolumeDownIcon } from './Icons';
|
||||||
|
|
||||||
export default class VolumeControl extends React.Component {
|
const propTypes = {
|
||||||
renderVolumeBars() {
|
volume: PropTypes.number.isRequired,
|
||||||
const { volume, setVolume } = this.props;
|
setVolume: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const VolumeControl = ({ volume, setVolume }) => {
|
||||||
|
const renderVolumeBars = () => {
|
||||||
return Array(...Array(11)).map((bar, i) => (
|
return Array(...Array(11)).map((bar, i) => (
|
||||||
<span
|
<span
|
||||||
key={i} // eslint-disable-line react/no-array-index-key
|
key={i} // eslint-disable-line react/no-array-index-key
|
||||||
@ -16,37 +20,32 @@ export default class VolumeControl extends React.Component {
|
|||||||
onClick={() => setVolume(i * 10)}
|
onClick={() => setVolume(i * 10)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { volume, setVolume } = this.props;
|
<div className="ai-audio-volume-control">
|
||||||
|
<div className="ai-audio-volume-bars">{renderVolumeBars()}</div>
|
||||||
|
|
||||||
return (
|
<div className="ai-audio-volume-control-btns">
|
||||||
<div className="ai-audio-volume-control">
|
<Button
|
||||||
<div className="ai-audio-volume-bars">{this.renderVolumeBars()}</div>
|
className="ai-btn"
|
||||||
|
onClick={() => setVolume(volume >= 100 ? volume : volume + 10)}
|
||||||
<div className="ai-audio-volume-control-btns">
|
aria-label={aiStrings.volume_up}
|
||||||
<Button
|
>
|
||||||
className="ai-btn"
|
<VolumeUpIcon />
|
||||||
onClick={() => setVolume(volume >= 100 ? volume : volume + 10)}
|
</Button>
|
||||||
aria-label={aiStrings.volume_up}
|
<Button
|
||||||
>
|
className="ai-btn"
|
||||||
<VolumeUpIcon />
|
onClick={() => setVolume(volume <= 0 ? volume : volume - 10)}
|
||||||
</Button>
|
aria-label={aiStrings.volume_down}
|
||||||
<Button
|
>
|
||||||
className="ai-btn"
|
<VolumeDownIcon />
|
||||||
onClick={() => setVolume(volume <= 0 ? volume : volume - 10)}
|
</Button>
|
||||||
aria-label={aiStrings.volume_down}
|
|
||||||
>
|
|
||||||
<VolumeDownIcon />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
}
|
|
||||||
|
|
||||||
VolumeControl.propTypes = {
|
|
||||||
volume: PropTypes.number.isRequired,
|
|
||||||
setVolume: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VolumeControl.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default VolumeControl;
|
||||||
|
@ -5,6 +5,7 @@ import Sound from 'react-sound';
|
|||||||
import SoundCloud from '../utils/soundcloud';
|
import SoundCloud from '../utils/soundcloud';
|
||||||
import multiSoundDisabled from '../utils/multi-sound-disabled';
|
import multiSoundDisabled from '../utils/multi-sound-disabled';
|
||||||
import { getInitialTrackQueueAndIndex } from '../utils/getInitialTrackIndex';
|
import { getInitialTrackQueueAndIndex } from '../utils/getInitialTrackIndex';
|
||||||
|
import playerStorage from '../utils/playerStorage';
|
||||||
|
|
||||||
const PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 2, 3];
|
const PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 2, 3];
|
||||||
|
|
||||||
@ -14,12 +15,15 @@ const soundProvider = (Player, events) => {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
playerId,
|
||||||
volume,
|
volume,
|
||||||
cycleTracks,
|
cycleTracks,
|
||||||
defaultShuffle,
|
defaultShuffle,
|
||||||
shuffleEnabled,
|
shuffleEnabled,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const initialData = playerStorage.get(playerId);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
tracks: [],
|
tracks: [],
|
||||||
activeIndex: 0, // Determine active track by index
|
activeIndex: 0, // Determine active track by index
|
||||||
@ -30,7 +34,7 @@ const soundProvider = (Player, events) => {
|
|||||||
// [4, 2, 0, ...] will play the 5th track first, 3rd second, then the 1st, etc.
|
// [4, 2, 0, ...] will play the 5th track first, 3rd second, then the 1st, etc.
|
||||||
trackQueue: [],
|
trackQueue: [],
|
||||||
playStatus: Sound.status.STOPPED,
|
playStatus: Sound.status.STOPPED,
|
||||||
position: 0,
|
position: initialData?.position ?? 0,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
playbackRate: 1,
|
playbackRate: 1,
|
||||||
volume: volume == null ? 100 : volume,
|
volume: volume == null ? 100 : volume,
|
||||||
@ -61,19 +65,39 @@ const soundProvider = (Player, events) => {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {
|
const {
|
||||||
|
playerId,
|
||||||
tracksUrl,
|
tracksUrl,
|
||||||
soundcloudClientId,
|
soundcloudClientId,
|
||||||
reverseTrackOrder,
|
reverseTrackOrder,
|
||||||
initialTrack,
|
initialTrack,
|
||||||
|
rememberLastPosition,
|
||||||
|
track,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { shuffle } = this.state;
|
const { shuffle } = this.state;
|
||||||
|
const initialData = playerStorage.get(playerId);
|
||||||
|
|
||||||
|
// We have a standalone track (from the shortcode).
|
||||||
|
if (track) {
|
||||||
|
try {
|
||||||
|
this.setState({
|
||||||
|
tracks: [JSON.parse(track)],
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
// eslint-disable-next-line no-empty
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
const tracksPromised = fetch(tracksUrl).then(res => res.json());
|
const tracksPromised = fetch(tracksUrl).then(res => res.json());
|
||||||
|
|
||||||
if (!soundcloudClientId) {
|
if (!soundcloudClientId) {
|
||||||
tracksPromised.then(tracks => {
|
tracksPromised.then(tracks => {
|
||||||
const { trackQueue, activeIndex } = getInitialTrackQueueAndIndex({
|
const { trackQueue, activeIndex } = getInitialTrackQueueAndIndex({
|
||||||
tracks,
|
tracks,
|
||||||
initialTrack,
|
initialTrack:
|
||||||
|
initialData?.activeIndex && rememberLastPosition
|
||||||
|
? initialData.activeIndex + 1
|
||||||
|
: initialTrack,
|
||||||
reverseTrackOrder,
|
reverseTrackOrder,
|
||||||
shuffle,
|
shuffle,
|
||||||
});
|
});
|
||||||
@ -139,12 +163,23 @@ const soundProvider = (Player, events) => {
|
|||||||
|
|
||||||
// Events
|
// Events
|
||||||
onPlaying({ duration, position }) {
|
onPlaying({ duration, position }) {
|
||||||
|
const { activeIndex } = this.state;
|
||||||
|
const { playerId, rememberLastPosition } = this.props;
|
||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
() => ({ duration, position }),
|
() => ({ duration, position }),
|
||||||
() => {
|
() => {
|
||||||
if (events && events.onPlaying) {
|
if (events && events.onPlaying) {
|
||||||
events.onPlaying(this.getFinalProps());
|
events.onPlaying(this.getFinalProps());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store last position every 5 seconds
|
||||||
|
if (playerId && rememberLastPosition && position % 5000 < 300) {
|
||||||
|
playerStorage.set(playerId, {
|
||||||
|
position,
|
||||||
|
activeIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -399,9 +434,11 @@ const soundProvider = (Player, events) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EnhancedPlayer.propTypes = {
|
EnhancedPlayer.propTypes = {
|
||||||
|
playerId: PropTypes.string,
|
||||||
volume: PropTypes.number,
|
volume: PropTypes.number,
|
||||||
cycleTracks: PropTypes.bool,
|
cycleTracks: PropTypes.bool,
|
||||||
tracksUrl: PropTypes.string,
|
tracksUrl: PropTypes.string,
|
||||||
|
track: PropTypes.string,
|
||||||
soundcloudClientId: PropTypes.string,
|
soundcloudClientId: PropTypes.string,
|
||||||
reverseTrackOrder: PropTypes.bool,
|
reverseTrackOrder: PropTypes.bool,
|
||||||
skipAmount: PropTypes.number,
|
skipAmount: PropTypes.number,
|
||||||
@ -410,6 +447,7 @@ const soundProvider = (Player, events) => {
|
|||||||
initialTrack: PropTypes.number,
|
initialTrack: PropTypes.number,
|
||||||
shuffleEnabled: PropTypes.bool,
|
shuffleEnabled: PropTypes.bool,
|
||||||
defaultShuffle: PropTypes.bool,
|
defaultShuffle: PropTypes.bool,
|
||||||
|
rememberLastPosition: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
return EnhancedPlayer;
|
return EnhancedPlayer;
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Very basic local storage facade with the ability to store objects.
|
||||||
|
*
|
||||||
|
* @type {{set: playerStorage.set, get: ((function(*): (undefined))|*)}}
|
||||||
|
*/
|
||||||
|
const playerStorage = {
|
||||||
|
set: (key, value) => {
|
||||||
|
if (!key || !value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(value));
|
||||||
|
} else {
|
||||||
|
window.localStorage.setItem(key, value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get: key => {
|
||||||
|
const value = localStorage.getItem(key);
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value);
|
||||||
|
|
||||||
|
if (parsed && typeof parsed === 'object') {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default playerStorage;
|
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* @file React hook for determining the size of a component.
|
||||||
|
*
|
||||||
|
* Forked from https://github.com/rehooks/component-size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useCallback, useState, useLayoutEffect } from 'react';
|
||||||
|
|
||||||
|
const getSize = el => {
|
||||||
|
if (!el) {
|
||||||
|
return {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: el.offsetWidth,
|
||||||
|
height: el.offsetHeight,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const useComponentSize = ref => {
|
||||||
|
const [ComponentSize, setComponentSize] = useState(
|
||||||
|
getSize(ref ? ref.current : {}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleResize = useCallback(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
setComponentSize(getSize(ref.current));
|
||||||
|
}
|
||||||
|
}, [ref]);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (!ref.current) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
|
||||||
|
if (typeof ResizeObserver === 'function') {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
let resizeObserver = new ResizeObserver(() => handleResize());
|
||||||
|
resizeObserver.observe(ref.current);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizeObserver.disconnect(ref.current);
|
||||||
|
resizeObserver = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
}, [ref.current]);
|
||||||
|
|
||||||
|
return ComponentSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useComponentSize;
|
@ -597,6 +597,52 @@ $screen-xs-max: 320px !default;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Player buttons
|
||||||
|
//
|
||||||
|
.ai-player-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
line-height: normal;
|
||||||
|
grid-gap: calc($spacing / 2);
|
||||||
|
margin-top: $spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-player-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
grid-gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: currentColor;
|
||||||
|
width: auto;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-player-button-icon-only {
|
||||||
|
padding: 0;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-player-button-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
fill: currentColor;
|
||||||
|
|
||||||
|
rect,
|
||||||
|
path {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Footer
|
// Footer
|
||||||
//
|
//
|
||||||
@ -979,16 +1025,16 @@ $screen-xs-max: 320px !default;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ai-audio-controls-main {
|
.ai-audio-controls-main {
|
||||||
padding-left: $spacing / 2;
|
padding-left: calc($spacing / 2);
|
||||||
padding-right: $spacing / 2;
|
padding-right: calc($spacing / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-track-info {
|
.ai-track-info {
|
||||||
padding-left: $spacing / 2;
|
padding-left: calc($spacing / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-audio-controls-meta {
|
.ai-audio-controls-meta {
|
||||||
margin-left: $spacing / 2;
|
margin-left: calc($spacing / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,9 @@ const common = {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
devServer: {
|
devServer: {
|
||||||
contentBase: path.resolve('assets'),
|
static: {
|
||||||
|
directory: path.resolve('assets'),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.jsx'],
|
extensions: ['.js', '.jsx'],
|
||||||
@ -37,7 +39,8 @@ const common = {
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.jsx?$/,
|
test: /\.jsx?$/,
|
||||||
use: ['babel-loader?cacheDirectory'],
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -51,6 +54,7 @@ switch (TARGET) {
|
|||||||
config = merge(
|
config = merge(
|
||||||
common,
|
common,
|
||||||
{
|
{
|
||||||
|
mode: 'production',
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: [path.resolve(__dirname), 'node_modules'],
|
modules: [path.resolve(__dirname), 'node_modules'],
|
||||||
extensions: ['.js', '.jsx'],
|
extensions: ['.js', '.jsx'],
|
||||||
@ -66,6 +70,7 @@ switch (TARGET) {
|
|||||||
config = merge(
|
config = merge(
|
||||||
common,
|
common,
|
||||||
{
|
{
|
||||||
|
mode: 'development',
|
||||||
devtool: 'eval-source-map',
|
devtool: 'eval-source-map',
|
||||||
},
|
},
|
||||||
parts.setupSass(PATHS.style),
|
parts.setupSass(PATHS.style),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
const autoprefixer = require('autoprefixer');
|
const autoprefixer = require('autoprefixer');
|
||||||
|
|
||||||
exports.setupSass = paths => ({
|
exports.setupSass = paths => ({
|
||||||
@ -19,48 +20,34 @@ exports.extractCSS = paths => ({
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: ExtractTextPlugin.extract({
|
use: [
|
||||||
fallback: 'style-loader',
|
MiniCssExtractPlugin.loader,
|
||||||
use: [
|
{
|
||||||
{
|
loader: 'css-loader',
|
||||||
loader: 'css-loader',
|
},
|
||||||
options: {
|
{
|
||||||
minimize: true,
|
loader: 'postcss-loader',
|
||||||
},
|
options: {
|
||||||
},
|
postcssOptions: {
|
||||||
{
|
plugins: [
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: {
|
|
||||||
plugins: () => [
|
|
||||||
autoprefixer({
|
autoprefixer({
|
||||||
browsers: [
|
browsers: ['last 2 versions', '>1%'],
|
||||||
'Chrome >= 46',
|
|
||||||
'Firefox ESR',
|
|
||||||
'Edge >= 12',
|
|
||||||
'Explorer >= 9',
|
|
||||||
'iOS >= 8',
|
|
||||||
'Safari >= 8',
|
|
||||||
'Android >= 4',
|
|
||||||
],
|
|
||||||
cascade: false,
|
cascade: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
loader: 'sass-loader',
|
{
|
||||||
options: {
|
loader: 'sass-loader',
|
||||||
outputStyle: 'expanded',
|
},
|
||||||
},
|
],
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
include: paths,
|
include: paths,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new ExtractTextPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: '[name].css',
|
filename: '[name].css',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@ -68,33 +55,25 @@ exports.extractCSS = paths => ({
|
|||||||
|
|
||||||
exports.devServer = options => ({
|
exports.devServer = options => ({
|
||||||
devServer: {
|
devServer: {
|
||||||
contentBase: __dirname,
|
static:{
|
||||||
|
directory: __dirname,
|
||||||
|
},
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
hot: false,
|
hot: false,
|
||||||
inline: true,
|
|
||||||
stats: 'errors-only',
|
|
||||||
host: options.host,
|
host: options.host,
|
||||||
port: options.port,
|
port: options.port,
|
||||||
overlay: {
|
|
||||||
warnings: true,
|
|
||||||
errors: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.minify = () => ({
|
exports.minify = () => ({
|
||||||
plugins: [
|
optimization: {
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
minimize: true,
|
||||||
compress: {
|
minimizer: [
|
||||||
warnings: false,
|
new TerserPlugin({
|
||||||
drop_console: true,
|
parallel: false,
|
||||||
screw_ie8: true,
|
}),
|
||||||
},
|
],
|
||||||
output: {
|
},
|
||||||
comments: false,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.setFreeVariable = (key, value) => {
|
exports.setFreeVariable = (key, value) => {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,8 @@
|
|||||||
Contributors: cssigniterteam, anastis, silencerius, tsiger
|
Contributors: cssigniterteam, anastis, silencerius, tsiger
|
||||||
Tags: audio, podcast, audio player, html5 player, mp3 player, music player, music, radio stream, radio player, sound player, player, podcast player
|
Tags: audio, podcast, audio player, html5 player, mp3 player, music player, music, radio stream, radio player, sound player, player, podcast player
|
||||||
Requires at least: 5.0
|
Requires at least: 5.0
|
||||||
Tested up to: 5.9
|
Tested up to: 6.0
|
||||||
Stable tag: 1.7.3
|
Stable tag: 1.9.0
|
||||||
License: GPLv2 or later
|
License: GPLv2 or later
|
||||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||||
|
|
||||||
@ -84,6 +84,10 @@ A [Pro version](https://www.cssigniter.com/plugins/audioigniter) is also availab
|
|||||||
* Customize the colors through the Customizer
|
* Customize the colors through the Customizer
|
||||||
* Custom block for the Gutenberg Block Editor (With the ability to change colors per player)
|
* Custom block for the Gutenberg Block Editor (With the ability to change colors per player)
|
||||||
* Widget & Shortcode available
|
* Widget & Shortcode available
|
||||||
|
* Streaming service button links
|
||||||
|
* Sync download URL with audio URL automatically
|
||||||
|
* Standalone shortcode for single tracks (without the need to create a playlist)
|
||||||
|
* Remember last played track and position
|
||||||
|
|
||||||
**PREMIUM SUPPORT**
|
**PREMIUM SUPPORT**
|
||||||
You can expect the same level of support for both the free and pro version of our plugin. Average response time: 24 hours.
|
You can expect the same level of support for both the free and pro version of our plugin. Average response time: 24 hours.
|
||||||
@ -102,6 +106,21 @@ You can expect the same level of support for both the free and pro version of ou
|
|||||||
|
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 1.9.0 =
|
||||||
|
* Fixed a JavaScript error in the admin when selecting an image without thumbnails.
|
||||||
|
* Show the playlist shortcode metabox on the side.
|
||||||
|
* Show the playlist shortcode on the admin playlists listing page.
|
||||||
|
* Action 'audioigniter_metabox_tracks_field_controls' now passes $location and $post_id parameters.
|
||||||
|
* Repeatable fields overhaul.
|
||||||
|
* Underlying support for new Pro functionality (Use track as download url, player buttons, single track shortcode).
|
||||||
|
|
||||||
|
= 1.8.0 =
|
||||||
|
* General performance updates.
|
||||||
|
* Upgrade of base libraries.
|
||||||
|
* Drop support for Internet Explorer.
|
||||||
|
* Removed unneeded nonce.
|
||||||
|
* The playlists' shortcode meta box now has a 'low' priority so that it's displayed last.
|
||||||
|
|
||||||
= 1.7.3 =
|
= 1.7.3 =
|
||||||
* Top "Add Track" prepends a track, and bottom "Add Track" appends a track.
|
* Top "Add Track" prepends a track, and bottom "Add Track" appends a track.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user