Set up some basic web components and basically format a track card #25
|
@ -11,6 +11,7 @@
|
|||
<div class="controls"><button class="play-pause">Pause</button></div>
|
||||
|
||||
<div class="track-list">
|
||||
<!--
|
||||
<div class="track-list__grouping">
|
||||
<ul class="bulletless-list">
|
||||
<li> By Artist </li>
|
||||
|
@ -19,60 +20,11 @@
|
|||
<li> Dance Music </li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="track-list__tracks">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th> id </th>
|
||||
<th> Track # </th>
|
||||
<th> Title </th>
|
||||
<th> Artist </th>
|
||||
<th> Album </th>
|
||||
<th> Length </th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<!--
|
||||
<tr class="track-list__track-row">
|
||||
<td> 1 </td>
|
||||
<td> Underground </td>
|
||||
<td> Lindsey Stirling </td>
|
||||
<td> Artemis </td>
|
||||
<td> 4:24 </td>
|
||||
</tr>
|
||||
<tr class="track-list__track-row">
|
||||
<td> 2 </td>
|
||||
<td> Artemis </td>
|
||||
<td> Lindsey Stirling </td>
|
||||
<td> Artemis </td>
|
||||
<td> 3:54 </td>
|
||||
</tr>
|
||||
<tr class="track-list__track-row">
|
||||
<td> 3 </td>
|
||||
<td> Til the Light Goes Out </td>
|
||||
<td> Lindsey Stirling </td>
|
||||
<td> Artemis </td>
|
||||
<td> 4:46 </td>
|
||||
</tr>
|
||||
<tr class="track-list__track-row">
|
||||
<td> 4 </td>
|
||||
<td> Between Twilight </td>
|
||||
<td> Lindsey Stirling </td>
|
||||
<td> Artemis </td>
|
||||
<td> 4:20 </td>
|
||||
</tr>
|
||||
<tr class="track-list__track-row">
|
||||
<td> 5 </td>
|
||||
<td> Foreverglow </td>
|
||||
<td> Lindsey Stirling </td>
|
||||
<td> Artemis </td>
|
||||
<td> 3:58 </td>
|
||||
</tr>
|
||||
-->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div>
|
||||
<ul class="track-list__tracks bulletless-list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,9 +4,9 @@
|
|||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"build": "browserify src/main.ts -p [ tsify ] > dist/bundle.js && cp index.html styles.css dist",
|
||||
"build": "webpack",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"watch": "exa index.html styles.css src/* | entr -s 'npm run build'"
|
||||
"watch": "webpack --watch"
|
||||
},
|
||||
"author": "Savanni D'Gerinel <savanni@luminescent-dreams.com>",
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
@ -16,10 +16,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.191",
|
||||
"babelify": "^10.0.0",
|
||||
"browserify": "^17.0.0",
|
||||
"tsify": "^5.0.4",
|
||||
"typescript": "^4.9.4",
|
||||
"watchify": "^4.0.0"
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.7.3",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
import { TrackInfo } from "../client";
|
||||
|
||||
export class TrackName extends HTMLElement {
|
||||
container: HTMLElement;
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["name"];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.container = document.createElement("div");
|
||||
}
|
||||
|
||||
get name(): string | null {
|
||||
return this.getAttribute("name");
|
||||
}
|
||||
|
||||
set name(name: string | null) {
|
||||
while (this.container.lastChild) {
|
||||
this.container.removeChild(this.container.lastChild);
|
||||
}
|
||||
if (name) {
|
||||
this.setAttribute("name", name);
|
||||
this.container.appendChild(document.createTextNode(name));
|
||||
} else {
|
||||
this.removeAttribute("name");
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.appendChild(this.container);
|
||||
}
|
||||
}
|
||||
|
||||
export class TrackCard extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return ["id", "trackNumber", "name", "album", "artist"];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
attributeChangeCallback(
|
||||
attrName: string,
|
||||
oldValue: string,
|
||||
newValue: string
|
||||
): void {
|
||||
if (newValue !== oldValue) {
|
||||
this.updateContent();
|
||||
}
|
||||
}
|
||||
|
||||
get name(): string | null {
|
||||
return this.getAttribute("name");
|
||||
}
|
||||
|
||||
set name(name: string | null) {
|
||||
if (name) {
|
||||
this.setAttribute("name", name);
|
||||
} else {
|
||||
this.removeAttribute("open");
|
||||
}
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
get artist(): string | null {
|
||||
return this.getAttribute("artist");
|
||||
}
|
||||
|
||||
set artist(artist: string | null) {
|
||||
if (artist) {
|
||||
this.setAttribute("artist", artist);
|
||||
} else {
|
||||
this.removeAttribute("open");
|
||||
}
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
get album(): string | null {
|
||||
return this.getAttribute("album");
|
||||
}
|
||||
|
||||
set album(album: string | null) {
|
||||
if (album) {
|
||||
this.setAttribute("album", album);
|
||||
} else {
|
||||
this.removeAttribute("open");
|
||||
}
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
get length(): string | null {
|
||||
return this.getAttribute("length");
|
||||
}
|
||||
|
||||
set length(length: string | null) {
|
||||
if (length) {
|
||||
this.setAttribute("length", length);
|
||||
} else {
|
||||
this.removeAttribute("open");
|
||||
}
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
updateContent() {
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("track-card");
|
||||
this.innerHTML = "";
|
||||
|
||||
this.appendChild(container);
|
||||
|
||||
while (container.lastChild) {
|
||||
container.removeChild(container.lastChild);
|
||||
}
|
||||
|
||||
if (this["name"]) {
|
||||
const trackName = document.createElement("track-name");
|
||||
trackName.name = this["name"];
|
||||
container.appendChild(trackName);
|
||||
}
|
||||
this["length"] && container.appendChild(document.createTextNode("1:23"));
|
||||
this["album"] &&
|
||||
container.appendChild(document.createTextNode("Shatter Me"));
|
||||
this["artist"] &&
|
||||
container.appendChild(document.createTextNode("Lindsey Stirling"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
export interface TrackInfo {
|
||||
id: string;
|
||||
track_number?: number;
|
||||
name?: string;
|
||||
album?: string;
|
||||
artist?: string;
|
||||
}
|
||||
|
||||
export const getTracks = (): Promise<TrackInfo[]> =>
|
||||
fetch("/api/v1/tracks").then((r) => r.json());
|
|
@ -1,11 +1,15 @@
|
|||
import * as _ from "lodash";
|
||||
import { TrackInfo, getTracks } from "./client";
|
||||
import { TrackName, TrackCard } from "./blocks/track";
|
||||
|
||||
interface TrackInfo {
|
||||
id: string;
|
||||
track_number?: number;
|
||||
name?: string;
|
||||
album?: string;
|
||||
artist?: string;
|
||||
window.customElements.define("track-name", TrackName);
|
||||
window.customElements.define("track-card", TrackCard);
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"track-name": TrackName;
|
||||
"track-card": TrackCard;
|
||||
}
|
||||
}
|
||||
|
||||
const replaceTitle = () => {
|
||||
|
@ -15,52 +19,22 @@ const replaceTitle = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const getTracks = () => fetch("/api/v1/tracks").then((r) => r.json());
|
||||
|
||||
const formatTrack = (track: TrackInfo) => {
|
||||
let row = document.createElement("tr");
|
||||
row.classList.add("track-list__row");
|
||||
|
||||
let track_id = document.createElement("td");
|
||||
track_id.appendChild(document.createTextNode(track.id));
|
||||
track_id.classList.add("track-list__cell");
|
||||
|
||||
let track_number = document.createElement("td");
|
||||
track_number.appendChild(
|
||||
document.createTextNode(track.track_number?.toString() || "")
|
||||
);
|
||||
track_number.classList.add("track-list__cell");
|
||||
|
||||
let name = document.createElement("td");
|
||||
name.appendChild(document.createTextNode(track.name || ""));
|
||||
name.classList.add("track-list__cell");
|
||||
|
||||
let album = document.createElement("td");
|
||||
album.appendChild(document.createTextNode(track.album || ""));
|
||||
album.classList.add("track-list__cell");
|
||||
|
||||
let artist = document.createElement("td");
|
||||
artist.appendChild(document.createTextNode(track.artist || ""));
|
||||
artist.classList.add("track-list__cell");
|
||||
|
||||
let length = document.createElement("td");
|
||||
artist.appendChild(document.createTextNode(""));
|
||||
length.classList.add("track-list__cell");
|
||||
|
||||
row.appendChild(track_id);
|
||||
row.appendChild(track_number);
|
||||
row.appendChild(name);
|
||||
row.appendChild(artist);
|
||||
row.appendChild(album);
|
||||
row.appendChild(length);
|
||||
return row;
|
||||
};
|
||||
|
||||
const updateTrackList = (tracks: TrackInfo[]) => {
|
||||
const track_list = document.querySelector(".track-list__tracks tbody");
|
||||
const track_list = document.querySelector(".track-list__tracks");
|
||||
if (track_list) {
|
||||
let track_formats = _.map(tracks, formatTrack);
|
||||
_.map(track_formats, (trackinfo) => track_list.appendChild(trackinfo));
|
||||
let track_formats = _.map(tracks, (info) => {
|
||||
let card: TrackCard = document.createElement("track-card");
|
||||
card.name = info.name || null;
|
||||
return card;
|
||||
});
|
||||
_.map(track_formats, (trackCard) => {
|
||||
let listItem = document.createElement("li");
|
||||
listItem.classList.add("track-list__row");
|
||||
listItem.appendChild(trackCard);
|
||||
track_list.appendChild(listItem);
|
||||
});
|
||||
} else {
|
||||
console.log("track_list does not exist");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -26,9 +26,10 @@ body {
|
|||
}
|
||||
|
||||
.track-list__row {
|
||||
background-color: rgb(10, 10, 10);
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
/*
|
||||
.track-list__row:nth-child(even) {
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
@ -36,7 +37,25 @@ body {
|
|||
.track-list__row:nth-child(odd) {
|
||||
background-color: rgb(200, 200, 200);
|
||||
}
|
||||
*/
|
||||
|
||||
.track-list__cell {
|
||||
.track-card {
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
width: 300px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.track-card__name {
|
||||
}
|
||||
|
||||
.track-card__length {
|
||||
}
|
||||
|
||||
.track-card__album {
|
||||
}
|
||||
|
||||
.track-card__artist {
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
"outDir": "./dist",
|
||||
"lib": ["es2016", "DOM"],
|
||||
"sourceMap": true,
|
||||
"strict": true
|
||||
}
|
||||
"strict": true,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
const path = require('path');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
entry: './src/main.ts',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.html$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
},
|
||||
plugins: [
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: "index.html", to: "index.html" },
|
||||
{ from: "styles.css", to: "styles.css" },
|
||||
],
|
||||
}),
|
||||
],
|
||||
output: {
|
||||
filename: 'bundle.js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
};
|
|
@ -583,6 +583,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"dbus",
|
||||
"flow",
|
||||
"mime_guess",
|
||||
"mpris",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
dbus = { version = "0.9.7" }
|
||||
flow = { path = "../../flow" }
|
||||
mime_guess = "2.0.4"
|
||||
mpris = { version = "2.0" }
|
||||
rusqlite = { version = "0.28" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
|
|
@ -21,20 +21,21 @@ fn tracks(index: &Arc<impl MusicIndex>) -> Vec<TrackInfo> {
|
|||
}
|
||||
}
|
||||
|
||||
enum Bundle {
|
||||
Index,
|
||||
App,
|
||||
Styles,
|
||||
}
|
||||
struct Static(PathBuf);
|
||||
|
||||
impl Bundle {
|
||||
impl Static {
|
||||
fn read(self, root: PathBuf) -> String {
|
||||
/*
|
||||
let mut path = root;
|
||||
match self {
|
||||
Bundle::Index => path.push(PathBuf::from("index.html")),
|
||||
Bundle::App => path.push(PathBuf::from("bundle.js")),
|
||||
Bundle::Styles => path.push(PathBuf::from("styles.css")),
|
||||
};
|
||||
std::fs::read_to_string(path).expect("to find the file")
|
||||
*/
|
||||
let mut path = root;
|
||||
path.push(self.0);
|
||||
println!("path: {:?}", path);
|
||||
std::fs::read_to_string(path).expect("to find the file")
|
||||
}
|
||||
|
@ -68,23 +69,22 @@ pub async fn main() {
|
|||
move || {
|
||||
warp::http::Response::builder()
|
||||
.header("content-type", "text/html")
|
||||
.body(Bundle::Index.read(bundle_root.clone()))
|
||||
.body(Static(PathBuf::from("index.html")).read(bundle_root.clone()))
|
||||
}
|
||||
});
|
||||
let app = warp::path!("bundle.js").and(warp::get()).map({
|
||||
let assets = warp::path!(String).and(warp::get()).map({
|
||||
let bundle_root = bundle_root.clone();
|
||||
move || {
|
||||
move |filename: String| {
|
||||
let mime_type = mime_guess::from_path(filename.clone())
|
||||
.first()
|
||||
.map(|m| m.essence_str().to_owned())
|
||||
.unwrap_or("text/plain".to_owned());
|
||||
println!("mime_type: {:?}", mime_type);
|
||||
// let mut path = PathBuf::from("assets");
|
||||
// path.push(filename);
|
||||
warp::http::Response::builder()
|
||||
.header("content-type", "text/javascript")
|
||||
.body(Bundle::App.read(bundle_root.clone()))
|
||||
}
|
||||
});
|
||||
let styles = warp::path!("styles.css").and(warp::get()).map({
|
||||
let bundle_root = bundle_root.clone();
|
||||
move || {
|
||||
warp::http::Response::builder()
|
||||
.header("content-type", "text/css")
|
||||
.body(Bundle::Styles.read(bundle_root.clone()))
|
||||
.header("content-type", mime_type)
|
||||
.body(Static(PathBuf::from(filename)).read(bundle_root.clone()))
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -128,12 +128,9 @@ pub async fn main() {
|
|||
.or(queue)
|
||||
.or(playing_status);
|
||||
*/
|
||||
let routes = root.or(app).or(styles).or(track_list);
|
||||
let routes = root.or(assets).or(track_list);
|
||||
let server = warp::serve(routes);
|
||||
server
|
||||
.run(SocketAddr::new(
|
||||
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||
8002,
|
||||
))
|
||||
.run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8002))
|
||||
.await;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,10 @@ impl FileIterator {
|
|||
id: TrackId::from(path.to_str().unwrap().to_owned()),
|
||||
album: None,
|
||||
artist: None,
|
||||
name: None,
|
||||
name: path
|
||||
.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(|s| s.to_owned()),
|
||||
track_number: None,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue