Compare commits
10 Commits
main
...
45-impleme
Author | SHA1 | Date | |
---|---|---|---|
6112e0dfac | |||
af604a9ddc | |||
bcb24c2a97 | |||
6676f2c533 | |||
3746c370a2 | |||
64e93649af | |||
fcc5870824 | |||
3ce762ce5b | |||
1ecd13d65f | |||
be775862f9 |
66
src/api/albums.rs
Normal file
66
src/api/albums.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use leptos::*;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "ssr")] {
|
||||
use crate::database::get_db_conn;
|
||||
use diesel::prelude::*;
|
||||
use time::Date;
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an album to the database
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `album_title` - The name of the artist to add
|
||||
/// * `release_data` - The release date of the album (Optional)
|
||||
/// * `image_path` - The path to the album's image file (Optional)
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Result<(), Box<dyn Error>>` - A empty result if successful, or an error
|
||||
///
|
||||
#[server(endpoint = "albums/add-album")]
|
||||
pub async fn add_album(album_title: String, release_date: Option<String>, image_path: Option<String>) -> Result<(), ServerFnError> {
|
||||
use crate::schema::albums::{self};
|
||||
use crate::models::Album;
|
||||
use leptos::server_fn::error::NoCustomError;
|
||||
|
||||
let date_format = time::macros::format_description!("[year]-[month]-[day]");
|
||||
let parsed_release_date = match release_date {
|
||||
Some(date) => {
|
||||
match Date::parse(&date, &date_format) {
|
||||
Ok(parsed_date) => Some(parsed_date),
|
||||
Err(_e) => return Err(ServerFnError::<NoCustomError>::ServerError("Invalid release date".to_string()))
|
||||
}
|
||||
},
|
||||
None => None
|
||||
};
|
||||
|
||||
let image_path_arg = match image_path {
|
||||
Some(image_path) => {
|
||||
if image_path.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(image_path)
|
||||
}
|
||||
},
|
||||
None => None
|
||||
};
|
||||
|
||||
let new_album = Album {
|
||||
id: None,
|
||||
title: album_title,
|
||||
release_date: parsed_release_date,
|
||||
image_path: image_path_arg
|
||||
};
|
||||
|
||||
let db = &mut get_db_conn();
|
||||
diesel::insert_into(albums::table)
|
||||
.values(&new_album)
|
||||
.execute(db)
|
||||
.map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error adding album: {}", e)))?;
|
||||
|
||||
Ok(())
|
||||
}
|
39
src/api/artists.rs
Normal file
39
src/api/artists.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use leptos::*;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "ssr")] {
|
||||
use crate::database::get_db_conn;
|
||||
use diesel::prelude::*;
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an artist to the database
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `artist_name` - The name of the artist to add
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Result<(), Box<dyn Error>>` - A empty result if successful, or an error
|
||||
///
|
||||
#[server(endpoint = "artists/add-artist")]
|
||||
pub async fn add_artist(artist_name: String) -> Result<(), ServerFnError> {
|
||||
use crate::schema::artists::dsl::*;
|
||||
use crate::models::Artist;
|
||||
use leptos::server_fn::error::NoCustomError;
|
||||
|
||||
let new_artist = Artist {
|
||||
id: None,
|
||||
name: artist_name,
|
||||
};
|
||||
|
||||
let db = &mut get_db_conn();
|
||||
diesel::insert_into(artists)
|
||||
.values(&new_artist)
|
||||
.execute(db)
|
||||
.map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error adding artist: {}", e)))?;
|
||||
|
||||
Ok(())
|
||||
}
|
2
src/api/mod.rs
Normal file
2
src/api/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod artists;
|
||||
pub mod albums;
|
18
src/app.rs
18
src/app.rs
@ -17,6 +17,8 @@ pub fn App() -> impl IntoView {
|
||||
let play_status = PlayStatus::default();
|
||||
let play_status = create_rw_signal(play_status);
|
||||
let upload_open = create_rw_signal(false);
|
||||
let add_artist_open = create_rw_signal(false);
|
||||
let add_album_open = create_rw_signal(false);
|
||||
|
||||
view! {
|
||||
// injects a stylesheet into the document <head>
|
||||
@ -37,7 +39,13 @@ pub fn App() -> impl IntoView {
|
||||
}>
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="" view=move || view! { <HomePage play_status=play_status upload_open=upload_open/> }>
|
||||
<Route path="" view=move ||
|
||||
view! { <HomePage play_status=play_status
|
||||
upload_open=upload_open
|
||||
add_artist_open=add_artist_open
|
||||
add_album_open=add_album_open
|
||||
/>
|
||||
}>
|
||||
<Route path="" view=Dashboard />
|
||||
<Route path="dashboard" view=Dashboard />
|
||||
<Route path="search" view=Search />
|
||||
@ -55,14 +63,18 @@ use crate::components::dashboard::*;
|
||||
use crate::components::search::*;
|
||||
use crate::components::personal::*;
|
||||
use crate::components::upload::*;
|
||||
use crate::components::add_artist::AddArtist;
|
||||
use crate::components::add_album::AddAlbum;
|
||||
|
||||
/// Renders the home page of your application.
|
||||
#[component]
|
||||
fn HomePage(play_status: RwSignal<PlayStatus>, upload_open: RwSignal<bool>) -> impl IntoView {
|
||||
fn HomePage(play_status: RwSignal<PlayStatus>, upload_open: RwSignal<bool>, add_artist_open: RwSignal<bool>, add_album_open: RwSignal<bool>) -> impl IntoView {
|
||||
view! {
|
||||
<div class="home-container">
|
||||
<Upload open=upload_open/>
|
||||
<Sidebar upload_open=upload_open/>
|
||||
<AddArtist open=add_artist_open/>
|
||||
<AddAlbum open=add_album_open/>
|
||||
<Sidebar upload_open=upload_open add_artist_open=add_artist_open add_album_open=add_album_open/>
|
||||
// This <Outlet /> will render the child route components
|
||||
<Outlet />
|
||||
<Personal />
|
||||
|
@ -3,3 +3,6 @@ pub mod dashboard;
|
||||
pub mod search;
|
||||
pub mod personal;
|
||||
pub mod upload;
|
||||
pub mod upload_dropdown;
|
||||
pub mod add_artist;
|
||||
pub mod add_album;
|
92
src/components/add_album.rs
Normal file
92
src/components/add_album.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use leptos::*;
|
||||
use leptos::leptos_dom::log;
|
||||
use leptos_icons::*;
|
||||
use crate::api::albums::add_album;
|
||||
|
||||
#[component]
|
||||
pub fn AddAlbumBtn(add_album_open: RwSignal<bool>) -> impl IntoView {
|
||||
let open_dialog = move |_| {
|
||||
add_album_open.set(true);
|
||||
};
|
||||
view! {
|
||||
<button class="add-album-btn add-btns" on:click=open_dialog>
|
||||
Add Album
|
||||
</button>
|
||||
}
|
||||
}
|
||||
#[component]
|
||||
pub fn AddAlbum(open: RwSignal<bool>) -> impl IntoView {
|
||||
let album_title = create_rw_signal("".to_string());
|
||||
let release_date = create_rw_signal("".to_string());
|
||||
let image_path = create_rw_signal("".to_string());
|
||||
|
||||
let close_dialog = move |ev: leptos::ev::MouseEvent| {
|
||||
ev.prevent_default();
|
||||
open.set(false);
|
||||
};
|
||||
|
||||
let on_add_album = move |ev: leptos::ev::SubmitEvent| {
|
||||
ev.prevent_default();
|
||||
let album_title_clone = album_title.get();
|
||||
let release_date_clone = Some(release_date.get());
|
||||
let image_path_clone = Some(image_path.get());
|
||||
|
||||
spawn_local(async move {
|
||||
let add_album_result = add_album(album_title_clone, release_date_clone, image_path_clone).await;
|
||||
if let Err(err) = add_album_result {
|
||||
log!("Error adding album: {:?}", err);
|
||||
} else if let Ok(album) = add_album_result {
|
||||
log!("Added album: {:?}", album);
|
||||
album_title.set("".to_string());
|
||||
release_date.set("".to_string());
|
||||
image_path.set("".to_string());
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
view! {
|
||||
<Show when=open fallback=move|| view!{}>
|
||||
<div class="add-album-container">
|
||||
<div class="upload-header">
|
||||
<h1>Add Album</h1>
|
||||
</div>
|
||||
<div class="close-button" on:click=close_dialog><Icon icon=icondata::IoClose /></div>
|
||||
<form class="create-album-form" action="POST" on:submit=on_add_album>
|
||||
<div class="input-bx">
|
||||
<input type="text" required class="text-input"
|
||||
prop:value=album_title
|
||||
on:input=move |ev: leptos::ev::Event| {
|
||||
album_title.set(event_target_value(&ev));
|
||||
}
|
||||
required
|
||||
/>
|
||||
<span>Album Title</span>
|
||||
</div>
|
||||
<div class="release-date">
|
||||
<div class="left">
|
||||
<span>Release</span>
|
||||
<span>Date</span>
|
||||
</div>
|
||||
<input class="info" type="date"
|
||||
prop:value=release_date
|
||||
on:input=move |ev: leptos::ev::Event| {
|
||||
release_date.set(event_target_value(&ev));
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div class="input-bx">
|
||||
<input type="text" class="text-input"
|
||||
prop:value=image_path
|
||||
on:input=move |ev: leptos::ev::Event| {
|
||||
image_path.set(event_target_value(&ev));
|
||||
}
|
||||
/>
|
||||
<span>Image Path</span>
|
||||
</div>
|
||||
<button type="submit" class="upload-button">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
</Show>
|
||||
}
|
||||
|
||||
}
|
62
src/components/add_artist.rs
Normal file
62
src/components/add_artist.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use leptos::*;
|
||||
use leptos::leptos_dom::log;
|
||||
use leptos_icons::*;
|
||||
use crate::api::artists::add_artist;
|
||||
|
||||
#[component]
|
||||
pub fn AddArtistBtn(add_artist_open: RwSignal<bool>) -> impl IntoView {
|
||||
let open_dialog = move |_| {
|
||||
add_artist_open.set(true);
|
||||
};
|
||||
view! {
|
||||
<button class="add-artist-btn add-btns" on:click=open_dialog>
|
||||
Add Artist
|
||||
</button>
|
||||
}
|
||||
}
|
||||
#[component]
|
||||
pub fn AddArtist(open: RwSignal<bool>) -> impl IntoView {
|
||||
let artist_name = create_rw_signal("".to_string());
|
||||
|
||||
let close_dialog = move |ev: leptos::ev::MouseEvent| {
|
||||
ev.prevent_default();
|
||||
open.set(false);
|
||||
};
|
||||
let on_add_artist = move |ev: leptos::ev::SubmitEvent| {
|
||||
ev.prevent_default();
|
||||
let artist_name_clone = artist_name.get();
|
||||
spawn_local(async move {
|
||||
let add_artist_result = add_artist(artist_name_clone).await;
|
||||
if let Err(err) = add_artist_result {
|
||||
log!("Error adding artist: {:?}", err);
|
||||
} else if let Ok(artist) = add_artist_result {
|
||||
log!("Added artist: {:?}", artist);
|
||||
artist_name.set("".to_string());
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
view! {
|
||||
<Show when=open fallback=move|| view!{}>
|
||||
<div class="add-artist-container">
|
||||
<div class="upload-header">
|
||||
<h1>Add Artist</h1>
|
||||
</div>
|
||||
<div class="close-button" on:click=close_dialog><Icon icon=icondata::IoClose /></div>
|
||||
<form class="create-artist-form" action="POST" on:submit=on_add_artist>
|
||||
<div class="input-bx">
|
||||
<input type="text" name="title" required class="text-input"
|
||||
prop:value=artist_name
|
||||
on:input=move |ev: leptos::ev::Event| {
|
||||
artist_name.set(event_target_value(&ev));
|
||||
}
|
||||
required
|
||||
/>
|
||||
<span>Artist Name</span>
|
||||
</div>
|
||||
<button type="submit" class="upload-button">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
</Show>
|
||||
}
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
use leptos::leptos_dom::*;
|
||||
use leptos::*;
|
||||
use leptos_icons::*;
|
||||
use crate::components::upload::*;
|
||||
use crate::components::upload_dropdown::*;
|
||||
|
||||
#[component]
|
||||
pub fn Sidebar(upload_open: RwSignal<bool>) -> impl IntoView {
|
||||
pub fn Sidebar(upload_open: RwSignal<bool>, add_artist_open: RwSignal<bool>, add_album_open: RwSignal<bool>) -> impl IntoView {
|
||||
use leptos_router::use_location;
|
||||
let location = use_location();
|
||||
|
||||
let dropdown_open = create_rw_signal(false);
|
||||
|
||||
let on_dashboard = Signal::derive(
|
||||
move || location.pathname.get().starts_with("/dashboard") || location.pathname.get() == "/",
|
||||
);
|
||||
@ -19,8 +21,26 @@ pub fn Sidebar(upload_open: RwSignal<bool>) -> impl IntoView {
|
||||
view! {
|
||||
<div class="sidebar-container">
|
||||
<div class="sidebar-top-container">
|
||||
<Show
|
||||
when=move || {upload_open.get() || add_artist_open.get() || add_album_open.get()}
|
||||
fallback=move || view! {}
|
||||
>
|
||||
<div class="upload-overlay" on:click=move |_| {
|
||||
upload_open.set(false);
|
||||
add_artist_open.set(false);
|
||||
add_album_open.set(false);
|
||||
}></div>
|
||||
</Show>
|
||||
<h2 class="header">LibreTunes</h2>
|
||||
<UploadBtn dialog_open=upload_open />
|
||||
<div class="upload-dropdown-container">
|
||||
<UploadDropdownBtn dropdown_open=dropdown_open/>
|
||||
<Show
|
||||
when= move || dropdown_open()
|
||||
fallback=move || view! {}
|
||||
>
|
||||
<UploadDropdown dropdown_open=dropdown_open upload_open=upload_open add_artist_open=add_artist_open add_album_open=add_album_open/>
|
||||
</Show>
|
||||
</div>
|
||||
<a class="buttons" href="/dashboard" style={move || if on_dashboard() {"color: #e1e3e1"} else {""}} >
|
||||
<Icon icon=icondata::OcHomeFillLg />
|
||||
<h1>Dashboard</h1>
|
||||
|
@ -16,11 +16,8 @@ pub fn UploadBtn(dialog_open: RwSignal<bool>) -> impl IntoView {
|
||||
};
|
||||
|
||||
view! {
|
||||
<button class="upload-btn" on:click=open_dialog>
|
||||
<div class="add-sign">
|
||||
<Icon icon=icondata::IoAddSharp />
|
||||
</div>
|
||||
Upload
|
||||
<button class="upload-btn add-btns" on:click=open_dialog>
|
||||
Upload Song
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
30
src/components/upload_dropdown.rs
Normal file
30
src/components/upload_dropdown.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use leptos::*;
|
||||
use leptos_icons::*;
|
||||
use crate::components::upload::*;
|
||||
use crate::components::add_artist::*;
|
||||
use crate::components::add_album::*;
|
||||
|
||||
#[component]
|
||||
pub fn UploadDropdownBtn(dropdown_open: RwSignal<bool>) -> impl IntoView {
|
||||
let open_dropdown = move |_| {
|
||||
dropdown_open.set(!dropdown_open.get());
|
||||
};
|
||||
view! {
|
||||
<button class={move || if dropdown_open() {"upload-dropdown-btn upload-dropdown-btn-active"} else {"upload-dropdown-btn"}} on:click=open_dropdown>
|
||||
<div class="add-sign">
|
||||
<Icon icon=icondata::IoAddSharp />
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn UploadDropdown(dropdown_open: RwSignal<bool>, upload_open: RwSignal<bool>, add_artist_open: RwSignal<bool>, add_album_open: RwSignal<bool>) -> impl IntoView {
|
||||
view! {
|
||||
<div class="upload-dropdown" on:click=move |_| dropdown_open.set(false)>
|
||||
<UploadBtn dialog_open=upload_open />
|
||||
<AddArtistBtn add_artist_open=add_artist_open/>
|
||||
<AddAlbumBtn add_album_open=add_album_open/>
|
||||
</div>
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ pub mod fileserv;
|
||||
pub mod error_template;
|
||||
pub mod upload;
|
||||
pub mod util;
|
||||
pub mod api;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
|
135
style/addAlbum.scss
Normal file
135
style/addAlbum.scss
Normal file
@ -0,0 +1,135 @@
|
||||
@import "theme.scss";
|
||||
|
||||
.add-album-container {
|
||||
position: fixed;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 30rem;
|
||||
height: 24rem;
|
||||
border: 1px solid white;
|
||||
border-radius: 5px;
|
||||
padding: 1rem;
|
||||
padding-top: 0;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #1c1c1c;
|
||||
z-index: 11;
|
||||
.upload-header {
|
||||
font-size: .7rem;
|
||||
font-weight: 300;
|
||||
padding-bottom: 0;
|
||||
border-bottom: 1px solid white;
|
||||
font-family: "Roboto", sans-serif;
|
||||
}
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
font-size: 1.6rem;
|
||||
transition: all 0.3s;
|
||||
border: none;
|
||||
|
||||
}
|
||||
.close-button:hover {
|
||||
transform: scale(1.1);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.close-button:active {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
.create-album-form {
|
||||
width:100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.input-bx{
|
||||
position: relative;
|
||||
margin-top: 1rem;
|
||||
width: 300px;
|
||||
input{
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #7f8fa6;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
font-size: 1rem;
|
||||
transition: 0.6s;
|
||||
background-color: transparent;
|
||||
}
|
||||
span{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1px;
|
||||
padding: 10px;
|
||||
font-size: 1rem;
|
||||
color: #7f8fa6;
|
||||
text-transform: uppercase;
|
||||
pointer-events: none;
|
||||
transition: 0.6s;
|
||||
background-color: transparent;
|
||||
}
|
||||
input:valid ~ span,
|
||||
input:focus ~ span{
|
||||
color: #fff;
|
||||
transform: translateX(10px) translateY(-7px);
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
padding: 0 10px;
|
||||
background: #1c1c1c;
|
||||
letter-spacing: 0.1rem;
|
||||
}
|
||||
input:valid,
|
||||
input:focus{
|
||||
color: #fff;
|
||||
border: 2px solid #fff;
|
||||
}
|
||||
|
||||
}
|
||||
.release-date {
|
||||
margin-top: 1rem;
|
||||
font-size: 1.2rem;
|
||||
color: #7f8fa6;
|
||||
font-family: "Roboto", sans-serif;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 5px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
span {
|
||||
font-size: .85rem;
|
||||
}
|
||||
input {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
.upload-button {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
margin-top: 1rem;
|
||||
padding: 10px;
|
||||
background-color: #7f8fa6;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
font-size: 1rem;
|
||||
font-family: "Roboto", sans-serif;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
color: #7f8fa6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
115
style/addArtist.scss
Normal file
115
style/addArtist.scss
Normal file
@ -0,0 +1,115 @@
|
||||
@import "theme.scss";
|
||||
|
||||
.add-artist-container {
|
||||
position: fixed;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 30rem;
|
||||
height: 15rem;
|
||||
border: 1px solid white;
|
||||
border-radius: 5px;
|
||||
padding: 1rem;
|
||||
padding-top: 0;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #1c1c1c;
|
||||
z-index: 11;
|
||||
.upload-header {
|
||||
font-size: .7rem;
|
||||
font-weight: 300;
|
||||
padding-bottom: 0;
|
||||
border-bottom: 1px solid white;
|
||||
font-family: "Roboto", sans-serif;
|
||||
}
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
font-size: 1.6rem;
|
||||
transition: all 0.3s;
|
||||
border: none;
|
||||
|
||||
}
|
||||
.close-button:hover {
|
||||
transform: scale(1.1);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.close-button:active {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
.create-artist-form {
|
||||
width:100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.input-bx{
|
||||
margin-top: 1rem;
|
||||
width: 300px;
|
||||
position: relative;
|
||||
input{
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #7f8fa6;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
font-size: 1rem;
|
||||
transition: 0.6s;
|
||||
background-color: transparent;
|
||||
}
|
||||
span{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1px;
|
||||
padding: 10px;
|
||||
font-size: 1rem;
|
||||
color: #7f8fa6;
|
||||
text-transform: uppercase;
|
||||
pointer-events: none;
|
||||
transition: 0.6s;
|
||||
background-color: transparent;
|
||||
}
|
||||
input:valid ~ span,
|
||||
input:focus ~ span{
|
||||
color: #fff;
|
||||
transform: translateX(10px) translateY(-7px);
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
padding: 0 10px;
|
||||
background: #1c1c1c;
|
||||
letter-spacing: 0.1rem;
|
||||
}
|
||||
input:valid,
|
||||
input:focus{
|
||||
color: #fff;
|
||||
border: 2px solid #fff;
|
||||
}
|
||||
|
||||
}
|
||||
.upload-button {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
margin-top: 1rem;
|
||||
padding: 10px;
|
||||
background-color: #7f8fa6;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
font-size: 1rem;
|
||||
font-family: "Roboto", sans-serif;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
color: #7f8fa6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
}
|
||||
.home-component {
|
||||
background: #1c1c1c;
|
||||
|
@ -9,6 +9,8 @@
|
||||
@import 'search.scss';
|
||||
@import 'personal.scss';
|
||||
@import 'upload.scss';
|
||||
@import 'addArtist.scss';
|
||||
@import 'addAlbum.scss';
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
|
@ -11,35 +11,71 @@
|
||||
margin: 3px;
|
||||
padding: 0.1rem 1rem 1rem 1rem;
|
||||
position: relative;
|
||||
.upload-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
}
|
||||
.header {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.upload-btn {
|
||||
.upload-dropdown-container {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 7px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.9rem;
|
||||
border-radius: 50px;
|
||||
border: none;
|
||||
height: 2.2rem;
|
||||
padding-right: 1rem;
|
||||
padding-left: 1rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
.add-sign {
|
||||
font-size: 1.5rem;
|
||||
margin-top: auto;
|
||||
margin-right: 5px;
|
||||
color: white;
|
||||
.upload-dropdown-btn {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
font-size: 0.9rem;
|
||||
border-radius: 50px;
|
||||
border: none;
|
||||
height: 2.2rem;
|
||||
padding-right: 1rem;
|
||||
padding-left: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
.add-sign {
|
||||
font-size: 1.5rem;
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
.upload-dropdown-btn:hover {
|
||||
background-color: #9e9e9e;
|
||||
}
|
||||
.upload-dropdown-btn-active {
|
||||
border-radius: 12.5px 12.5px 0 0;
|
||||
width: 110px;
|
||||
}
|
||||
.upload-dropdown {
|
||||
background-color: #f0ecec;
|
||||
color: black;
|
||||
width: 110px;
|
||||
border-radius: 0 0 5px 5px;
|
||||
.add-btns {
|
||||
border: none;
|
||||
border-bottom: 1px solid black;
|
||||
width: 100%;
|
||||
padding: 0.25rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.add-btns:first-child {
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
.add-btns:last-child {
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.upload-btn:hover {
|
||||
background-color: #9e9e9e;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
@ -15,6 +15,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #1c1c1c;
|
||||
z-index: 11;
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
@ -27,9 +28,7 @@
|
||||
font-size: 1.6rem;
|
||||
transition: all 0.3s;
|
||||
border: none;
|
||||
|
||||
}
|
||||
|
||||
.close-button:hover {
|
||||
transform: scale(1.1);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
@ -48,6 +47,9 @@
|
||||
padding: .1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.input-bx{
|
||||
margin-top: 1rem;
|
||||
position: relative;
|
||||
@ -126,6 +128,9 @@
|
||||
}
|
||||
}
|
||||
.upload-button {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
width: 100%;
|
||||
margin-top: 1rem;
|
||||
padding: 10px;
|
||||
background-color: #7f8fa6;
|
||||
|
Loading…
x
Reference in New Issue
Block a user