Compare commits
28 Commits
v1.0.2
...
feat_raw_r
| Author | SHA1 | Date | |
|---|---|---|---|
| 979ec4b576 | |||
| 12223347d3 | |||
| f9019ec508 | |||
| d52052de90 | |||
| 91defa42c2 | |||
| 2812d21782 | |||
| eb5a366a12 | |||
| 6b801d250f | |||
| 01fad1b9d4 | |||
| 371bea79f9 | |||
| 35725e1320 | |||
| d6a8c7d23f | |||
| 3c604e9593 | |||
| 43d8108270 | |||
| 1a883193d0 | |||
| 78b1970ba9 | |||
| 746d5dff96 | |||
| 8780ea8e63 | |||
| 8911eed0fb | |||
| 1a3652472e | |||
| 2e62577103 | |||
| 653e77160b | |||
| 3898a6bf4f | |||
| 448cf1569b | |||
| d3e2b3e601 | |||
| 8f026d47e1 | |||
| de17fc228d | |||
| 3434a48573 |
17
README.md
17
README.md
@@ -40,6 +40,23 @@ cd front
|
|||||||
pnpm run unlink_kar_cw
|
pnpm run unlink_kar_cw
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Tools in production mode
|
||||||
|
========================
|
||||||
|
|
||||||
|
Changing the Log Level
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
In a production environment, you can adjust the log level to help diagnose bugs more effectively.
|
||||||
|
|
||||||
|
The available log levels are:
|
||||||
|
| **Log Level Tag** | **org.kar.karusic** | **org.kar.archidata** | **other** |
|
||||||
|
| ----------------- | ------------------- | --------------------- | --------- |
|
||||||
|
| `prod` | INFO | INFO | INFO |
|
||||||
|
| `prod-debug` | DEBUG | INFO | INFO |
|
||||||
|
| `prod-trace` | TRACE | DEBUG | INFO |
|
||||||
|
| `prod-trace-full` | TRACE | TRACE | INFO |
|
||||||
|
| `dev` | TRACE | DEBUG | INFO |
|
||||||
|
|
||||||
|
|
||||||
Manual set in production:
|
Manual set in production:
|
||||||
=========================
|
=========================
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
FROM maven:3-openjdk-18 AS build
|
FROM maven:3-openjdk-23 AS build
|
||||||
|
|
||||||
COPY pom.xml /tmp/
|
COPY pom.xml /tmp/
|
||||||
COPY src /tmp/src/
|
COPY src /tmp/src/
|
||||||
|
COPY Formatter.xml /tmp/
|
||||||
WORKDIR /tmp/
|
WORKDIR /tmp/
|
||||||
RUN mvn clean compile assembly:single
|
RUN mvn clean compile assembly:single
|
||||||
|
|
||||||
|
|||||||
97
back/pom.xml
97
back/pom.xml
@@ -3,11 +3,11 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.kar</groupId>
|
<groupId>org.kar</groupId>
|
||||||
<artifactId>karusic</artifactId>
|
<artifactId>karusic</artifactId>
|
||||||
<version>1.0.2</version>
|
<version>1.1.1-SNAPSHOT</version>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.version>3.1</maven.compiler.version>
|
<maven.compiler.version>3.13.0</maven.compiler.version>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>23</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>23</maven.compiler.target>
|
||||||
<maven.dependency.version>3.1.1</maven.dependency.version>
|
<maven.dependency.version>3.1.1</maven.dependency.version>
|
||||||
</properties>
|
</properties>
|
||||||
<repositories>
|
<repositories>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>kangaroo-and-rabbit</groupId>
|
<groupId>kangaroo-and-rabbit</groupId>
|
||||||
<artifactId>archidata</artifactId>
|
<artifactId>archidata</artifactId>
|
||||||
<version>0.20.2</version>
|
<version>0.21.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Loopback of logger JDK logging API to SLF4J -->
|
<!-- Loopback of logger JDK logging API to SLF4J -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -39,10 +39,15 @@
|
|||||||
<artifactId>xercesImpl</artifactId>
|
<artifactId>xercesImpl</artifactId>
|
||||||
<version>2.12.2</version>
|
<version>2.12.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.janino</groupId>
|
||||||
|
<artifactId>janino</artifactId>
|
||||||
|
<version>3.1.9</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
<version>2.18.0-rc1</version>
|
<version>2.18.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--
|
<!--
|
||||||
************************************************************
|
************************************************************
|
||||||
@@ -108,7 +113,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
<version>3.2.1</version>
|
<version>4.0.0-beta-1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>attach-sources</id>
|
<id>attach-sources</id>
|
||||||
@@ -122,10 +127,12 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>3.0.0-M5</version>
|
<version>3.2.5</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.7.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
@@ -137,81 +144,21 @@
|
|||||||
</descriptorRefs>
|
</descriptorRefs>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Create coverage -->
|
|
||||||
<!--
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.jacoco</groupId>
|
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
|
||||||
<version>0.8.10</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>prepare-agent</id>
|
|
||||||
<goals>
|
|
||||||
<goal>prepare-agent</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>report</id>
|
|
||||||
<phase>test</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>report</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>jacoco-check</id>
|
|
||||||
<goals>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<rules>
|
|
||||||
<rule>
|
|
||||||
<element>PACKAGE</element>
|
|
||||||
<limits>
|
|
||||||
<limit>
|
|
||||||
<counter>LINE</counter>
|
|
||||||
<value>COVEREDRATIO</value>
|
|
||||||
<minimum>0.50</minimum>
|
|
||||||
</limit>
|
|
||||||
</limits>
|
|
||||||
</rule>
|
|
||||||
</rules>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
-->
|
|
||||||
<!-- Java-doc generation for stand-alone site -->
|
<!-- Java-doc generation for stand-alone site -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<show>private</show>
|
<show>private</show>
|
||||||
<nohelp>true</nohelp>
|
<nohelp>true</nohelp>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>exec-maven-plugin</artifactId>
|
|
||||||
<version>3.1.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>exec-application</id>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>java</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<mainClass>org.kar.karusic.WebLauncher</mainClass>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<!-- Check the style of the code -->
|
<!-- Check the style of the code -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>net.revelc.code.formatter</groupId>
|
<groupId>net.revelc.code.formatter</groupId>
|
||||||
<artifactId>formatter-maven-plugin</artifactId>
|
<artifactId>formatter-maven-plugin</artifactId>
|
||||||
<version>2.23.0</version>
|
<version>2.24.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<encoding>UTF-8</encoding>
|
<encoding>UTF-8</encoding>
|
||||||
<lineEnding>LF</lineEnding>
|
<lineEnding>LF</lineEnding>
|
||||||
@@ -242,14 +189,6 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
|
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
|
||||||
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
|
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
|
||||||
<!--<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.h3xstream.findsecbugs</groupId>
|
|
||||||
<artifactId>findsecbugs-plugin</artifactId>
|
|
||||||
<version>1.12.0</version>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
-->
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
@@ -260,7 +199,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<show>public</show>
|
<show>public</show>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
package org.kar.karusic.internal;
|
|
||||||
|
|
||||||
//import io.scenarium.logger.LogLevel;
|
|
||||||
//import io.scenarium.logger.Logger;
|
|
||||||
|
|
||||||
public class Log {
|
|
||||||
// private static final String LIB_NAME = "logger";
|
|
||||||
// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME);
|
|
||||||
// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL);
|
|
||||||
// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR);
|
|
||||||
// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING);
|
|
||||||
// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO);
|
|
||||||
// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG);
|
|
||||||
// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE);
|
|
||||||
// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO);
|
|
||||||
// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT);
|
|
||||||
//
|
|
||||||
// private Log() {}
|
|
||||||
//
|
|
||||||
// public static void print(String data) {
|
|
||||||
// if (PRINT_PRINT)
|
|
||||||
// Logger.print(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void todo(String data) {
|
|
||||||
// if (PRINT_TODO)
|
|
||||||
// Logger.todo(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void critical(String data) {
|
|
||||||
// if (PRINT_CRITICAL)
|
|
||||||
// Logger.critical(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void error(String data) {
|
|
||||||
// if (PRINT_ERROR)
|
|
||||||
// Logger.error(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void warning(String data) {
|
|
||||||
// if (PRINT_WARNING)
|
|
||||||
// Logger.warning(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void info(String data) {
|
|
||||||
// if (PRINT_INFO)
|
|
||||||
// Logger.info(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void debug(String data) {
|
|
||||||
// if (PRINT_DEBUG)
|
|
||||||
// Logger.debug(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void verbose(String data) {
|
|
||||||
// if (PRINT_VERBOSE)
|
|
||||||
// Logger.verbose(LIB_NAME_DRAW, data);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -25,14 +25,10 @@ public class Initialization extends MigrationSqlStep {
|
|||||||
return "Initialization";
|
return "Initialization";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Initialization() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateStep() throws Exception {
|
public void generateStep() throws Exception {
|
||||||
for (final Class<?> elem : CLASSES_BASE) {
|
for (final Class<?> clazz : CLASSES_BASE) {
|
||||||
addClass(elem);
|
addClass(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAction((final DBAccess da) -> {
|
addAction((final DBAccess da) -> {
|
||||||
@@ -63,6 +59,7 @@ public class Initialization extends MigrationSqlStep {
|
|||||||
new Gender(24L, "Bande Originale"), //
|
new Gender(24L, "Bande Originale"), //
|
||||||
new Gender(25L, "Variété Belge"), //
|
new Gender(25L, "Variété Belge"), //
|
||||||
new Gender(26L, "Gospel"));
|
new Gender(26L, "Gospel"));
|
||||||
|
da.insertMultiple(data);
|
||||||
});
|
});
|
||||||
// set start increment element to permit to add after default elements
|
// set start increment element to permit to add after default elements
|
||||||
addAction("""
|
addAction("""
|
||||||
|
|||||||
@@ -1,18 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
<!-- environment detection (defaut: dev) -->
|
||||||
<encoder>
|
<property name="LOG_LEVEL_ENV" value="${LOG_LEVEL:-dev}" />
|
||||||
<pattern>
|
<!-- Appender for development -->
|
||||||
%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %logger - %msg%n
|
<if condition="property("LOG_LEVEL_ENV").equals("dev")">
|
||||||
</pattern>
|
<then>
|
||||||
<!--
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<pattern>
|
<encoder>
|
||||||
%d{HH:mm:ss.SSS} | %thread | %highlight(%-5level) | %logger - %msg%n
|
<pattern>%green(%d{HH:mm:ss.SSS}) %highlight(%-5level) %-30((%file:%line\)): %msg%n</pattern>
|
||||||
</pattern>
|
</encoder>
|
||||||
-->
|
</appender>
|
||||||
</encoder>
|
<logger name="org.kar.karusic" level="TRACE" />
|
||||||
</appender>
|
<logger name="org.kar.archidata" level="DEBUG" />
|
||||||
|
<root level="INFO">
|
||||||
<root level="info">
|
<appender-ref ref="CONSOLE" />
|
||||||
<appender-ref ref="CONSOLE" />
|
</root>
|
||||||
</root>
|
</then>
|
||||||
|
</if>
|
||||||
|
<!-- Appender for production -->
|
||||||
|
<if condition="property("LOG_LEVEL_ENV").matches("^prod.*")">
|
||||||
|
<then>
|
||||||
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%thread] %level %logger - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
</root>
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
<if condition="property("LOG_LEVEL_ENV").equals("prod-debug")">
|
||||||
|
<then>
|
||||||
|
<logger name="org.kar.karusic" level="DEBUG" />
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
<if condition="property("LOG_LEVEL_ENV").equals("prod-trace")">
|
||||||
|
<then>
|
||||||
|
<logger name="org.kar.karusic" level="TRACE" />
|
||||||
|
<logger name="org.kar.archidata" level="DEBUG" />
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
|
<if condition="property("LOG_LEVEL_ENV").equals("prod-trace-full")">
|
||||||
|
<then>
|
||||||
|
<logger name="org.kar.karusic" level="TRACE" />
|
||||||
|
<logger name="org.kar.archidata" level="TRACE" />
|
||||||
|
</then>
|
||||||
|
</if>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# SLF4J's SimpleLogger configuration file
|
|
||||||
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
|
|
||||||
# Default logging detail level for all instances of SimpleLogger.
|
|
||||||
# Must be one of ("trace", "debug", "info", "warn", or "error").
|
|
||||||
# If not specified, defaults to "info".
|
|
||||||
org.slf4j.simpleLogger.defaultLogLevel=INFO
|
|
||||||
|
|
||||||
# Logging detail level for a SimpleLogger instance named "xxxxx".
|
|
||||||
# Must be one of ("trace", "debug", "info", "warn", or "error").
|
|
||||||
# If not specified, the default logging detail level is used.
|
|
||||||
#org.slf4j.simpleLogger.log.xxxxx=
|
|
||||||
org.slf4j.simpleLogger.log.org.kar.archidata=TRACE
|
|
||||||
org.slf4j.simpleLogger.log.org.kar.karusic=TRACE
|
|
||||||
|
|
||||||
# Set to true if you want the current date and time to be included in output messages.
|
|
||||||
# Default is false, and will output the number of milliseconds elapsed since startup.
|
|
||||||
#org.slf4j.simpleLogger.showDateTime=false
|
|
||||||
|
|
||||||
# The date and time format to be used in the output messages.
|
|
||||||
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
|
|
||||||
# If the format is not specified or is invalid, the default format is used.
|
|
||||||
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
|
|
||||||
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z
|
|
||||||
|
|
||||||
# Set to true if you want to output the current thread name.
|
|
||||||
# Defaults to true.
|
|
||||||
org.slf4j.simpleLogger.showThreadName=true
|
|
||||||
|
|
||||||
# Set to true if you want the Logger instance name to be included in output messages.
|
|
||||||
# Defaults to true.
|
|
||||||
#org.slf4j.simpleLogger.showLogName=true
|
|
||||||
|
|
||||||
# Set to true if you want the last component of the name to be included in output messages.
|
|
||||||
# Defaults to false.
|
|
||||||
#org.slf4j.simpleLogger.showShortLogName=false
|
|
||||||
|
|
||||||
# Utilise les codes ANSI pour la couleur
|
|
||||||
org.slf4j.simpleLogger.warnColor=\u001B[33m
|
|
||||||
org.slf4j.simpleLogger.errorColor=\u001B[31m
|
|
||||||
org.slf4j.simpleLogger.infoColor=\u001B[32m
|
|
||||||
org.slf4j.simpleLogger.debugColor=\u001B[34m
|
|
||||||
|
|
||||||
@@ -35,6 +35,10 @@ public class ConfigureDb {
|
|||||||
if (modeTestForced != null) {
|
if (modeTestForced != null) {
|
||||||
modeTest = modeTestForced;
|
modeTest = modeTestForced;
|
||||||
}
|
}
|
||||||
|
// for local test:
|
||||||
|
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12342/test/api/";
|
||||||
|
// Enable the test mode permit to access to the test token (never use it in production).
|
||||||
|
ConfigBaseVariable.testMode = "true";
|
||||||
final List<Class<?>> listObject = List.of( //
|
final List<Class<?>> listObject = List.of( //
|
||||||
Album.class, //
|
Album.class, //
|
||||||
Artist.class, //
|
Artist.class, //
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ public class TestBase {
|
|||||||
ConfigureDb.configure();
|
ConfigureDb.configure();
|
||||||
LOGGER.info("configure server ...");
|
LOGGER.info("configure server ...");
|
||||||
webInterface = new WebLauncherTest();
|
webInterface = new WebLauncherTest();
|
||||||
LOGGER.info("Clean previous table");
|
|
||||||
|
|
||||||
LOGGER.info("Start REST (BEGIN)");
|
LOGGER.info("Start REST (BEGIN)");
|
||||||
webInterface.process();
|
webInterface.process();
|
||||||
LOGGER.info("Start REST (DONE)");
|
LOGGER.info("Start REST (DONE)");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"display": "2025-01-06",
|
"display": "2025-01-14",
|
||||||
"version": "0.0.1-dev\n - 2025-01-06T00:49:52+01:00",
|
"version": "0.0.1-dev\n - 2025-01-14T20:19:20+01:00",
|
||||||
"commit": "0.0.1-dev\n",
|
"commit": "0.0.1-dev\n",
|
||||||
"date": "2025-01-06T00:49:52+01:00"
|
"date": "2025-01-14T20:19:20+01:00"
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"update_packages": "ncu --upgrade",
|
"update_packages": "ncu --target minor",
|
||||||
|
"upgrade_packages": "ncu --upgrade ",
|
||||||
"install_dependency": "pnpm install",
|
"install_dependency": "pnpm install",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:watch": "vitest watch",
|
"test:watch": "vitest watch",
|
||||||
@@ -28,46 +29,18 @@
|
|||||||
"*.{ts,tsx,js,jsx,json}": "prettier --write"
|
"*.{ts,tsx,js,jsx,json}": "prettier --write"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chakra-ui/anatomy": "2.2.2",
|
|
||||||
"@chakra-ui/cli": "2.4.1",
|
|
||||||
"@chakra-ui/react": "2.8.2",
|
|
||||||
"@chakra-ui/theme-tools": "2.2.6",
|
|
||||||
"@dnd-kit/core": "6.3.1",
|
|
||||||
"@dnd-kit/modifiers": "9.0.0",
|
|
||||||
"@dnd-kit/sortable": "10.0.0",
|
|
||||||
"@dnd-kit/utilities": "3.2.2",
|
|
||||||
"@emotion/react": "11.14.0",
|
|
||||||
"@emotion/styled": "11.14.0",
|
|
||||||
"@formiz/core": "2.4.5",
|
|
||||||
"@formiz/validations": "2.0.1",
|
|
||||||
"allotment": "1.20.2",
|
|
||||||
"css-mediaquery": "0.1.2",
|
|
||||||
"dayjs": "1.11.13",
|
|
||||||
"history": "5.3.0",
|
"history": "5.3.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-color-palette": "7.3.0",
|
|
||||||
"react-currency-input-field": "3.9.0",
|
|
||||||
"react-custom-scrollbars": "4.2.1",
|
|
||||||
"react-day-picker": "9.5.0",
|
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-error-boundary": "4.0.13",
|
"react-error-boundary": "5.0.0",
|
||||||
"react-focus-lock": "2.13.2",
|
"react-icons": "5.4.0",
|
||||||
"react-icons": "5.3.0",
|
"react-router-dom": "7.1.1",
|
||||||
"react-popper": "2.3.0",
|
|
||||||
"react-router-dom": "6.26.2",
|
|
||||||
"react-select": "5.9.0",
|
"react-select": "5.9.0",
|
||||||
"react-simple-keyboard": "3.8.33",
|
|
||||||
"react-sticky-el": "2.1.1",
|
|
||||||
"react-use": "17.6.0",
|
"react-use": "17.6.0",
|
||||||
"react-use-draggable-scroll": "0.4.7",
|
|
||||||
"react-virtuoso": "4.12.3",
|
|
||||||
"ts-pattern": "5.6.0",
|
|
||||||
"uuid": "11.0.4",
|
|
||||||
"zod": "3.24.1",
|
"zod": "3.24.1",
|
||||||
"zustand": "5.0.2"
|
"zustand": "5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@chakra-ui/styled-system": "2.12.0",
|
|
||||||
"@playwright/test": "1.49.1",
|
"@playwright/test": "1.49.1",
|
||||||
"@storybook/addon-actions": "8.4.7",
|
"@storybook/addon-actions": "8.4.7",
|
||||||
"@storybook/addon-essentials": "8.4.7",
|
"@storybook/addon-essentials": "8.4.7",
|
||||||
@@ -81,30 +54,28 @@
|
|||||||
"@testing-library/user-event": "14.5.2",
|
"@testing-library/user-event": "14.5.2",
|
||||||
"@trivago/prettier-plugin-sort-imports": "5.2.1",
|
"@trivago/prettier-plugin-sort-imports": "5.2.1",
|
||||||
"@types/jest": "29.5.14",
|
"@types/jest": "29.5.14",
|
||||||
"@types/node": "22.10.5",
|
"@types/node": "22.10.6",
|
||||||
"@types/react": "18.3.8",
|
"@types/react": "18.3.8",
|
||||||
"@types/react-dom": "18.3.0",
|
"@types/react-dom": "18.3.0",
|
||||||
"@types/react-sticky-el": "1.0.7",
|
"@typescript-eslint/eslint-plugin": "8.20.0",
|
||||||
"@typescript-eslint/eslint-plugin": "8.19.0",
|
"@typescript-eslint/parser": "8.20.0",
|
||||||
"@typescript-eslint/parser": "8.19.0",
|
|
||||||
"@vitejs/plugin-react": "4.3.4",
|
"@vitejs/plugin-react": "4.3.4",
|
||||||
"eslint": "9.17.0",
|
"eslint": "9.18.0",
|
||||||
"eslint-plugin-codeceptjs": "1.3.0",
|
"eslint-plugin-codeceptjs": "1.3.0",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
"eslint-plugin-react": "7.37.3",
|
"eslint-plugin-react": "7.37.4",
|
||||||
"eslint-plugin-react-hooks": "5.1.0",
|
"eslint-plugin-react-hooks": "5.1.0",
|
||||||
"eslint-plugin-storybook": "0.11.2",
|
"eslint-plugin-storybook": "0.11.2",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-environment-jsdom": "29.7.0",
|
"jest-environment-jsdom": "29.7.0",
|
||||||
"knip": "5.41.1",
|
"knip": "5.42.0",
|
||||||
"lint-staged": "15.3.0",
|
"lint-staged": "15.3.0",
|
||||||
"npm-check-updates": "^17.1.13",
|
"npm-check-updates": "^17.1.13",
|
||||||
"prettier": "3.4.2",
|
"prettier": "3.4.2",
|
||||||
"puppeteer": "23.11.1",
|
|
||||||
"react-is": "19.0.0",
|
"react-is": "19.0.0",
|
||||||
"storybook": "8.4.7",
|
"storybook": "8.4.7",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "10.9.2",
|
||||||
"typescript": "5.7.2",
|
"typescript": "5.7.3",
|
||||||
"vite": "6.0.7",
|
"vite": "6.0.7",
|
||||||
"vitest": "2.1.8"
|
"vitest": "2.1.8"
|
||||||
}
|
}
|
||||||
|
|||||||
3447
front/pnpm-lock.yaml
generated
3447
front/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,13 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
import { ChakraProvider, Select } from '@chakra-ui/react';
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { environment } from '@/environment';
|
|
||||||
import { App as SpaApp } from '@/scene/App';
|
import { App as SpaApp } from '@/scene/App';
|
||||||
import { USERS } from '@/service/session';
|
import { Div, FullPage } from './ui';
|
||||||
import theme from '@/theme';
|
import { useDisclosure } from './utils/disclosure';
|
||||||
import { hashLocalData } from '@/utils/sso';
|
import { useState } from 'react';
|
||||||
|
import { environment } from './environment';
|
||||||
|
import { hashLocalData } from './utils/sso';
|
||||||
|
import { USERS } from './service/session';
|
||||||
|
|
||||||
const AppEnvHint = () => {
|
const AppEnvHint = () => {
|
||||||
const modal = useDisclosure();
|
const dialog = useDisclosure();
|
||||||
const [selectUserTest, setSelectUserTest] = useState<string>('NO_USER');
|
const [selectUserTest, setSelectUserTest] = useState<string>('NO_USER');
|
||||||
//const setUser = useRightsStore((store) => store.setUser);
|
//const setUser = useRightsStore((store) => store.setUser);
|
||||||
const buildEnv =
|
const buildEnv =
|
||||||
@@ -40,7 +24,7 @@ const AppEnvHint = () => {
|
|||||||
setSelectUserTest(selectedOption.target.value);
|
setSelectUserTest(selectedOption.target.value);
|
||||||
};
|
};
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
modal.onClose();
|
dialog.onClose();
|
||||||
if (selectUserTest == 'NO_USER') {
|
if (selectUserTest == 'NO_USER') {
|
||||||
window.location.href = `/${environment.applName}/sso/${hashLocalData()}/false/__LOGOUT__`;
|
window.location.href = `/${environment.applName}/sso/${hashLocalData()}/false/__LOGOUT__`;
|
||||||
} else {
|
} else {
|
||||||
@@ -50,68 +34,82 @@ const AppEnvHint = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Div style={{
|
||||||
zIndex="100000"
|
zIndex: "100000",
|
||||||
position="fixed"
|
position: "fixed",
|
||||||
top="0"
|
top: "0",
|
||||||
insetStart="0"
|
height: "2px",
|
||||||
insetEnd="0"
|
width: "100%",
|
||||||
h="2px"
|
background: "warning.400",
|
||||||
bg="warning.400"
|
cursor: "pointer"
|
||||||
as="button"
|
}}
|
||||||
cursor="pointer"
|
|
||||||
data-test-id="devtools"
|
data-test-id="devtools"
|
||||||
onClick={modal.onOpen}
|
onClick={dialog.onOpen}
|
||||||
>
|
>
|
||||||
<Text
|
<Div style={{
|
||||||
position="fixed"
|
position: "fixed",
|
||||||
top="0"
|
top: "0",
|
||||||
insetStart="4"
|
background: "warning.400",
|
||||||
bg="warning.400"
|
color: "warning.900",
|
||||||
color="warning.900"
|
fontSize: "0.6rem",
|
||||||
fontSize="0.6rem"
|
fontWeight: "bold",
|
||||||
fontWeight="bold"
|
paddingLeft: "10px",
|
||||||
px="10px"
|
paddingRight: "10px",
|
||||||
marginLeft="25%"
|
marginLeft: "25%",
|
||||||
borderBottomStartRadius="sm"
|
borderRadius: "0 0 10px 10px",
|
||||||
borderBottomEndRadius="sm"
|
textTransform: "uppercase",
|
||||||
textTransform="uppercase"
|
}}
|
||||||
>
|
>
|
||||||
{envName.join(' : ')}
|
{envName.join(' : ')}
|
||||||
</Text>
|
</Div>
|
||||||
</Box>
|
</Div>
|
||||||
<Modal isOpen={modal.isOpen} onClose={modal.onClose}>
|
{/* <Dialog.Root open={dialog.open} onOpenChange={dialog.onClose}>
|
||||||
<ModalOverlay />
|
<Dialog.Trigger asChild>
|
||||||
<ModalContent>
|
<Button>
|
||||||
<ModalHeader>Outils développeurs</ModalHeader>
|
{dialog.open ? "Close" : "Open"} Dialog
|
||||||
<ModalCloseButton />
|
</Button>
|
||||||
<ModalBody>
|
</Dialog.Trigger>
|
||||||
<Stack>
|
<Portal>
|
||||||
<Text>Utilisateur</Text>
|
<Dialog.Backdrop />
|
||||||
<Select placeholder="Select test user" onChange={handleChange}>
|
<Dialog.Positioner>
|
||||||
{Object.keys(USERS).map((key) => (
|
<Dialog.Content>
|
||||||
<option value={key} key={key}>
|
<Dialog.Title>Outils développeurs</Dialog.Title>
|
||||||
{key}
|
<Dialog.Description>
|
||||||
</option>
|
<HStack>
|
||||||
))}
|
<Text>User</Text>
|
||||||
</Select>
|
<Select.Root onChange={handleChange} collection={USERS_COLLECTION}>
|
||||||
</Stack>
|
<Select.Trigger>
|
||||||
</ModalBody>
|
<SelectValueText placeholder="Select test user" />
|
||||||
<ModalFooter>
|
</Select.Trigger>
|
||||||
<Button onClick={onClose}>Apply</Button>
|
<Select.Content>
|
||||||
</ModalFooter>
|
{USERS_COLLECTION.items.map((value) => (
|
||||||
</ModalContent>
|
<Select.Item item={value} key={value.value}>
|
||||||
</Modal>
|
{value.label}
|
||||||
|
</Select.Item>
|
||||||
|
))}
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
</HStack>
|
||||||
|
</Dialog.Description>
|
||||||
|
<Dialog.CloseTrigger>
|
||||||
|
<Button onClick={onClose}>Apply</Button>
|
||||||
|
</Dialog.CloseTrigger>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Positioner>
|
||||||
|
</Portal>
|
||||||
|
</Dialog.Root> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChakraProvider theme={theme}>
|
<FullPage data-test-id="Full-root-page">
|
||||||
<AppEnvHint />
|
<AppEnvHint />
|
||||||
<SpaApp />
|
<SpaApp data-test-id="app" />
|
||||||
</ChakraProvider>
|
{/* <Toaster /> */}
|
||||||
|
</FullPage>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
*/
|
*/
|
||||||
import { z as zod } from "zod";
|
import { z as zod } from "zod";
|
||||||
|
|
||||||
import {ZodUUID} from "./uuid";
|
import {ZodObjectId} from "./object-id";
|
||||||
import {ZodInteger} from "./integer";
|
import {ZodInteger} from "./integer";
|
||||||
|
|
||||||
export const ZodRestErrorResponse = zod.object({
|
export const ZodRestErrorResponse = zod.object({
|
||||||
uuid: ZodUUID.optional(),
|
oid: ZodObjectId.optional(),
|
||||||
name: zod.string(),
|
name: zod.string(),
|
||||||
message: zod.string(),
|
message: zod.string(),
|
||||||
time: zod.string(),
|
time: zod.string(),
|
||||||
|
|||||||
@@ -1,26 +1,13 @@
|
|||||||
import { SyntheticEvent, useEffect, useRef, useState } from 'react';
|
import { SyntheticEvent, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
IconButton,
|
|
||||||
Slider,
|
|
||||||
SliderFilledTrack,
|
|
||||||
SliderThumb,
|
|
||||||
SliderTrack,
|
|
||||||
Text,
|
|
||||||
position,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
|
||||||
MdCheck,
|
|
||||||
MdFastForward,
|
MdFastForward,
|
||||||
MdFastRewind,
|
MdFastRewind,
|
||||||
MdGraphicEq,
|
MdGraphicEq,
|
||||||
MdLooksOne,
|
MdLooksOne,
|
||||||
MdNavigateBefore,
|
MdNavigateBefore,
|
||||||
MdNavigateNext,
|
MdNavigateNext,
|
||||||
MdOutlinePlayArrow,
|
|
||||||
MdPause,
|
MdPause,
|
||||||
MdPlayArrow,
|
MdPlayArrow,
|
||||||
MdRepeat,
|
MdRepeat,
|
||||||
@@ -35,8 +22,10 @@ import { useSpecificArtists } from '@/service/Artist';
|
|||||||
import { useSpecificGender } from '@/service/Gender';
|
import { useSpecificGender } from '@/service/Gender';
|
||||||
import { useSpecificTrack } from '@/service/Track';
|
import { useSpecificTrack } from '@/service/Track';
|
||||||
import { DataUrlAccess } from '@/utils/data-url-access';
|
import { DataUrlAccess } from '@/utils/data-url-access';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { Icon } from './Icon';
|
||||||
|
import { Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export enum PlayMode {
|
export enum PlayMode {
|
||||||
PLAY_ONE,
|
PLAY_ONE,
|
||||||
@@ -65,8 +54,7 @@ const formatTime = (time) => {
|
|||||||
return '00:00';
|
return '00:00';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AudioPlayer = ({}: AudioPlayerProps) => {
|
export const AudioPlayer = ({ }: AudioPlayerProps) => {
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const { playTrackList, trackOffset, previous, next, first } =
|
const { playTrackList, trackOffset, previous, next, first } =
|
||||||
useActivePlaylistService();
|
useActivePlaylistService();
|
||||||
const audioRef = useRef<HTMLAudioElement>(null);
|
const audioRef = useRef<HTMLAudioElement>(null);
|
||||||
@@ -89,14 +77,17 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
|
|||||||
: ''
|
: ''
|
||||||
);
|
);
|
||||||
}, [dataTrack, setMediaSource]);
|
}, [dataTrack, setMediaSource]);
|
||||||
const backColor = mode('back.100', 'back.800');
|
const backColor = useColorThemeValue('back.100', 'back.800');
|
||||||
const configButton = {
|
const configButton = {
|
||||||
borderRadius: 'full',
|
borderRadius: 'full',
|
||||||
backgroundColor: '#00000000',
|
background: '#00000000',
|
||||||
_hover: {
|
_hover: {
|
||||||
boxShadow: 'outline-over',
|
boxShadow: 'outline-over',
|
||||||
bgColor: 'brand.500',
|
bgColor: 'brand.500',
|
||||||
},
|
},
|
||||||
|
width: "50px",
|
||||||
|
height: "50px",
|
||||||
|
padding: "5px",
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -202,7 +193,7 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
|
|||||||
console.log(`onTimeUpdate ${audioRef.current.currentTime}`);
|
console.log(`onTimeUpdate ${audioRef.current.currentTime}`);
|
||||||
setTimeProgress(audioRef.current.currentTime);
|
setTimeProgress(audioRef.current.currentTime);
|
||||||
};
|
};
|
||||||
const onDurationChange = (event) => {};
|
const onDurationChange = (event) => { };
|
||||||
const onChangeStateToPlay = () => {
|
const onChangeStateToPlay = () => {
|
||||||
setIsPlaying(true);
|
setIsPlaying(true);
|
||||||
};
|
};
|
||||||
@@ -213,131 +204,129 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
|
|||||||
<>
|
<>
|
||||||
{!isNullOrUndefined(trackOffset) && (
|
{!isNullOrUndefined(trackOffset) && (
|
||||||
<Flex
|
<Flex
|
||||||
position="absolute"
|
style={{
|
||||||
height="150px"
|
position: "absolute",
|
||||||
minHeight="150px"
|
height: "150px",
|
||||||
paddingY="5px"
|
minHeight: "150px",
|
||||||
paddingX="10px"
|
padding: "5px 10px 5px 10px",
|
||||||
marginX="15px"
|
margin: "0 15px 0 15px",
|
||||||
bottom={0}
|
bottom: 0,
|
||||||
left={0}
|
left: 0,
|
||||||
right={0}
|
right: 0,
|
||||||
zIndex={1000}
|
zIndex: 1000,
|
||||||
borderWidth="1px"
|
borderWidth: "1px",
|
||||||
borderColor="brand.900"
|
borderColor: "brand.900",
|
||||||
bgColor={backColor}
|
background: backColor,
|
||||||
borderTopRadius="10px"
|
borderRadius: "10px 10px 0 0",
|
||||||
|
}}
|
||||||
direction="column"
|
direction="column"
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
align="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
style={{
|
||||||
marginRight="auto"
|
alignContent: "left",
|
||||||
overflow="hidden"
|
userSelect: "none",
|
||||||
noOfLines={1}
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
// noOfLines={1}
|
||||||
>
|
>
|
||||||
{dataTrack?.name ?? '???'}
|
{dataTrack?.name ?? '???'}
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
align="left"
|
|
||||||
fontSize="16px"
|
fontSize="16px"
|
||||||
userSelect="none"
|
style={{
|
||||||
marginRight="auto"
|
alignContent: "left",
|
||||||
overflow="hidden"
|
userSelect: "none",
|
||||||
noOfLines={1}
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
//noOfLines:1
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{dataArtists.map((data) => data.name).join(', ')} /{' '}
|
{dataArtists.map((data) => data.name).join(', ')} /{' '}
|
||||||
{dataAlbum && dataAlbum?.name}
|
{dataAlbum && dataAlbum?.name}
|
||||||
{dataGender && ` / ${dataGender.name}`}
|
{dataGender && ` / ${dataGender.name}`}
|
||||||
</Text>
|
</Text>
|
||||||
<Box width="full" paddingX="15px">
|
<Flex style={{ width: "100%", padding: "0 15px 0 15px" }}>
|
||||||
<Slider
|
<>TODO ... </>
|
||||||
aria-label="slider-ex-4"
|
{/* <Slider.Root
|
||||||
defaultValue={0}
|
defaultValue={[0]}
|
||||||
value={timeProgress}
|
value={[timeProgress]}
|
||||||
min={0}
|
min={0}
|
||||||
max={duration}
|
max={duration}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
onChange={onSeek}
|
onChange={onSeek}
|
||||||
focusThumbOnChange={false}
|
variant="outline"
|
||||||
|
// focusThumbOnChange={false}
|
||||||
>
|
>
|
||||||
<SliderTrack bg="gray.200" height="10px" borderRadius="full">
|
<SliderTrack bg="gray.200" height="10px" borderRadius="full">
|
||||||
<SliderFilledTrack bg="brand.600" />
|
{/ * <SliderFilledTrack bg="brand.600" /> * /}
|
||||||
</SliderTrack>
|
</SliderTrack>
|
||||||
<SliderThumb boxSize={6}>
|
</Slider.Root> */}
|
||||||
<Box color="brand.600" as={MdGraphicEq} />
|
</Flex>
|
||||||
</SliderThumb>
|
|
||||||
</Slider>
|
|
||||||
</Box>
|
|
||||||
<Flex>
|
<Flex>
|
||||||
<Text
|
<Text
|
||||||
align="left"
|
|
||||||
fontSize="16px"
|
fontSize="16px"
|
||||||
userSelect="none"
|
style={{
|
||||||
marginRight="auto"
|
alignContent: "left",
|
||||||
overflow="hidden"
|
userSelect: "none",
|
||||||
noOfLines={1}
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// noOfLines={1},
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{formatTime(timeProgress)}
|
{formatTime(timeProgress)}
|
||||||
</Text>
|
</Text>
|
||||||
<Text align="left" fontSize="16px" userSelect="none">
|
<Text fontSize="16px" style={{ alignContent: "left", userSelect: "none" }}>
|
||||||
{formatTime(duration)}
|
{formatTime(duration)}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex gap="5px">
|
{/* <Flex gap="5px">
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
aria-label={'Play'}
|
aria-label={'Play'}
|
||||||
icon={
|
|
||||||
isPlaying ? (
|
|
||||||
<MdPause size="30px" />
|
|
||||||
) : (
|
|
||||||
<MdPlayArrow size="30px" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onClick={onPlay}
|
onClick={onPlay}
|
||||||
/>
|
>
|
||||||
|
{isPlaying ? (
|
||||||
|
<MdPause size="30px" />
|
||||||
|
) : (
|
||||||
|
<MdPlayArrow size="30px" />
|
||||||
|
)}
|
||||||
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
aria-label={'Stop'}
|
aria-label={'Stop'}
|
||||||
icon={<MdStop size="30px" />}
|
|
||||||
onClick={onStop}
|
onClick={onStop}
|
||||||
/>
|
><MdStop size="30px" /></IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
aria-label={'Previous track'}
|
aria-label={'Previous track'}
|
||||||
icon={<MdNavigateBefore size="30px" />}
|
|
||||||
onClick={onNavigatePrevious}
|
onClick={onNavigatePrevious}
|
||||||
marginLeft="auto"
|
marginLeft="auto"
|
||||||
/>
|
><MdNavigateBefore size="30px" /> </IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
aria-label={'jump 15sec in past'}
|
aria-label={'jump 15sec in past'}
|
||||||
icon={<MdFastRewind size="30px" />}
|
|
||||||
onClick={onFastRewind}
|
onClick={onFastRewind}
|
||||||
/>
|
><MdFastRewind size="30px" /></IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
aria-label={'jump 15sec in future'}
|
aria-label={'jump 15sec in future'}
|
||||||
icon={<MdFastForward size="30px" />}
|
|
||||||
onClick={onFastForward}
|
onClick={onFastForward}
|
||||||
/>
|
><MdFastForward style={{ width: "100%", height: "100%" }} /></IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
aria-label={'Next track'}
|
aria-label={'Next track'}
|
||||||
icon={<MdNavigateNext size="30px" />}
|
|
||||||
marginRight="auto"
|
marginRight="auto"
|
||||||
onClick={onNavigateNext}
|
onClick={onNavigateNext}
|
||||||
/>
|
><MdNavigateNext style={{ width: "100%", height: "100%" }} /></IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
aria-label={'continue to the end'}
|
aria-label={'continue to the end'}
|
||||||
icon={playModeIcon[playingMode]}
|
|
||||||
onClick={onTypePlay}
|
onClick={onTypePlay}
|
||||||
/>
|
>{playModeIcon[playingMode]}</IconButton>
|
||||||
</Flex>
|
</Flex> */}
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { ReactElement, useEffect, useState } from 'react';
|
import { CSSProperties, ReactElement, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { As, Box, BoxProps, Flex, StyleProps } from '@chakra-ui/react';
|
|
||||||
import { Image } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { DataUrlAccess } from '@/utils/data-url-access';
|
import { DataUrlAccess } from '@/utils/data-url-access';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
import { ObjectId } from '@/back-api';
|
import { ObjectId } from '@/back-api';
|
||||||
|
import { DivProps, Flex } from '@/ui';
|
||||||
|
|
||||||
export type CoversProps = BoxProps & {
|
export type CoversProps = Omit<DivProps, "iconEmpty"> & {
|
||||||
data?: ObjectId[];
|
data?: ObjectId[];
|
||||||
size?: StyleProps["width"];
|
size?: CSSProperties["width"];
|
||||||
iconEmpty?: As;
|
iconEmpty?: ReactElement;
|
||||||
slideshow?: boolean;
|
slideshow?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,26 +43,34 @@ export const Covers = ({
|
|||||||
return <Icon icon={iconEmpty} sizeIcon={size} />;
|
return <Icon icon={iconEmpty} sizeIcon={size} />;
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Flex
|
||||||
width={size}
|
style={{
|
||||||
height={size}
|
width: size,
|
||||||
minHeight={size}
|
height: size,
|
||||||
minWidth={size}
|
minHeight: size,
|
||||||
borderColor="blue"
|
minWidth: size,
|
||||||
borderWidth="1px"
|
borderColor: "blue",
|
||||||
margin="auto"
|
borderWidth: "1px",
|
||||||
|
margin: "auto",
|
||||||
|
}}
|
||||||
{...rest}
|
{...rest}
|
||||||
></Box>
|
></Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (slideshow === false || data.length === 1) {
|
if (slideshow === false || data.length === 1) {
|
||||||
const url = DataUrlAccess.getThumbnailUrl(data[0]);
|
const url = DataUrlAccess.getThumbnailUrl(data[0]);
|
||||||
return <Image loading="lazy" src={url} maxWidth={size} boxSize={size} {...rest} />;
|
return <></>;//<image loading="lazy" src={url} maxWidth={size} boxSize={size} /*{...rest}*/ />;
|
||||||
}
|
}
|
||||||
const urlCurrent = DataUrlAccess.getThumbnailUrl(data[currentImageIndex]);
|
const urlCurrent = DataUrlAccess.getThumbnailUrl(data[currentImageIndex]);
|
||||||
const urlPrevious = DataUrlAccess.getThumbnailUrl(data[previousImageIndex]);
|
const urlPrevious = DataUrlAccess.getThumbnailUrl(data[previousImageIndex]);
|
||||||
return <Flex position="relative" {...rest} maxWidth={size} width={size} height={size} overflow="hidden">
|
return <></>/*<Flex
|
||||||
|
position="relative"
|
||||||
|
// {...rest}
|
||||||
|
maxWidth={size}
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
overflow="hidden">
|
||||||
<Image
|
<Image
|
||||||
src={urlPrevious}
|
src={urlPrevious}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@@ -89,5 +95,5 @@ export const Covers = ({
|
|||||||
opacity={topOpacity}
|
opacity={topOpacity}
|
||||||
zIndex={2}
|
zIndex={2}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>*/
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { Box } from '@chakra-ui/react';
|
import { Flex } from "@/ui";
|
||||||
|
|
||||||
export const EmptyEnd = () => {
|
export const EmptyEnd = () => {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Flex
|
||||||
width="full"
|
style={{
|
||||||
height="25%"
|
width: "100%",
|
||||||
minHeight="250px"
|
height: "25%",
|
||||||
|
minHeight: "250px",
|
||||||
|
}}
|
||||||
// borderWidth="1px"
|
// borderWidth="1px"
|
||||||
// borderColor="red"
|
// borderColor="red"
|
||||||
></Box>
|
></Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
import {
|
|
||||||
As,
|
import { Flex, FlexProps } from '@/ui';
|
||||||
Box,
|
import { forwardRef, ReactNode } from 'react';
|
||||||
BoxProps,
|
|
||||||
Icon as ChakraIcon,
|
|
||||||
IconProps as ChakraIconProps,
|
|
||||||
Flex,
|
|
||||||
FlexProps,
|
|
||||||
forwardRef,
|
|
||||||
LayoutProps,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export type IconProps = FlexProps & {
|
export type IconProps = FlexProps & {
|
||||||
icon: As;
|
icon: ReactNode;
|
||||||
color?: string;
|
color?: string;
|
||||||
sizeIcon?: LayoutProps['width'];
|
sizeIcon?: FlexProps['width'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Icon = forwardRef<IconProps, 'span'>(
|
export const Icon = forwardRef<HTMLDivElement, IconProps>(
|
||||||
({ icon: IconEl, color, sizeIcon = '1em', ...rest }, ref) => {
|
({ icon: IconEl, color, sizeIcon = '1em', style, ...rest }, ref) => {
|
||||||
return (
|
return (
|
||||||
<Flex flex="none"
|
<Flex
|
||||||
minWidth={sizeIcon}
|
|
||||||
minHeight={sizeIcon}
|
|
||||||
maxWidth={sizeIcon}
|
|
||||||
maxHeight={sizeIcon}
|
|
||||||
align="center"
|
align="center"
|
||||||
padding="1px"
|
style={{
|
||||||
ref={ref}
|
flex: "none",
|
||||||
|
minWidth: sizeIcon,
|
||||||
|
minHeight: sizeIcon,
|
||||||
|
maxWidth: sizeIcon,
|
||||||
|
maxHeight: sizeIcon,
|
||||||
|
padding: "1px",
|
||||||
|
...style
|
||||||
|
}}
|
||||||
{...rest}>
|
{...rest}>
|
||||||
<Box
|
<Flex
|
||||||
marginX="auto"
|
style={{
|
||||||
as={IconEl}
|
margin: "0 auto 0 auto",
|
||||||
width="100%"
|
width: "100%",
|
||||||
minWidth="100%"
|
minWidth: "100%",
|
||||||
height="100%"
|
height: "100%",
|
||||||
color={color}
|
color: color,
|
||||||
/>
|
}}
|
||||||
|
>
|
||||||
|
{IconEl}
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Icon.displayName = 'Icon';
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import React, { ReactNode, useEffect } from 'react';
|
import React, { ReactNode, useEffect } from 'react';
|
||||||
|
|
||||||
import { Flex, Image } from '@chakra-ui/react';
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import background from '@/assets/images/ikon.svg';
|
import background from '@/assets/images/ikon.svg';
|
||||||
import { TOP_BAR_HEIGHT } from '@/components/TopBar/TopBar';
|
import { TOP_BAR_HEIGHT } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex, Image } from '@/ui';
|
||||||
|
|
||||||
export type LayoutProps = React.PropsWithChildren<unknown> & {
|
export type LayoutProps = React.PropsWithChildren<unknown> & {
|
||||||
topBar?: ReactNode;
|
topBar?: ReactNode;
|
||||||
@@ -20,30 +20,34 @@ export const PageLayout = ({ children }: LayoutProps) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Flex
|
<Flex
|
||||||
minH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
style={{
|
||||||
maxH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
position: "absolute",
|
||||||
position="absolute"
|
minHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
top={TOP_BAR_HEIGHT}
|
maxHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
bottom={0}
|
top: TOP_BAR_HEIGHT,
|
||||||
left={0}
|
bottom: 0,
|
||||||
right={0}
|
left: 0,
|
||||||
minWidth="300px"
|
right: 0,
|
||||||
zIndex={-1}
|
minWidth: "300px",
|
||||||
|
zIndex: -1,
|
||||||
|
background: "back.800",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Image src={background} boxSize="90%" margin="auto" opacity="30%" />
|
<Image src={background} boxSize="90%" style={{ margin: "auto", opacity: "30%" }} />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
overflowX="auto"
|
style={{
|
||||||
overflowY="auto"
|
overflow: "auto",
|
||||||
minH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
minHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
maxH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
maxHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
position="absolute"
|
position: "absolute",
|
||||||
top={TOP_BAR_HEIGHT}
|
top: TOP_BAR_HEIGHT,
|
||||||
bottom={0}
|
bottom: 0,
|
||||||
left={0}
|
left: 0,
|
||||||
right={0}
|
right: 0,
|
||||||
minWidth="300px"
|
minWidth: "300px",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import React, { ReactNode, useEffect } from 'react';
|
import { CSSProperties, useEffect } from 'react';
|
||||||
|
|
||||||
import { Flex, FlexProps } from '@chakra-ui/react';
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { colors } from '@/theme/foundations/colors';
|
import { basicColor } from '@/theme/colors';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Flex, FlexProps } from '@/ui';
|
||||||
|
|
||||||
export type LayoutProps = FlexProps & {
|
export type LayoutProps = FlexProps & {
|
||||||
children: ReactNode;
|
width?: CSSProperties['width'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PageLayoutInfoCenter = ({
|
export const PageLayoutInfoCenter = ({
|
||||||
children,
|
children,
|
||||||
width = '25%',
|
width = "75%",
|
||||||
|
style,
|
||||||
...rest
|
...rest
|
||||||
}: LayoutProps) => {
|
}: LayoutProps) => {
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
@@ -22,19 +23,21 @@ export const PageLayoutInfoCenter = ({
|
|||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
|
||||||
const { mode } = useThemeMode();
|
|
||||||
return (
|
return (
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
margin="auto"
|
style={{
|
||||||
minWidth={width}
|
margin: "auto",
|
||||||
border="back.900"
|
width,
|
||||||
borderWidth="1px"
|
border: "back.900",
|
||||||
borderRadius="8px"
|
borderWidth: "1px",
|
||||||
padding="10px"
|
borderRadius: "8px",
|
||||||
boxShadow={'0px 0px 16px ' + colors.back[900]}
|
padding: "10px",
|
||||||
backgroundColor={mode('#FFFFFF', '#000000')}
|
boxShadow: '0px 0px 16px ' + basicColor.back[900],
|
||||||
|
background: useColorThemeValue('#FFFFFF', '#000000'),
|
||||||
|
...style
|
||||||
|
}}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Input,
|
|
||||||
InputGroup,
|
|
||||||
InputLeftElement,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { MdSearch } from 'react-icons/md';
|
import { MdSearch } from 'react-icons/md';
|
||||||
|
|
||||||
export type SearchInputProps = {
|
export type SearchInputProps = {
|
||||||
@@ -43,17 +38,15 @@ export const SearchInput = ({
|
|||||||
onSubmitValue(inputData);
|
onSubmitValue(inputData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (<></>
|
||||||
<InputGroup maxWidth="200px" marginLeft="auto" {...searchInputProperty}>
|
//<Group maxWidth="200px" marginLeft="auto" {...searchInputProperty}>
|
||||||
<InputLeftElement pointerEvents="none">
|
// <MdSearch color="gray.300" />
|
||||||
<MdSearch color="gray.300" />
|
// <Input
|
||||||
</InputLeftElement>
|
// onFocus={onFocusKeep}
|
||||||
<Input
|
// onBlur={() => setTimeout(() => onFocusLost(), 200)}
|
||||||
onFocus={onFocusKeep}
|
// onChange={onChange}
|
||||||
onBlur={() => setTimeout(() => onFocusLost(), 200)}
|
// onSubmit={onSubmit}
|
||||||
onChange={onChange}
|
// />
|
||||||
onSubmit={onSubmit}
|
//</Group>
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,49 +1,31 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Drawer,
|
|
||||||
DrawerBody,
|
|
||||||
DrawerContent,
|
|
||||||
DrawerHeader,
|
|
||||||
DrawerOverlay,
|
|
||||||
Flex,
|
|
||||||
HStack,
|
|
||||||
IconButton,
|
|
||||||
Menu,
|
|
||||||
MenuButton,
|
|
||||||
MenuItem,
|
|
||||||
MenuList,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
LuAlignJustify,
|
LuAlignJustify,
|
||||||
LuArrowBigLeft,
|
LuArrowBigLeft,
|
||||||
LuArrowUpSquare,
|
|
||||||
LuHelpCircle,
|
|
||||||
LuHome,
|
|
||||||
LuLogIn,
|
LuLogIn,
|
||||||
LuLogOut,
|
LuLogOut,
|
||||||
LuMoon,
|
LuMoon,
|
||||||
LuPlusCircle,
|
|
||||||
LuSettings,
|
LuSettings,
|
||||||
LuSun,
|
LuSun,
|
||||||
LuUserCircle,
|
|
||||||
} from 'react-icons/lu';
|
} from 'react-icons/lu';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { SessionState } from '@/service/SessionState';
|
import { SessionState } from '@/service/SessionState';
|
||||||
import { colors } from '@/theme/foundations/colors';
|
import { basicColor } from '@/theme/colors';
|
||||||
import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso';
|
import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
|
||||||
import { useSessionService } from '@/service/session';
|
import { useSessionService } from '@/service/session';
|
||||||
|
import { MdHelp, MdHome, MdMore, MdOutlinePlaylistPlay, MdOutlineUploadFile, MdSupervisedUserCircle } from 'react-icons/md';
|
||||||
|
import { useColorThemeValue, useTheme } from '@/theme/ThemeContext';
|
||||||
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export const TOP_BAR_HEIGHT = '50px';
|
export const TOP_BAR_HEIGHT = '50px';
|
||||||
|
|
||||||
export const BUTTON_TOP_BAR_PROPERTY = {
|
export const BUTTON_TOP_BAR_PROPERTY = {
|
||||||
variant: '@menu',
|
theme: '@menu',
|
||||||
height: TOP_BAR_HEIGHT,
|
height: TOP_BAR_HEIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,11 +35,11 @@ export type TopBarProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const TopBar = ({ title, children }: TopBarProps) => {
|
export const TopBar = ({ title, children }: TopBarProps) => {
|
||||||
const { mode, colorMode, toggleColorMode } = useThemeMode();
|
const { theme, toggleTheme } = useTheme();
|
||||||
const { clearToken } = useSessionService();
|
const { clearToken } = useSessionService();
|
||||||
|
|
||||||
const { session } = useServiceContext();
|
const { session } = useServiceContext();
|
||||||
const backColor = mode('back.100', 'back.800');
|
const backColor = useColorThemeValue('back.100', 'back.800');
|
||||||
const drawerDisclose = useDisclosure();
|
const drawerDisclose = useDisclosure();
|
||||||
const onChangeTheme = () => {
|
const onChangeTheme = () => {
|
||||||
drawerDisclose.onOpen();
|
drawerDisclose.onOpen();
|
||||||
@@ -81,6 +63,9 @@ export const TopBar = ({ title, children }: TopBarProps) => {
|
|||||||
const onSelectHome = () => {
|
const onSelectHome = () => {
|
||||||
navigate('/');
|
navigate('/');
|
||||||
};
|
};
|
||||||
|
const onSelectOnAir = () => {
|
||||||
|
navigate('/on-air');
|
||||||
|
};
|
||||||
const onHelp = () => {
|
const onHelp = () => {
|
||||||
navigate('/help');
|
navigate('/help');
|
||||||
};
|
};
|
||||||
@@ -89,22 +74,24 @@ export const TopBar = ({ title, children }: TopBarProps) => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
position="absolute"
|
|
||||||
top={0}
|
|
||||||
left={0}
|
|
||||||
right={0}
|
|
||||||
height={TOP_BAR_HEIGHT}
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="space-between"
|
|
||||||
backgroundColor={backColor}
|
|
||||||
gap="2"
|
gap="2"
|
||||||
px="2"
|
align="center"
|
||||||
boxShadow={'0px 2px 4px ' + colors.back[900]}
|
justify="space-between"
|
||||||
zIndex={200}
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: TOP_BAR_HEIGHT,
|
||||||
|
background: backColor,
|
||||||
|
padding: "0 2 0 2",
|
||||||
|
boxShadow: `0px 2px 4px ${basicColor.back[900]}`,
|
||||||
|
zIndex: 200,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onChangeTheme}>
|
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onChangeTheme}>
|
||||||
<LuAlignJustify />
|
<LuAlignJustify />
|
||||||
<Text paddingLeft="3px" fontWeight="bold">
|
<Text style={{ padding: "0 0 0 3px" }} fontWeight="bold">
|
||||||
Karusic
|
Karusic
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -112,80 +99,85 @@ export const TopBar = ({ title, children }: TopBarProps) => {
|
|||||||
<Text
|
<Text
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
textTransform="uppercase"
|
style={{
|
||||||
marginRight="auto"
|
textTransform: "uppercase",
|
||||||
userSelect="none"
|
marginRight: "auto",
|
||||||
|
userSelect: "none",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
{children}
|
{children}
|
||||||
<Flex right="0">
|
<Flex style={{ right: 0 }}>
|
||||||
{session?.state !== SessionState.CONNECTED && (
|
{session?.state !== SessionState.CONNECTED && (
|
||||||
<>
|
<>
|
||||||
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onSignIn}>
|
<Button {...BUTTON_TOP_BAR_PROPERTY} /*{...THEME.Button.primary}*/ onClick={onSignIn}>
|
||||||
<LuLogIn />
|
<LuLogIn />
|
||||||
<Text paddingLeft="3px" fontWeight="bold">
|
<Text style={{ paddingLeft: "0 0 0 3px" }} fontWeight="bold">
|
||||||
Sign-in
|
Sign-in
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
{...BUTTON_TOP_BAR_PROPERTY}
|
{...BUTTON_TOP_BAR_PROPERTY}
|
||||||
onClick={onSignUp}
|
onClick={onSignUp}
|
||||||
disabled={true}
|
// disabled={true}
|
||||||
>
|
>
|
||||||
<LuPlusCircle />
|
<MdMore />
|
||||||
<Text paddingLeft="3px" fontWeight="bold">
|
<Text style={{ padding: "0 0 0 3px" }} fontWeight="bold">
|
||||||
Sign-up
|
Sign-up
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{session?.state === SessionState.CONNECTED && (
|
{/* {session?.state === SessionState.CONNECTED && (
|
||||||
<Menu>
|
<Menu.Root>
|
||||||
<MenuButton
|
<Menu.Trigger asChild>
|
||||||
as={IconButton}
|
<IconButton
|
||||||
aria-label="Options"
|
as={IconButton}
|
||||||
icon={<LuUserCircle />}
|
aria-label="Options"
|
||||||
{...BUTTON_TOP_BAR_PROPERTY}
|
{...BUTTON_TOP_BAR_PROPERTY}
|
||||||
width={TOP_BAR_HEIGHT}
|
width={TOP_BAR_HEIGHT}
|
||||||
/>
|
><MdSupervisedUserCircle /></IconButton>
|
||||||
<MenuList>
|
</Menu.Trigger>
|
||||||
<MenuItem _hover={{}} color={mode('brand.800', 'brand.200')}>
|
<Menu.Content>
|
||||||
Sign in as {session?.login ?? 'Fail'}
|
<Menu.Item value="user" valueText="user" _hover={{}} color={useColorModeValue('brand.800', 'brand.200')}>
|
||||||
</MenuItem>
|
<MdSupervisedUserCircle />
|
||||||
<MenuItem icon={<LuSettings />} onClick={onSettings}>Settings</MenuItem>
|
<Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box>
|
||||||
<MenuItem icon={<LuHelpCircle />} onClick={onHelp}>Help</MenuItem>
|
</Menu.Item>
|
||||||
<MenuItem icon={<LuLogOut />} onClick={onSignOut}>
|
<Menu.Item value="Settings" valueText="Settings" onClick={onSettings}><LuSettings />Settings</Menu.Item>
|
||||||
Sign-out
|
<Menu.Item value="Help" valueText="Help" onClick={onHelp}><MdHelp /> Help</Menu.Item>
|
||||||
</MenuItem>
|
<Menu.Item value="Sign-out" valueText="Sign-out" onClick={onSignOut}>
|
||||||
|
<LuLogOut /> Sign-out
|
||||||
|
</Menu.Item>
|
||||||
{colorMode === 'light' ? (
|
{colorMode === 'light' ? (
|
||||||
<MenuItem icon={<LuMoon />} onClick={toggleColorMode}>
|
<Menu.Item value="set-dark" valueText="set-dark" onClick={toggleColorMode}>
|
||||||
Set dark mode
|
<LuMoon /> Set dark mode
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
) : (
|
) : (
|
||||||
<MenuItem icon={<LuSun />} onClick={toggleColorMode}>
|
<Menu.Item value="set-light" valueText="set-light" onClick={toggleColorMode}>
|
||||||
Set light mode
|
<LuSun /> Set light mode
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
)}
|
)}
|
||||||
</MenuList>
|
</Menu.Content>
|
||||||
</Menu>
|
</Menu.Root>
|
||||||
)}
|
)} */}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Drawer
|
{/* <Drawer.Root
|
||||||
placement="left"
|
placement="start"
|
||||||
onClose={drawerDisclose.onClose}
|
onOpenChange={drawerDisclose.onClose}
|
||||||
isOpen={drawerDisclose.isOpen}
|
open={drawerDisclose.open}
|
||||||
|
data-testid="top-bar_drawer-root"
|
||||||
>
|
>
|
||||||
<DrawerOverlay />
|
<Drawer.Content
|
||||||
<DrawerContent>
|
data-test-id="top-bar_drawer-content">
|
||||||
<DrawerHeader
|
<Drawer.Header
|
||||||
paddingY="auto"
|
paddingY="auto"
|
||||||
as="button"
|
as="button"
|
||||||
onClick={drawerDisclose.onClose}
|
onClick={drawerDisclose.onClose}
|
||||||
boxShadow={'0px 2px 4px ' + colors.back[900]}
|
boxShadow={'0px 2px 4px ' + colors.back[900]}
|
||||||
backgroundColor={backColor}
|
background={backColor}
|
||||||
color={mode('brand.900', 'brand.50')}
|
color={useColorModeValue('brand.900', 'brand.50')}
|
||||||
textTransform="uppercase"
|
textTransform="uppercase"
|
||||||
>
|
>
|
||||||
<HStack height={TOP_BAR_HEIGHT}>
|
<HStack height={TOP_BAR_HEIGHT}>
|
||||||
@@ -194,15 +186,15 @@ export const TopBar = ({ title, children }: TopBarProps) => {
|
|||||||
Karusic
|
Karusic
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
</DrawerHeader>
|
</Drawer.Header>
|
||||||
<DrawerBody paddingX="0px">
|
<Drawer.Body paddingX="0px">
|
||||||
<Button
|
<Button
|
||||||
background="#00000000"
|
background="#00000000"
|
||||||
borderRadius="0px"
|
borderRadius="0px"
|
||||||
onClick={onSelectHome}
|
onClick={onSelectHome}
|
||||||
width="full"
|
width="100%"
|
||||||
>
|
>
|
||||||
<LuHome />
|
<MdHome />
|
||||||
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
|
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
|
||||||
Home
|
Home
|
||||||
</Text>
|
</Text>
|
||||||
@@ -211,17 +203,29 @@ export const TopBar = ({ title, children }: TopBarProps) => {
|
|||||||
<Button
|
<Button
|
||||||
background="#00000000"
|
background="#00000000"
|
||||||
borderRadius="0px"
|
borderRadius="0px"
|
||||||
onClick={onSelectAdd}
|
onClick={onSelectOnAir}
|
||||||
width="full"
|
width="100%"
|
||||||
>
|
>
|
||||||
<LuArrowUpSquare />
|
<MdOutlinePlaylistPlay />
|
||||||
|
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
|
||||||
|
On air
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
<hr />
|
||||||
|
<Button
|
||||||
|
background="#00000000"
|
||||||
|
borderRadius="0px"
|
||||||
|
onClick={onSelectAdd}
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
|
<MdOutlineUploadFile />
|
||||||
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
|
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
|
||||||
Add Media
|
Add Media
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</DrawerBody>
|
</Drawer.Body>
|
||||||
</DrawerContent>
|
</Drawer.Content>
|
||||||
</Drawer>
|
</Drawer.Root> */}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { LuDisc3 } from 'react-icons/lu';
|
import { LuDisc3 } from 'react-icons/lu';
|
||||||
|
|
||||||
import { Album } from '@/back-api';
|
import { Album } from '@/back-api';
|
||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
import { useCountTracksWithAlbumId } from '@/service/Track';
|
import { useCountTracksWithAlbumId } from '@/service/Track';
|
||||||
import { BASE_WRAP_ICON_SIZE } from '@/constants/genericSpacing';
|
import { BASE_WRAP_ICON_SIZE } from '@/constants/genericSpacing';
|
||||||
|
import { Flex, Text } from '@/ui';
|
||||||
|
import { Span } from '@/ui/Span';
|
||||||
|
|
||||||
export type DisplayAlbumProps = {
|
export type DisplayAlbumProps = {
|
||||||
dataAlbum?: Album;
|
dataAlbum?: Album;
|
||||||
@@ -13,18 +15,19 @@ export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
|
|||||||
const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(dataAlbum?.id);
|
const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(dataAlbum?.id);
|
||||||
if (!dataAlbum) {
|
if (!dataAlbum) {
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full">
|
||||||
Fail to retrieve Album Data.
|
Fail to retrieve Album Data.
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full"
|
||||||
|
data-testid="display-album_flex">
|
||||||
<Covers
|
<Covers
|
||||||
data={dataAlbum?.covers}
|
data={dataAlbum?.covers}
|
||||||
size={BASE_WRAP_ICON_SIZE}
|
size={BASE_WRAP_ICON_SIZE}
|
||||||
flex={1}
|
flex={1}
|
||||||
iconEmpty={LuDisc3}
|
// TODO: iconEmpty={LuDisc3}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
@@ -32,32 +35,37 @@ export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
|
|||||||
//maxWidth="150px"
|
//maxWidth="150px"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
flex={1}
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
// align="left"
|
||||||
align="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
marginRight="auto"
|
style={{
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
noOfLines={[1, 2]}
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
// noOfLines={[1, 2]}
|
||||||
>
|
>
|
||||||
{dataAlbum?.name}
|
{dataAlbum?.name}
|
||||||
</Text>
|
</Span>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
// align="left"
|
||||||
align="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
marginRight="auto"
|
style={{
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
noOfLines={1}
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
// noOfLines={1}
|
||||||
>
|
>
|
||||||
{countTracksOfAnAlbum} track{countTracksOfAnAlbum >= 1 && 's'}
|
{countTracksOfAnAlbum} track{countTracksOfAnAlbum >= 1 && 's'}
|
||||||
</Text>
|
</Span>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ export type DisplayAlbumIdProps = {
|
|||||||
};
|
};
|
||||||
export const DisplayAlbumId = ({ id }: DisplayAlbumIdProps) => {
|
export const DisplayAlbumId = ({ id }: DisplayAlbumIdProps) => {
|
||||||
const { dataAlbum } = useSpecificAlbum(id);
|
const { dataAlbum } = useSpecificAlbum(id);
|
||||||
return <DisplayAlbum dataAlbum={dataAlbum} />;
|
return <DisplayAlbum dataAlbum={dataAlbum}
|
||||||
|
data-testid="display-album-id" />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
import {
|
|
||||||
IconButton,
|
|
||||||
Menu,
|
|
||||||
MenuButton,
|
|
||||||
MenuItem,
|
|
||||||
MenuList,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { LuMenu } from 'react-icons/lu';
|
import { LuMenu } from 'react-icons/lu';
|
||||||
|
|
||||||
|
|
||||||
export type MenuElement = {
|
export type MenuElement = {
|
||||||
name: string;
|
name: string;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
@@ -19,24 +12,28 @@ export type ContextMenuProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ContextMenu = ({ elements }: ContextMenuProps) => {
|
export const ContextMenu = ({ elements }: ContextMenuProps) => {
|
||||||
if (!elements) {
|
// if (!elements) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
// }
|
||||||
return (
|
// return (
|
||||||
<Menu>
|
// <Menu.Root
|
||||||
<MenuButton
|
// data-testid="context-menu">
|
||||||
as={IconButton}
|
// <Menu.Trigger asChild
|
||||||
aria-label="Options"
|
// data-testid="context-menu_trigger">
|
||||||
icon={<LuMenu />}
|
// {/* This is very stupid, we need to set as span to prevent a button in button... WTF */}
|
||||||
marginY="auto"
|
// <Button {...THEME.Button.primary} >
|
||||||
/>
|
// <LuMenu />
|
||||||
<MenuList>
|
// </Button>
|
||||||
{elements?.map((data) => (
|
// </Menu.Trigger>
|
||||||
<MenuItem key={data.name} onClick={data.onClick}>
|
// <Menu.Content
|
||||||
{data.name}
|
// data-testid="context-menu_content">
|
||||||
</MenuItem>
|
// {elements?.map((data) => (
|
||||||
))}
|
// <Menu.Item key={data.name} value={data.name} onClick={data.onClick}
|
||||||
</MenuList>
|
// data-testid="context-menu_item">
|
||||||
</Menu>
|
// {data.name}
|
||||||
);
|
// </Menu.Item>
|
||||||
|
// ))}
|
||||||
|
// </Menu.Content>
|
||||||
|
// </Menu.Root >
|
||||||
|
//);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ import {
|
|||||||
RefObject,
|
RefObject,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
BoxProps,
|
|
||||||
Center,
|
|
||||||
Image,
|
|
||||||
Wrap,
|
|
||||||
WrapItem,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
MdHighlightOff,
|
MdHighlightOff,
|
||||||
MdUploadFile,
|
MdUploadFile,
|
||||||
@@ -19,6 +12,7 @@ import {
|
|||||||
import { FormGroup } from '@/components/form/FormGroup';
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
import { UseFormidableReturn } from '@/components/form/Formidable';
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
import { DataUrlAccess } from '@/utils/data-url-access';
|
import { DataUrlAccess } from '@/utils/data-url-access';
|
||||||
|
import { Flex, FlexProps } from '@/ui';
|
||||||
|
|
||||||
export type DragNdropProps = {
|
export type DragNdropProps = {
|
||||||
onFilesSelected?: (file: File[]) => void;
|
onFilesSelected?: (file: File[]) => void;
|
||||||
@@ -58,40 +52,42 @@ export const DragNdrop = ({
|
|||||||
onUriSelected(listUri);
|
onUriSelected(listUri);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
return <></>;
|
||||||
return (
|
/*
|
||||||
<Box
|
return (
|
||||||
width={width}
|
<Box
|
||||||
height={height}
|
width={width}
|
||||||
border="2px"
|
height={height}
|
||||||
borderRadius="5px"
|
border="2px"
|
||||||
borderStyle="dashed"
|
borderRadius="5px"
|
||||||
onDrop={handleDrop}
|
borderStyle="dashed"
|
||||||
onDragOver={(event) => event.preventDefault()}
|
onDrop={handleDrop}
|
||||||
>
|
onDragOver={(event) => event.preventDefault()}
|
||||||
<label htmlFor="browse">
|
>
|
||||||
<Box paddingY="15%" height="100%" cursor="pointer">
|
<label htmlFor="browse">
|
||||||
<Center>
|
<Box paddingY="15%" height="100%" cursor="pointer">
|
||||||
<MdUploadFile size="50%" />
|
<Center>
|
||||||
</Center>
|
<MdUploadFile size="50%" />
|
||||||
<Center>
|
</Center>
|
||||||
<input
|
<Center>
|
||||||
type="file"
|
<input
|
||||||
hidden
|
type="file"
|
||||||
id="browse"
|
hidden
|
||||||
onChange={handleFileChange}
|
id="browse"
|
||||||
//accept=".pdf,.docx,.pptx,.txt,.xlsx"
|
onChange={handleFileChange}
|
||||||
multiple
|
//accept=".pdf,.docx,.pptx,.txt,.xlsx"
|
||||||
/>
|
multiple
|
||||||
Browse files
|
/>
|
||||||
</Center>
|
Browse files
|
||||||
</Box>
|
</Center>
|
||||||
</label>
|
</Box>
|
||||||
</Box>
|
</label>
|
||||||
);
|
</Box>
|
||||||
|
);
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CenterIconProps = BoxProps & {
|
export type CenterIconProps = FlexProps & {
|
||||||
icon: any;
|
icon: any;
|
||||||
sizeIcon?: string;
|
sizeIcon?: string;
|
||||||
};
|
};
|
||||||
@@ -99,11 +95,13 @@ export type CenterIconProps = BoxProps & {
|
|||||||
export const CenterIcon = ({
|
export const CenterIcon = ({
|
||||||
icon: IconEl,
|
icon: IconEl,
|
||||||
sizeIcon = '15px',
|
sizeIcon = '15px',
|
||||||
|
style,
|
||||||
...rest
|
...rest
|
||||||
}: CenterIconProps) => {
|
}: CenterIconProps) => {
|
||||||
return (
|
return (
|
||||||
<Box position="relative" w={sizeIcon} h={sizeIcon} flex="none" {...rest}>
|
<Flex style={{ position: "relative", width: sizeIcon, height: sizeIcon, flex: "none", ...style }}
|
||||||
<Box
|
{...rest}>
|
||||||
|
{/*<Flex
|
||||||
as={IconEl}
|
as={IconEl}
|
||||||
w={sizeIcon}
|
w={sizeIcon}
|
||||||
h={sizeIcon}
|
h={sizeIcon}
|
||||||
@@ -111,8 +109,8 @@ export const CenterIcon = ({
|
|||||||
top="50%"
|
top="50%"
|
||||||
left="50%"
|
left="50%"
|
||||||
transform="translate(-50%, -50%)"
|
transform="translate(-50%, -50%)"
|
||||||
/>
|
/>*/}
|
||||||
</Box>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -143,10 +141,10 @@ export const FormCovers = ({
|
|||||||
isModify={form.isModify[variableName]}
|
isModify={form.isModify[variableName]}
|
||||||
onRestore={() => form.restoreValue({ [variableName]: true })}
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
> <></>
|
||||||
<Wrap width="full">
|
{/* <HStack wrap="wrap" width="100%">
|
||||||
{urls.map((data, index) => (
|
{urls.map((data, index) => (
|
||||||
<WrapItem key={data}>
|
<Flex align="flex-start" key={data}>
|
||||||
<Box width="125px" height="125px" position="relative">
|
<Box width="125px" height="125px" position="relative">
|
||||||
<Box width="125px" height="125px" position="absolute">
|
<Box width="125px" height="125px" position="absolute">
|
||||||
<CenterIcon
|
<CenterIcon
|
||||||
@@ -161,17 +159,17 @@ export const FormCovers = ({
|
|||||||
</Box>
|
</Box>
|
||||||
<Image loading="lazy" src={data} boxSize="full" />
|
<Image loading="lazy" src={data} boxSize="full" />
|
||||||
</Box>
|
</Box>
|
||||||
</WrapItem>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<WrapItem key="data">
|
<Flex align="flex-start" key="data">
|
||||||
<DragNdrop
|
<DragNdrop
|
||||||
height="125px"
|
height="125px"
|
||||||
width="125px"
|
width="125px"
|
||||||
onFilesSelected={onFilesSelected}
|
onFilesSelected={onFilesSelected}
|
||||||
onUriSelected={onUriSelected}
|
onUriSelected={onUriSelected}
|
||||||
/>
|
/>
|
||||||
</WrapItem>
|
</Flex>
|
||||||
</Wrap>
|
</HStack> */}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { Flex, Text } from '@/ui';
|
||||||
|
import { Span } from '@/ui/Span';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { MdErrorOutline, MdHelpOutline, MdRefresh } from 'react-icons/md';
|
import { MdErrorOutline, MdHelpOutline, MdRefresh } from 'react-icons/md';
|
||||||
|
|
||||||
export type FormGroupProps = {
|
export type FormGroupProps = {
|
||||||
@@ -23,20 +24,22 @@ export const FormGroup = ({
|
|||||||
onRestore,
|
onRestore,
|
||||||
}: FormGroupProps) => (
|
}: FormGroupProps) => (
|
||||||
<Flex
|
<Flex
|
||||||
borderLeftWidth="3px"
|
style={{
|
||||||
borderLeftColor={error ? 'red' : isModify ? 'blue' : '#00000000'}
|
borderLeftWidth: "3px",
|
||||||
|
borderLeftColor: error ? 'red' : isModify ? 'blue' : '#00000000',
|
||||||
|
}}
|
||||||
paddingLeft="7px"
|
paddingLeft="7px"
|
||||||
paddingY="4px"
|
padding="0 4px"
|
||||||
direction="column"
|
direction="column"
|
||||||
>
|
>
|
||||||
<Flex direction="row" width="full" gap="52px">
|
<Flex direction="row" width="100%" gap="52px">
|
||||||
{!!label && (
|
{!!label && (
|
||||||
<Text marginRight="auto" fontWeight="bold">
|
<Text style={{ marginRight: "auto" }} fontWeight="bold">
|
||||||
{label}{' '}
|
{label}{' '}
|
||||||
{isRequired && (
|
{isRequired && (
|
||||||
<Text as="span" color="red.600">
|
<Span color="red.600">
|
||||||
*
|
*
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { RefObject } from 'react';
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
import { Input } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { FormGroup } from '@/components/form/FormGroup';
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
import { UseFormidableReturn } from '@/components/form/Formidable';
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
import { Input } from '@/ui';
|
||||||
|
|
||||||
export type FormInputProps = {
|
export type FormInputProps = {
|
||||||
form: UseFormidableReturn;
|
form: UseFormidableReturn;
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
import { RefObject } from 'react';
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
NumberDecrementStepper,
|
|
||||||
NumberIncrementStepper,
|
|
||||||
NumberInput,
|
|
||||||
NumberInputField,
|
|
||||||
NumberInputProps,
|
|
||||||
NumberInputStepper,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { FormGroup } from '@/components/form/FormGroup';
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
import { UseFormidableReturn } from '@/components/form/Formidable';
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
|
||||||
export type FormNumberProps = Pick<
|
export type FormNumberProps = Pick<
|
||||||
NumberInputProps,
|
NumberInput.RootProps,
|
||||||
'step' | 'defaultValue' | 'min' | 'max'
|
'step' | 'defaultValue' | 'min' | 'max'
|
||||||
> & {
|
> & {
|
||||||
form: UseFormidableReturn;
|
form: UseFormidableReturn;
|
||||||
@@ -41,21 +33,18 @@ export const FormNumber = ({
|
|||||||
onRestore={() => form.restoreValue({ [variableName]: true })}
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
<NumberInput
|
<></>
|
||||||
|
{/* <NumberInput.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
value={form.values[variableName]}
|
value={form.values[variableName]}
|
||||||
onChange={(_, value) => form.setValues({ [variableName]: value })}
|
onValueChange={(value) => form.setValues({ [variableName]: value })}
|
||||||
step={step}
|
step={step}
|
||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
>
|
>
|
||||||
<NumberInputField />
|
<NumberInput.Input />
|
||||||
<NumberInputStepper>
|
</NumberInput.Root> */}
|
||||||
<NumberIncrementStepper />
|
|
||||||
<NumberDecrementStepper />
|
|
||||||
</NumberInputStepper>
|
|
||||||
</NumberInput>
|
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Box } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { FormSelect } from '@/components/form/FormSelect';
|
import { FormSelect } from '@/components/form/FormSelect';
|
||||||
import { useFormidable } from '@/components/form/Formidable';
|
import { useFormidable } from '@/components/form/Formidable';
|
||||||
|
import { Flex } from '@/ui';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Components/FormSelect',
|
title: 'Components/FormSelect',
|
||||||
@@ -94,7 +94,7 @@ export const DarkBackground = {
|
|||||||
render: () => {
|
render: () => {
|
||||||
const form = useFormidable<BasicFormData>({});
|
const form = useFormidable<BasicFormData>({});
|
||||||
return (
|
return (
|
||||||
<Box p="4" color="white" bg="gray.800">
|
<Flex style={{ padding: "4", color: "white", background: "gray.800" }}>
|
||||||
<FormSelect
|
<FormSelect
|
||||||
label="Simple Title for (DarkBackground)"
|
label="Simple Title for (DarkBackground)"
|
||||||
form={form}
|
form={form}
|
||||||
@@ -105,7 +105,7 @@ export const DarkBackground = {
|
|||||||
{ id: 333, name: 'third item' },
|
{ id: 333, name: 'third item' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { RefObject } from 'react';
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
import { Text } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { FormGroup } from '@/components/form/FormGroup';
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
import { UseFormidableReturn } from '@/components/form/Formidable';
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Box } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { FormSelectMultiple } from '@/components/form/FormSelectMultiple';
|
import { FormSelectMultiple } from '@/components/form/FormSelectMultiple';
|
||||||
import { useFormidable } from '@/components/form/Formidable';
|
import { useFormidable } from '@/components/form/Formidable';
|
||||||
|
import { Flex } from '@/ui';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Components/FormSelectMultipleMultiple',
|
title: 'Components/FormSelectMultipleMultiple',
|
||||||
@@ -94,7 +94,7 @@ export const DarkBackground = {
|
|||||||
render: () => {
|
render: () => {
|
||||||
const form = useFormidable<BasicFormData>({});
|
const form = useFormidable<BasicFormData>({});
|
||||||
return (
|
return (
|
||||||
<Box p="4" color="white" bg="gray.800">
|
<Flex style={{ padding: "4", color: "white", background: "gray.800" }}>
|
||||||
<FormSelectMultiple
|
<FormSelectMultiple
|
||||||
label="Simple Title for (DarkBackground)"
|
label="Simple Title for (DarkBackground)"
|
||||||
form={form}
|
form={form}
|
||||||
@@ -105,7 +105,7 @@ export const DarkBackground = {
|
|||||||
{ id: 333, name: 'third item' },
|
{ id: 333, name: 'third item' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { RefObject } from 'react';
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
import { Textarea } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import { FormGroup } from '@/components/form/FormGroup';
|
import { FormGroup } from '@/components/form/FormGroup';
|
||||||
import { UseFormidableReturn } from '@/components/form/Formidable';
|
import { UseFormidableReturn } from '@/components/form/Formidable';
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { LuDisc3 } from 'react-icons/lu';
|
import { LuDisc3 } from 'react-icons/lu';
|
||||||
|
|
||||||
import { Gender } from '@/back-api';
|
import { Gender } from '@/back-api';
|
||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
import { useCountTracksOfAGender } from '@/service/Track';
|
import { useCountTracksOfAGender } from '@/service/Track';
|
||||||
|
import { Flex, Span, Text } from '@/ui';
|
||||||
|
|
||||||
export type DisplayGenderProps = {
|
export type DisplayGenderProps = {
|
||||||
dataGender?: Gender;
|
dataGender?: Gender;
|
||||||
@@ -12,18 +13,18 @@ export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
|
|||||||
const { countTracksOnAGender } = useCountTracksOfAGender(dataGender?.id);
|
const { countTracksOnAGender } = useCountTracksOfAGender(dataGender?.id);
|
||||||
if (!dataGender) {
|
if (!dataGender) {
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full">
|
||||||
Fail to retrieve Gender Data.
|
Fail to retrieve Gender Data.
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full">
|
||||||
<Covers
|
<Covers
|
||||||
data={dataGender?.covers}
|
data={dataGender?.covers}
|
||||||
size="100"
|
size="100"
|
||||||
height="full"
|
height="full"
|
||||||
iconEmpty={LuDisc3}
|
//TODO: iconEmpty={LuDisc3}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
@@ -31,31 +32,36 @@ export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
|
|||||||
maxWidth="150px"
|
maxWidth="150px"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
|
overflowX: "hidden"
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
align="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
style={{
|
||||||
marginRight="auto"
|
userSelect: "none",
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
noOfLines={[1, 2]}
|
overflow: "hidden",
|
||||||
|
alignContent: "left",
|
||||||
|
}}
|
||||||
|
|
||||||
|
//TODO: noOfLines={[1, 2]}
|
||||||
>
|
>
|
||||||
{dataGender?.name}
|
{dataGender?.name}
|
||||||
</Text>
|
</Span>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
align="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
userSelect="none"
|
style={{
|
||||||
marginRight="auto"
|
userSelect: "none",
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
noOfLines={1}
|
overflow: "hidden",
|
||||||
|
alignContent: "left",
|
||||||
|
}}
|
||||||
|
//TODO: noOfLines={1}
|
||||||
>
|
>
|
||||||
{countTracksOnAGender} track{countTracksOnAGender >= 1 && 's'}
|
{countTracksOnAGender} track{countTracksOnAGender >= 1 && 's'}
|
||||||
</Text>
|
</Span>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
MdAdminPanelSettings,
|
MdAdminPanelSettings,
|
||||||
MdDeleteForever,
|
MdDeleteForever,
|
||||||
@@ -32,6 +19,7 @@ import { useAlbumService, useSpecificAlbum } from '@/service/Album';
|
|||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { useCountTracksWithAlbumId } from '@/service/Track';
|
import { useCountTracksWithAlbumId } from '@/service/Track';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
|
|
||||||
export type AlbumEditPopUpProps = {};
|
export type AlbumEditPopUpProps = {};
|
||||||
|
|
||||||
@@ -65,8 +53,8 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
|
|||||||
);
|
);
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
const initialRef = useRef(null);
|
const initialRef = useRef<HTMLButtonElement>(null);
|
||||||
const finalRef = useRef(null);
|
const finalRef = useRef<HTMLButtonElement>(null);
|
||||||
const form = useFormidable<Album>({
|
const form = useFormidable<Album>({
|
||||||
initialValues: dataAlbum,
|
initialValues: dataAlbum,
|
||||||
});
|
});
|
||||||
@@ -140,107 +128,110 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return <></>;
|
||||||
<Modal
|
// return (
|
||||||
initialFocusRef={initialRef}
|
// <Dialog.Root
|
||||||
finalFocusRef={finalRef}
|
// //initialFocusRef={initialRef}
|
||||||
closeOnOverlayClick={false}
|
// //finalFocusRef={finalRef}
|
||||||
onClose={onClose}
|
// //closeOnOverlayClick={false}
|
||||||
isOpen={true}
|
// onOpenChange={onClose}
|
||||||
>
|
// open={true}
|
||||||
<ModalOverlay />
|
// data-testid="album-edit-pop-up"
|
||||||
<ModalContent>
|
// >
|
||||||
<ModalHeader>Edit Album</ModalHeader>
|
// {/* <DialogOverlay /> */}
|
||||||
<ModalCloseButton ref={finalRef} />
|
// {/* <DialogCloseTrigger /> */}
|
||||||
|
// <Dialog.Content>
|
||||||
|
// <Dialog.Header>Edit Album</Dialog.Header>
|
||||||
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<ModalBody pb={6} gap="0px" paddingLeft="18px">
|
// <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
|
||||||
{admin && (
|
// {admin && (
|
||||||
<>
|
// <>
|
||||||
<FormGroup isRequired label="Id">
|
// <FormGroup isRequired label="Id">
|
||||||
<Text>{dataAlbum?.id}</Text>
|
// <Text>{dataAlbum?.id}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
{countTracksOfAnAlbum !== 0 && (
|
// {countTracksOfAnAlbum !== 0 && (
|
||||||
<Flex paddingLeft="14px">
|
// <Flex paddingLeft="14px">
|
||||||
<MdWarning color="red.600" />
|
// <MdWarning color="red.600" />
|
||||||
<Text paddingLeft="6px" color="red.600" fontWeight="bold">
|
// <Text paddingLeft="6px" color="red.600" fontWeight="bold">
|
||||||
Can not remove album {countTracksOfAnAlbum} track(s) depend
|
// Can not remove album {countTracksOfAnAlbum} track(s) depend
|
||||||
on it.
|
// on it.
|
||||||
</Text>
|
// </Text>
|
||||||
</Flex>
|
// </Flex>
|
||||||
)}
|
// )}
|
||||||
<FormGroup label="Action(s):">
|
// <FormGroup label="Action(s):">
|
||||||
<Button
|
// <Button
|
||||||
onClick={disclosure.onOpen}
|
// onClick={disclosure.onOpen}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
variant="@danger"
|
// theme="@danger"
|
||||||
isDisabled={countTracksOfAnAlbum !== 0}
|
// disabled={countTracksOfAnAlbum !== 0}
|
||||||
>
|
// >
|
||||||
<MdDeleteForever /> Remove Media
|
// <MdDeleteForever /> Remove Media
|
||||||
</Button>
|
// </Button>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<ConfirmPopUp
|
// <ConfirmPopUp
|
||||||
disclosure={disclosure}
|
// disclosure={disclosure}
|
||||||
title="Remove album"
|
// title="Remove album"
|
||||||
body={`Remove Album [${dataAlbum?.id}] ${dataAlbum?.name}`}
|
// body={`Remove Album [${dataAlbum?.id}] ${dataAlbum?.name}`}
|
||||||
confirmTitle="Remove"
|
// confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
// onConfirm={onRemove}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
{!admin && (
|
// {!admin && (
|
||||||
<>
|
// <>
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="name"
|
// variableName="name"
|
||||||
isRequired
|
// isRequired
|
||||||
label="Title"
|
// label="Title"
|
||||||
ref={initialRef}
|
// ref={initialRef}
|
||||||
/>
|
// />
|
||||||
<FormTextarea
|
// <FormTextarea
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="description"
|
// variableName="description"
|
||||||
label="Description"
|
// label="Description"
|
||||||
/>
|
// />
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="publication"
|
// variableName="publication"
|
||||||
label="Publication"
|
// label="Publication"
|
||||||
/>
|
// />
|
||||||
<FormCovers
|
// <FormCovers
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="covers"
|
// variableName="covers"
|
||||||
onFilesSelected={onFilesSelected}
|
// onFilesSelected={onFilesSelected}
|
||||||
onUriSelected={onUriSelected}
|
// onUriSelected={onUriSelected}
|
||||||
onRemove={onRemoveCover}
|
// onRemove={onRemoveCover}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</ModalBody>
|
// </Dialog.Body>
|
||||||
<ModalFooter>
|
// <Dialog.Footer>
|
||||||
<Button
|
// <Button
|
||||||
onClick={() => setAdmin((value) => !value)}
|
// onClick={() => setAdmin((value) => !value)}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
>
|
// >
|
||||||
{admin ? (
|
// {admin ? (
|
||||||
<>
|
// <>
|
||||||
<MdEdit />
|
// <MdEdit />
|
||||||
Edit
|
// Edit
|
||||||
</>
|
// </>
|
||||||
) : (
|
// ) : (
|
||||||
<>
|
// <>
|
||||||
<MdAdminPanelSettings />
|
// <MdAdminPanelSettings />
|
||||||
Admin
|
// Admin
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</Button>
|
// </Button>
|
||||||
{!admin && form.isFormModified && (
|
// {!admin && form.isFormModified && (
|
||||||
<Button colorScheme="blue" mr={3} onClick={onSave}>
|
// <Button colorScheme="blue" mr={3} onClick={onSave}>
|
||||||
Save
|
// Save
|
||||||
</Button>
|
// </Button>
|
||||||
)}
|
// )}
|
||||||
<Button onClick={onClose}>Cancel</Button>
|
// <Button onClick={onClose}>Cancel</Button>
|
||||||
</ModalFooter>
|
// </Dialog.Footer>
|
||||||
</ModalContent>
|
// </Dialog.Content>
|
||||||
</Modal>
|
// </Dialog.Root>
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,6 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
MdAdminPanelSettings,
|
MdAdminPanelSettings,
|
||||||
MdDeleteForever,
|
MdDeleteForever,
|
||||||
@@ -32,6 +20,7 @@ import { useArtistService, useSpecificArtist } from '@/service/Artist';
|
|||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { useCountTracksOfAnArtist } from '@/service/Track';
|
import { useCountTracksOfAnArtist } from '@/service/Track';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
|
|
||||||
export type ArtistEditPopUpProps = {};
|
export type ArtistEditPopUpProps = {};
|
||||||
|
|
||||||
@@ -65,8 +54,8 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
|
|||||||
);
|
);
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
const initialRef = useRef(null);
|
const initialRef = useRef<HTMLButtonElement>(null);
|
||||||
const finalRef = useRef(null);
|
const finalRef = useRef<HTMLButtonElement>(null);
|
||||||
const form = useFormidable<Artist>({
|
const form = useFormidable<Artist>({
|
||||||
initialValues: dataArtist,
|
initialValues: dataArtist,
|
||||||
});
|
});
|
||||||
@@ -140,109 +129,110 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Modal
|
// <Dialog.Root
|
||||||
initialFocusRef={initialRef}
|
// //initialFocusRef={initialRef}
|
||||||
finalFocusRef={finalRef}
|
// //finalFocusRef={finalRef}
|
||||||
closeOnOverlayClick={false}
|
// //closeOnOverlayClick={false}
|
||||||
onClose={onClose}
|
// onOpenChange={onClose}
|
||||||
isOpen={true}
|
// open={true}
|
||||||
>
|
// data-testid="artist-edit-pop-up"
|
||||||
<ModalOverlay />
|
// >
|
||||||
<ModalContent>
|
// {/* <DialogOverlay /> */}
|
||||||
<ModalHeader>Edit Artist</ModalHeader>
|
// <Dialog.Content>
|
||||||
<ModalCloseButton ref={finalRef} />
|
// <Dialog.Header>Edit Artist</Dialog.Header>
|
||||||
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<ModalBody pb={6} gap="0px" paddingLeft="18px">
|
// <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
|
||||||
{admin && (
|
// {admin && (
|
||||||
<>
|
// <>
|
||||||
<FormGroup isRequired label="Id">
|
// <FormGroup isRequired label="Id">
|
||||||
<Text>{dataArtist?.id}</Text>
|
// <Text>{dataArtist?.id}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
{countTracksOnAnArtist !== 0 && (
|
// {countTracksOnAnArtist !== 0 && (
|
||||||
<Flex paddingLeft="14px">
|
// <Flex paddingLeft="14px">
|
||||||
<MdWarning color="red.600" />
|
// <MdWarning color="red.600" />
|
||||||
<Text paddingLeft="6px" color="red.600" fontWeight="bold">
|
// <Text paddingLeft="6px" color="red.600" fontWeight="bold">
|
||||||
Can not remove artist {countTracksOnAnArtist} track(s)
|
// Can not remove artist {countTracksOnAnArtist} track(s)
|
||||||
depend on it.
|
// depend on it.
|
||||||
</Text>
|
// </Text>
|
||||||
</Flex>
|
// </Flex>
|
||||||
)}
|
// )}
|
||||||
<FormGroup label="Action(s):">
|
// <FormGroup label="Action(s):">
|
||||||
<Button
|
// <Button
|
||||||
onClick={disclosure.onOpen}
|
// onClick={disclosure.onOpen}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
variant="@danger"
|
// theme="@danger"
|
||||||
isDisabled={countTracksOnAnArtist !== 0}
|
// disabled={countTracksOnAnArtist !== 0}
|
||||||
>
|
// >
|
||||||
<MdDeleteForever /> Remove Media
|
// <MdDeleteForever /> Remove Media
|
||||||
</Button>
|
// </Button>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<ConfirmPopUp
|
// <ConfirmPopUp
|
||||||
disclosure={disclosure}
|
// disclosure={disclosure}
|
||||||
title="Remove artist"
|
// title="Remove artist"
|
||||||
body={`Remove Artist [${dataArtist?.id}] ${dataArtist?.name}`}
|
// body={`Remove Artist [${dataArtist?.id}] ${dataArtist?.name}`}
|
||||||
confirmTitle="Remove"
|
// confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
// onConfirm={onRemove}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
{!admin && (
|
// {!admin && (
|
||||||
<>
|
// <>
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="name"
|
// variableName="name"
|
||||||
isRequired
|
// isRequired
|
||||||
label="Artist name"
|
// label="Artist name"
|
||||||
ref={initialRef}
|
// ref={initialRef}
|
||||||
/>
|
// />
|
||||||
<FormTextarea
|
// <FormTextarea
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="description"
|
// variableName="description"
|
||||||
label="Description"
|
// label="Description"
|
||||||
/>
|
// />
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="firstName"
|
// variableName="firstName"
|
||||||
label="First Name"
|
// label="First Name"
|
||||||
/>
|
// />
|
||||||
<FormInput form={form} variableName="surname" label="SurName" />
|
// <FormInput form={form} variableName="surname" label="SurName" />
|
||||||
<FormInput form={form} variableName="birth" label="Birth date" />
|
// <FormInput form={form} variableName="birth" label="Birth date" />
|
||||||
<FormInput form={form} variableName="death" label="Death date" />
|
// <FormInput form={form} variableName="death" label="Death date" />
|
||||||
<FormCovers
|
// <FormCovers
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="covers"
|
// variableName="covers"
|
||||||
onFilesSelected={onFilesSelected}
|
// onFilesSelected={onFilesSelected}
|
||||||
onUriSelected={onUriSelected}
|
// onUriSelected={onUriSelected}
|
||||||
onRemove={onRemoveCover}
|
// onRemove={onRemoveCover}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</ModalBody>
|
// </Dialog.Body>
|
||||||
<ModalFooter>
|
// <Dialog.Footer>
|
||||||
<Button
|
// <Button
|
||||||
onClick={() => setAdmin((value) => !value)}
|
// onClick={() => setAdmin((value) => !value)}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
>
|
// >
|
||||||
{admin ? (
|
// {admin ? (
|
||||||
<>
|
// <>
|
||||||
<MdEdit />
|
// <MdEdit />
|
||||||
Edit
|
// Edit
|
||||||
</>
|
// </>
|
||||||
) : (
|
// ) : (
|
||||||
<>
|
// <>
|
||||||
<MdAdminPanelSettings />
|
// <MdAdminPanelSettings />
|
||||||
Admin
|
// Admin
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</Button>
|
// </Button>
|
||||||
{!admin && form.isFormModified && (
|
// {!admin && form.isFormModified && (
|
||||||
<Button colorScheme="blue" mr={3} onClick={onSave}>
|
// <Button colorScheme="blue" mr={3} onClick={onSave}>
|
||||||
Save
|
// Save
|
||||||
</Button>
|
// </Button>
|
||||||
)}
|
// )}
|
||||||
<Button onClick={onClose}>Cancel</Button>
|
// <Button onClick={onClose}>Cancel</Button>
|
||||||
</ModalFooter>
|
// </Dialog.Footer>
|
||||||
</ModalContent>
|
// </Dialog.Content>
|
||||||
</Modal>
|
// </Dialog.Root>
|
||||||
);
|
<></>);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
|
import { UseDisclosureReturn } from '@/utils/disclosure';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
AlertDialog,
|
|
||||||
AlertDialogBody,
|
|
||||||
AlertDialogContent,
|
|
||||||
AlertDialogFooter,
|
|
||||||
AlertDialogHeader,
|
|
||||||
AlertDialogOverlay,
|
|
||||||
Button,
|
|
||||||
UseDisclosureReturn,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export type ConfirmPopUpProps = {
|
export type ConfirmPopUpProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -30,31 +22,29 @@ export const ConfirmPopUp = ({
|
|||||||
onConfirm();
|
onConfirm();
|
||||||
disclosure.onClose();
|
disclosure.onClose();
|
||||||
};
|
};
|
||||||
const cancelRef = useRef(null);
|
const cancelRef = useRef<HTMLButtonElement>(null);
|
||||||
return (
|
return <></>;
|
||||||
<AlertDialog
|
// return (
|
||||||
isOpen={disclosure.isOpen}
|
// <Dialog.Root role="alertdialog"
|
||||||
leastDestructiveRef={cancelRef}
|
// open={disclosure.open}
|
||||||
onClose={disclosure.onClose}
|
// //leastDestructiveRef={cancelRef}
|
||||||
>
|
// onOpenChange={disclosure.onClose}
|
||||||
<AlertDialogOverlay>
|
// data-testid="confirm-pop-up"
|
||||||
<AlertDialogContent>
|
// >
|
||||||
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
// <Dialog.Content>
|
||||||
{title}
|
// <Dialog.Header fontSize="lg" fontWeight="bold">
|
||||||
</AlertDialogHeader>
|
// {title}
|
||||||
|
// </Dialog.Header>
|
||||||
<AlertDialogBody>{body}</AlertDialogBody>
|
// <Dialog.Body>{body}</Dialog.Body>
|
||||||
|
// <Dialog.Footer>
|
||||||
<AlertDialogFooter>
|
// <Button onClick={disclosure.onClose} ref={cancelRef}>
|
||||||
<Button onClick={disclosure.onClose} ref={cancelRef}>
|
// Cancel
|
||||||
Cancel
|
// </Button>
|
||||||
</Button>
|
// <Button colorScheme="red" onClick={onClickConfirm} ml={3}>
|
||||||
<Button colorScheme="red" onClick={onClickConfirm} ml={3}>
|
// {confirmTitle}
|
||||||
{confirmTitle}
|
// </Button>
|
||||||
</Button>
|
// </Dialog.Footer>
|
||||||
</AlertDialogFooter>
|
// </Dialog.Content>
|
||||||
</AlertDialogContent>
|
// </Dialog.Root>
|
||||||
</AlertDialogOverlay>
|
// );
|
||||||
</AlertDialog>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,24 +1,13 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
MdAdminPanelSettings,
|
MdAdminPanelSettings,
|
||||||
MdDeleteForever,
|
MdDeleteForever,
|
||||||
MdEdit,
|
MdEdit,
|
||||||
MdWarning,
|
MdWarning,
|
||||||
} from 'react-icons/md';
|
} from 'react-icons/md';
|
||||||
|
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { Gender, GenderResource } from '@/back-api';
|
import { Gender, GenderResource } from '@/back-api';
|
||||||
@@ -32,6 +21,7 @@ import { useGenderService, useSpecificGender } from '@/service/Gender';
|
|||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { useCountTracksOfAGender } from '@/service/Track';
|
import { useCountTracksOfAGender } from '@/service/Track';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
|
|
||||||
export type GenderEditPopUpProps = {};
|
export type GenderEditPopUpProps = {};
|
||||||
|
|
||||||
@@ -65,8 +55,8 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
|
|||||||
);
|
);
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
const initialRef = useRef(null);
|
const initialRef = useRef<HTMLButtonElement>(null);
|
||||||
const finalRef = useRef(null);
|
const finalRef = useRef<HTMLButtonElement>(null);
|
||||||
const form = useFormidable<Gender>({
|
const form = useFormidable<Gender>({
|
||||||
initialValues: dataGender,
|
initialValues: dataGender,
|
||||||
});
|
});
|
||||||
@@ -138,102 +128,104 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return <></>;
|
||||||
<Modal
|
// return (
|
||||||
initialFocusRef={initialRef}
|
// <Dialog.Root
|
||||||
finalFocusRef={finalRef}
|
// //initialFocusRef={initialRef}
|
||||||
closeOnOverlayClick={false}
|
// //finalFocusRef={finalRef}
|
||||||
onClose={onClose}
|
// //closeOnOverlayClick={false}
|
||||||
isOpen={true}
|
// onOpenChange={onClose}
|
||||||
>
|
// open={true}
|
||||||
<ModalOverlay />
|
// data-testid="gender-edit-pop-up"
|
||||||
<ModalContent>
|
// >
|
||||||
<ModalHeader>Edit Gender</ModalHeader>
|
// {/* <DialogOverlay /> */}
|
||||||
<ModalCloseButton ref={finalRef} />
|
// <Dialog.Content>
|
||||||
|
// <Dialog.Header>Edit Gender</Dialog.Header>
|
||||||
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<ModalBody pb={6} gap="0px" paddingLeft="18px">
|
// <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
|
||||||
{admin && (
|
// {admin && (
|
||||||
<>
|
// <>
|
||||||
<FormGroup isRequired label="Id">
|
// <FormGroup isRequired label="Id">
|
||||||
<Text>{dataGender?.id}</Text>
|
// <Text>{dataGender?.id}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
{countTracksOnAGender !== 0 && (
|
// {countTracksOnAGender !== 0 && (
|
||||||
<Flex paddingLeft="14px">
|
// <Flex paddingLeft="14px">
|
||||||
<MdWarning color="red.600" />
|
// <MdWarning color="red.600" />
|
||||||
<Text paddingLeft="6px" color="red.600" fontWeight="bold">
|
// <Text paddingLeft="6px" color="red.600" fontWeight="bold">
|
||||||
Can not remove gender {countTracksOnAGender} track(s) depend
|
// Can not remove gender {countTracksOnAGender} track(s) depend
|
||||||
on it.
|
// on it.
|
||||||
</Text>
|
// </Text>
|
||||||
</Flex>
|
// </Flex>
|
||||||
)}
|
// )}
|
||||||
<FormGroup label="Action(s):">
|
// <FormGroup label="Action(s):">
|
||||||
<Button
|
// <Button
|
||||||
onClick={disclosure.onOpen}
|
// onClick={disclosure.onOpen}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
variant="@danger"
|
// theme="@danger"
|
||||||
isDisabled={countTracksOnAGender !== 0}
|
// disabled={countTracksOnAGender !== 0}
|
||||||
>
|
// >
|
||||||
<MdDeleteForever /> Remove gender
|
// <MdDeleteForever /> Remove gender
|
||||||
</Button>
|
// </Button>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<ConfirmPopUp
|
// <ConfirmPopUp
|
||||||
disclosure={disclosure}
|
// disclosure={disclosure}
|
||||||
title="Remove gender"
|
// title="Remove gender"
|
||||||
body={`Remove gender [${dataGender?.id}] ${dataGender?.name}`}
|
// body={`Remove gender [${dataGender?.id}] ${dataGender?.name}`}
|
||||||
confirmTitle="Remove"
|
// confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
// onConfirm={onRemove}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
{!admin && (
|
// {!admin && (
|
||||||
<>
|
// <>
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="name"
|
// variableName="name"
|
||||||
isRequired
|
// isRequired
|
||||||
label="Gender name"
|
// label="Gender name"
|
||||||
ref={initialRef}
|
// ref={initialRef}
|
||||||
/>
|
// />
|
||||||
<FormTextarea
|
// <FormTextarea
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="description"
|
// variableName="description"
|
||||||
label="Description"
|
// label="Description"
|
||||||
/>
|
// />
|
||||||
<FormCovers
|
// <FormCovers
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="covers"
|
// variableName="covers"
|
||||||
onFilesSelected={onFilesSelected}
|
// onFilesSelected={onFilesSelected}
|
||||||
onUriSelected={onUriSelected}
|
// onUriSelected={onUriSelected}
|
||||||
onRemove={onRemoveCover}
|
// onRemove={onRemoveCover}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</ModalBody>
|
// </Dialog.Body>
|
||||||
<ModalFooter>
|
// <Dialog.Footer>
|
||||||
<Button
|
// <Button
|
||||||
onClick={() => setAdmin((value) => !value)}
|
// onClick={() => setAdmin((value) => !value)}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
>
|
// >
|
||||||
{admin ? (
|
// {admin ? (
|
||||||
<>
|
// <>
|
||||||
<MdEdit />
|
// <MdEdit />
|
||||||
Edit
|
// Edit
|
||||||
</>
|
// </>
|
||||||
) : (
|
// ) : (
|
||||||
<>
|
// <>
|
||||||
<MdAdminPanelSettings />
|
// <MdAdminPanelSettings />
|
||||||
Admin
|
// Admin
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</Button>
|
// </Button>
|
||||||
{!admin && form.isFormModified && (
|
// {!admin && form.isFormModified && (
|
||||||
<Button colorScheme="blue" mr={3} onClick={onSave}>
|
// <Button colorScheme="blue" mr={3} onClick={onSave}>
|
||||||
Save
|
// Save
|
||||||
</Button>
|
// </Button>
|
||||||
)}
|
// )}
|
||||||
<Button onClick={onClose}>Cancel</Button>
|
// <Button onClick={onClose}>Cancel</Button>
|
||||||
</ModalFooter>
|
// </Dialog.Footer>
|
||||||
</ModalContent>
|
// </Dialog.Content>
|
||||||
</Modal>
|
// </Dialog.Root>
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,38 +1,5 @@
|
|||||||
import { ReactElement, useRef, useState } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Progress,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
|
||||||
MdAdminPanelSettings,
|
|
||||||
MdDeleteForever,
|
|
||||||
MdEdit,
|
|
||||||
MdWarning,
|
|
||||||
} from 'react-icons/md';
|
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { Artist, ArtistResource } from '@/back-api';
|
|
||||||
import { FormCovers } from '@/components/form/FormCovers';
|
|
||||||
import { FormGroup } from '@/components/form/FormGroup';
|
|
||||||
import { FormInput } from '@/components/form/FormInput';
|
|
||||||
import { FormTextarea } from '@/components/form/FormTextarea';
|
|
||||||
import { useFormidable } from '@/components/form/Formidable';
|
|
||||||
import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp';
|
|
||||||
import { useArtistService, useSpecificArtist } from '@/service/Artist';
|
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
|
||||||
import { useCountTracksOfAnArtist } from '@/service/Track';
|
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
|
||||||
|
|
||||||
export type PopUpUploadProgressProps = {
|
export type PopUpUploadProgressProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -63,65 +30,68 @@ export const PopUpUploadProgress = ({
|
|||||||
title,
|
title,
|
||||||
totalSize,
|
totalSize,
|
||||||
}: PopUpUploadProgressProps) => {
|
}: PopUpUploadProgressProps) => {
|
||||||
const initialRef = useRef(null);
|
const initialRef = useRef<HTMLButtonElement>(null);
|
||||||
const finalRef = useRef(null);
|
const finalRef = useRef<HTMLButtonElement>(null);
|
||||||
return (
|
return <></>;
|
||||||
<Modal
|
|
||||||
initialFocusRef={initialRef}
|
|
||||||
finalFocusRef={finalRef}
|
|
||||||
closeOnOverlayClick={false}
|
|
||||||
onClose={onClose}
|
|
||||||
isOpen={true}
|
|
||||||
>
|
|
||||||
<ModalOverlay />
|
|
||||||
<ModalContent>
|
|
||||||
<ModalHeader>{title}</ModalHeader>
|
|
||||||
<ModalCloseButton ref={finalRef} />
|
|
||||||
|
|
||||||
<ModalBody pb={6} paddingLeft="18px">
|
// return (
|
||||||
<Flex direction="column" gap="10px">
|
// <Dialog.Root
|
||||||
{isFinished ? (
|
// //initialFocusRef={initialRef}
|
||||||
<Text fontSize="20px" fontWeight="bold">
|
// //finalFocusRef={finalRef}
|
||||||
All {elements.length} element have been sent
|
// //closeOnOverlayClick={false}
|
||||||
</Text>
|
// onOpenChange={onClose}
|
||||||
) : (
|
// open={true}
|
||||||
<Text fontSize="20px" fontWeight="bold">
|
// data-testid="upload-progress-edit-pop-up"
|
||||||
[{index + 1}/{elements.length}] {elements[index]}
|
// >
|
||||||
</Text>
|
// {/* <DialogOverlay /> */}
|
||||||
)}
|
// <Dialog.Content>
|
||||||
<Progress
|
// <Dialog.Header>{title}</Dialog.Header>
|
||||||
colorScheme="green"
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
hasStripe
|
|
||||||
value={currentSize}
|
// <Dialog.Body pb={6} paddingLeft="18px">
|
||||||
isAnimated
|
// <Flex direction="column" gap="10px">
|
||||||
max={totalSize}
|
// {isFinished ? (
|
||||||
height="24px"
|
// <Text fontSize="20px" fontWeight="bold">
|
||||||
/>
|
// All {elements.length} element have been sent
|
||||||
<Flex>
|
// </Text>
|
||||||
<Text>{currentSize.toLocaleString('fr-FR')} Bytes</Text>
|
// ) : (
|
||||||
<Text marginLeft="auto">
|
// <Text fontSize="20px" fontWeight="bold">
|
||||||
{totalSize.toLocaleString('fr-FR')} Bytes
|
// [{index + 1}/{elements.length}] {elements[index]}
|
||||||
</Text>
|
// </Text>
|
||||||
</Flex>
|
// )}
|
||||||
{error && (
|
// <Progress.Root
|
||||||
<Text fontWeight="bold" color="darkred">
|
// colorScheme="green"
|
||||||
{error}
|
// striped
|
||||||
</Text>
|
// value={currentSize}
|
||||||
)}
|
// animated
|
||||||
</Flex>
|
// max={totalSize}
|
||||||
</ModalBody>
|
// height="24px"
|
||||||
<ModalFooter>
|
// />
|
||||||
{isFinished ? (
|
// <Flex>
|
||||||
<Button onClick={onClose} variant="@success">
|
// <Text>{currentSize.toLocaleString('fr-FR')} Bytes</Text>
|
||||||
Ok
|
// <Text marginLeft="auto">
|
||||||
</Button>
|
// {totalSize.toLocaleString('fr-FR')} Bytes
|
||||||
) : (
|
// </Text>
|
||||||
<Button colorScheme="red" mr={3} onClick={onAbort} ref={initialRef}>
|
// </Flex>
|
||||||
Abort
|
// {error && (
|
||||||
</Button>
|
// <Text fontWeight="bold" color="darkred">
|
||||||
)}
|
// {error}
|
||||||
</ModalFooter>
|
// </Text>
|
||||||
</ModalContent>
|
// )}
|
||||||
</Modal>
|
// </Flex>
|
||||||
);
|
// </Dialog.Body>
|
||||||
|
// <Dialog.Footer>
|
||||||
|
// {isFinished ? (
|
||||||
|
// <Button onClick={onClose} theme="@success">
|
||||||
|
// Ok
|
||||||
|
// </Button>
|
||||||
|
// ) : (
|
||||||
|
// <Button colorScheme="red" mr={3} onClick={onAbort} ref={initialRef}>
|
||||||
|
// Abort
|
||||||
|
// </Button>
|
||||||
|
// )}
|
||||||
|
// </Dialog.Footer>
|
||||||
|
// </Dialog.Content>
|
||||||
|
// </Dialog.Root>
|
||||||
|
// );
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
Text,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md';
|
import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -30,10 +19,11 @@ import { useOrderedGenders } from '@/service/Gender';
|
|||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { useSpecificTrack, useTrackService } from '@/service/Track';
|
import { useSpecificTrack, useTrackService } from '@/service/Track';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
|
|
||||||
export type TrackEditPopUpProps = {};
|
export type TrackEditPopUpProps = {};
|
||||||
|
|
||||||
export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
|
export const TrackEditPopUp = ({ }: TrackEditPopUpProps) => {
|
||||||
const { trackId } = useParams();
|
const { trackId } = useParams();
|
||||||
const trackIdInt = isNullOrUndefined(trackId)
|
const trackIdInt = isNullOrUndefined(trackId)
|
||||||
? undefined
|
? undefined
|
||||||
@@ -65,8 +55,8 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
|
|||||||
);
|
);
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
const initialRef = useRef(null);
|
const initialRef = useRef<HTMLButtonElement>(null);
|
||||||
const finalRef = useRef(null);
|
const finalRef = useRef<HTMLButtonElement>(null);
|
||||||
const form = useFormidable<Track>({
|
const form = useFormidable<Track>({
|
||||||
//onSubmit,
|
//onSubmit,
|
||||||
//onValuesChange,
|
//onValuesChange,
|
||||||
@@ -90,115 +80,117 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return <></>;
|
||||||
<Modal
|
// return (
|
||||||
initialFocusRef={initialRef}
|
// <Dialog.Root
|
||||||
finalFocusRef={finalRef}
|
// //initialFocusRef={initialRef}
|
||||||
closeOnOverlayClick={false}
|
// //finalFocusRef={finalRef}
|
||||||
onClose={onClose}
|
// //closeOnOverlayClick={false}
|
||||||
isOpen={true}
|
// onOpenChange={onClose}
|
||||||
>
|
// open={true}
|
||||||
<ModalOverlay />
|
// data-testid="track-edit-pop-up"
|
||||||
<ModalContent>
|
// >
|
||||||
<ModalHeader>Edit Track</ModalHeader>
|
// {/* <DialogOverlay /> */}
|
||||||
<ModalCloseButton ref={finalRef} />
|
// <Dialog.Content>
|
||||||
|
// <Dialog.Header>Edit Track</Dialog.Header>
|
||||||
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<ModalBody pb={6} gap="0px" paddingLeft="18px">
|
// <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
|
||||||
{admin && (
|
// {admin && (
|
||||||
<>
|
// <>
|
||||||
<FormGroup isRequired label="Id">
|
// <FormGroup isRequired label="Id">
|
||||||
<Text>{dataTrack?.id}</Text>
|
// <Text>{dataTrack?.id}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<FormGroup label="Data Id">
|
// <FormGroup label="Data Id">
|
||||||
<Text>{dataTrack?.dataId}</Text>
|
// <Text>{dataTrack?.dataId}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<FormGroup label="Action(s):">
|
// <FormGroup label="Action(s):">
|
||||||
<Button
|
// <Button
|
||||||
onClick={disclosure.onOpen}
|
// onClick={disclosure.onOpen}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
variant="@danger"
|
// theme="@danger"
|
||||||
>
|
// >
|
||||||
<MdDeleteForever /> Remove Media
|
// <MdDeleteForever /> Remove Media
|
||||||
</Button>
|
// </Button>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<ConfirmPopUp
|
// <ConfirmPopUp
|
||||||
disclosure={disclosure}
|
// disclosure={disclosure}
|
||||||
title="Remove track"
|
// title="Remove track"
|
||||||
body={`Remove Media [${dataTrack?.id}] ${dataTrack?.name}`}
|
// body={`Remove Media [${dataTrack?.id}] ${dataTrack?.name}`}
|
||||||
confirmTitle="Remove"
|
// confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
// onConfirm={onRemove}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
{!admin && (
|
// {!admin && (
|
||||||
<>
|
// <>
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="name"
|
// variableName="name"
|
||||||
isRequired
|
// isRequired
|
||||||
label="Title"
|
// label="Title"
|
||||||
ref={initialRef}
|
// ref={initialRef}
|
||||||
/>
|
// />
|
||||||
<FormTextarea
|
// <FormTextarea
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="description"
|
// variableName="description"
|
||||||
label="Description"
|
// label="Description"
|
||||||
/>
|
// />
|
||||||
<FormSelect
|
// <FormSelect
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="genderId"
|
// variableName="genderId"
|
||||||
options={dataGenders}
|
// options={dataGenders}
|
||||||
label="Gender"
|
// label="Gender"
|
||||||
/>
|
// />
|
||||||
<FormSelectMultiple
|
// <FormSelectMultiple
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="artists"
|
// variableName="artists"
|
||||||
options={dataArtist}
|
// options={dataArtist}
|
||||||
label="Artist(s)"
|
// label="Artist(s)"
|
||||||
/>
|
// />
|
||||||
<FormSelect
|
// <FormSelect
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="albumId"
|
// variableName="albumId"
|
||||||
options={dataAlbums}
|
// options={dataAlbums}
|
||||||
label="Album"
|
// label="Album"
|
||||||
/>
|
// />
|
||||||
<FormNumber
|
// <FormNumber
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="track"
|
// variableName="track"
|
||||||
label="Track n°"
|
// label="Track n°"
|
||||||
step={1}
|
// step={1}
|
||||||
defaultValue={0}
|
// //defaultValue={0}
|
||||||
min={0}
|
// min={0}
|
||||||
max={1000}
|
// max={1000}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</ModalBody>
|
// </Dialog.Body>
|
||||||
<ModalFooter>
|
// <Dialog.Footer>
|
||||||
<Button
|
// <Button
|
||||||
onClick={() => setAdmin((value) => !value)}
|
// onClick={() => setAdmin((value) => !value)}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
>
|
// >
|
||||||
{admin ? (
|
// {admin ? (
|
||||||
<>
|
// <>
|
||||||
<MdEdit />
|
// <MdEdit />
|
||||||
Edit
|
// Edit
|
||||||
</>
|
// </>
|
||||||
) : (
|
// ) : (
|
||||||
<>
|
// <>
|
||||||
<MdAdminPanelSettings />
|
// <MdAdminPanelSettings />
|
||||||
Admin
|
// Admin
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</Button>
|
// </Button>
|
||||||
{!admin && form.isFormModified && (
|
// {!admin && form.isFormModified && (
|
||||||
<Button colorScheme="blue" mr={3} onClick={onSave}>
|
// <Button colorScheme="blue" mr={3} onClick={onSave}>
|
||||||
Save
|
// Save
|
||||||
</Button>
|
// </Button>
|
||||||
)}
|
// )}
|
||||||
<Button onClick={onClose}>Cancel</Button>
|
// <Button onClick={onClose}>Cancel</Button>
|
||||||
</ModalFooter>
|
// </Dialog.Footer>
|
||||||
</ModalContent>
|
// </Dialog.Content>
|
||||||
</Modal>
|
// </Dialog.Root>
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { Box, Button, Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { MdAdd } from 'react-icons/md';
|
import { MdAdd } from 'react-icons/md';
|
||||||
|
|
||||||
import { isNullOrUndefined, isNumber } from '@/utils/validator';
|
import { isNullOrUndefined, isNumber } from '@/utils/validator';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export type SelectListModel = {
|
export type SelectListModel = {
|
||||||
id: any;
|
id: any;
|
||||||
@@ -65,56 +65,65 @@ export const SelectList = ({
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<Box position="relative">
|
<Flex style={{ position: "relative" }}>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
width="full"
|
style={{
|
||||||
position="absolute"
|
width: "100%",
|
||||||
border="1px"
|
position: "absolute",
|
||||||
borderColor="black"
|
border: "1px",
|
||||||
backgroundColor="gray.700"
|
borderColor: "black",
|
||||||
overflowY="auto"
|
background: "gray.700",
|
||||||
overflowX="hidden"
|
overflowY: "auto",
|
||||||
maxHeight="300px"
|
overflowX: "hidden",
|
||||||
zIndex={300}
|
maxHeight: "300px",
|
||||||
transform="translateY(1px)"
|
zIndex: 300,
|
||||||
|
transform: "translateY(1px)",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{displayedValue.length === 0 && (
|
{displayedValue.length === 0 && (
|
||||||
<Text marginX="auto" color="red.500" fontWeight="bold" marginY="10px">
|
<Text fontWeight="bold" color="red.500" style={{ margin: "0 auto" }}>
|
||||||
... No element found...
|
... No element found...
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
{displayedValue.map((data) => (
|
{displayedValue.map((data) => (
|
||||||
<Button
|
<Button
|
||||||
key={data.id}
|
key={data.id}
|
||||||
marginY="1px"
|
style={{
|
||||||
borderRadius="0px"
|
margin: "1px 0",
|
||||||
autoFocus={false}
|
borderRadius: "0px",
|
||||||
backgroundColor={data.isSelected ? 'green.800' : '0x00000000'}
|
//autoFocus: false,
|
||||||
_hover={{ backgroundColor: 'gray.400' }}
|
background: data.isSelected ? 'green.800' : '0x00000000',
|
||||||
|
//_hover={ background: 'gray.400' },
|
||||||
|
}}
|
||||||
onClick={() => onSelectValue(data)}
|
onClick={() => onSelectValue(data)}
|
||||||
ref={data.isSelected ? scrollToRef : undefined}
|
//ref={data.isSelected ? scrollToRef : undefined}
|
||||||
>
|
>
|
||||||
<Text marginRight="auto" autoFocus={false}>
|
<Text style={{ margin: "0 auto", }} /*autoFocus={false}*/>
|
||||||
{data.name}
|
{data.name}
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
{onCreate && search && search.length > 0 && (
|
{onCreate && search && search.length > 0 && (
|
||||||
<Button
|
<Button
|
||||||
marginY="1px"
|
style={{
|
||||||
borderRadius="0px"
|
margin: "1px 0",
|
||||||
autoFocus={false}
|
borderRadius: "0px",
|
||||||
_hover={{ backgroundColor: 'gray.400' }}
|
//autoFocus:false,
|
||||||
|
//_hover={ background: 'gray.400' }
|
||||||
|
}}
|
||||||
onClick={() => onCreate(search)}
|
onClick={() => onCreate(search)}
|
||||||
>
|
>
|
||||||
<Flex marginRight="auto">
|
<Flex
|
||||||
|
style={{
|
||||||
|
margin: "0 auto",
|
||||||
|
}}>
|
||||||
<MdAdd />
|
<MdAdd />
|
||||||
<Text autoFocus={false}>Create '{search}'</Text>
|
<Text /*autoFocus={false}*/>Create '{search}'</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
import { RefObject, useEffect, useMemo, useRef, useState } from 'react';
|
import { RefObject, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Input,
|
|
||||||
Spinner,
|
|
||||||
Tag,
|
|
||||||
TagCloseButton,
|
|
||||||
TagLabel,
|
|
||||||
Wrap,
|
|
||||||
WrapItem,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { MdEdit, MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md';
|
import { MdEdit, MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md';
|
||||||
|
|
||||||
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { Button, Flex, HStack, Input } from '@/ui';
|
||||||
|
|
||||||
export type SelectMultipleProps = {
|
export type SelectMultipleProps = {
|
||||||
options?: object[];
|
options?: object[];
|
||||||
@@ -85,7 +75,7 @@ export const SelectMultiple = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!options) {
|
if (!options) {
|
||||||
return <Spinner />;
|
return <></>;// TODO: <Spinner />;
|
||||||
}
|
}
|
||||||
const onChangeInput = (value: string): void => {
|
const onChangeInput = (value: string): void => {
|
||||||
setHasSuggestion(false);
|
setHasSuggestion(false);
|
||||||
@@ -109,42 +99,47 @@ export const SelectMultiple = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" width="full" gap="0px">
|
<Flex direction="column" width="100%" gap="0px">
|
||||||
{selectedOptions && (
|
{selectedOptions && (
|
||||||
<Wrap spacing="5px" justify="left" width="full" marginBottom="2px">
|
<HStack style={{ flexWrap: "wrap", /*spacing="5px"*/ justifyContent: "left", width: "100%", marginBottom: "2px" }}>
|
||||||
{selectedOptions.map((data) => (
|
{selectedOptions.map((data) => (
|
||||||
<WrapItem key={data[keyKey]}>
|
<Flex align="flex-start" key={data[keyKey]}>
|
||||||
<Tag
|
{/* <Tag.Root
|
||||||
size="md"
|
size="md"
|
||||||
key="md"
|
key="md"
|
||||||
borderRadius="5px"
|
borderRadius="5px"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
backgroundColor="green.500"
|
background="green.500"
|
||||||
>
|
>
|
||||||
<TagLabel>{data[keyValue] ?? `id=${data[keyKey]}`}</TagLabel>
|
<Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label>
|
||||||
<TagCloseButton onClick={() => selectValue(data)} />
|
<Tag.CloseTrigger onClick={() => selectValue(data)} />
|
||||||
</Tag>
|
</Tag.Root> */}
|
||||||
</WrapItem>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Wrap>
|
</HStack>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Flex>
|
<Flex>
|
||||||
<Input
|
<Input
|
||||||
ref={refFocus}
|
ref={refFocus}
|
||||||
width="full"
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: "5px 0 0 5px",
|
||||||
|
}}
|
||||||
onChange={(e) => onChangeInput(e.target.value)}
|
onChange={(e) => onChangeInput(e.target.value)}
|
||||||
//onSubmit={onSubmit}
|
//onSubmit={onSubmit}
|
||||||
onFocus={() => setShowList(true)}
|
// TODO: onFocus={() => setShowList(true)}
|
||||||
onBlur={() => setTimeout(() => setShowList(false), 200)}
|
// TODO: onBlur={() => setTimeout(() => setShowList(false), 200)}
|
||||||
value={showList ? (currentSearch ?? '') : hasSuggestion ? `suggest: ${currentSearch}` : ''}
|
value={showList ? (currentSearch ?? '') : hasSuggestion ? `suggest: ${currentSearch}` : ''}
|
||||||
borderRadius="5px 0 0 5px"
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={onOpenClose}
|
onClick={onOpenClose}
|
||||||
variant="outline"
|
//variant="outline"
|
||||||
borderRadius="0 5px 5px 0"
|
style={{
|
||||||
borderWidth="1px 1px 1px 0"
|
borderRadius: "0 5px 5px 0",
|
||||||
|
borderWidth: "1px 1px 1px 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{showList ? (
|
{showList ? (
|
||||||
<MdKeyboardArrowUp color="gray.300" />
|
<MdKeyboardArrowUp color="gray.300" />
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { RefObject, useEffect, useMemo, useRef, useState } from 'react';
|
import { RefObject, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { Button, Flex, Input, Spinner } from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
MdClose,
|
MdClose,
|
||||||
MdEdit,
|
MdEdit,
|
||||||
@@ -10,6 +9,7 @@ import {
|
|||||||
|
|
||||||
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { Button, Flex, Input } from '@/ui';
|
||||||
|
|
||||||
export type SelectSingleProps = {
|
export type SelectSingleProps = {
|
||||||
options?: object[];
|
options?: object[];
|
||||||
@@ -70,7 +70,7 @@ export const SelectSingle = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!transformedOption) {
|
if (!transformedOption) {
|
||||||
return <Spinner />;
|
return <></>; // TODO: <Spinner />;
|
||||||
}
|
}
|
||||||
function onChangeInput(value: string): void {
|
function onChangeInput(value: string): void {
|
||||||
setHasSuggestion(false);
|
setHasSuggestion(false);
|
||||||
@@ -101,48 +101,53 @@ export const SelectSingle = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" width="full" gap="0px">
|
<Flex direction="column" width="100%" gap="0px">
|
||||||
<Flex>
|
<Flex>
|
||||||
<Input
|
<Input
|
||||||
ref={refFocus}
|
ref={refFocus}
|
||||||
width="full"
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
background: showList || !selectedOptions ? undefined : 'green.500',
|
||||||
|
borderRadius: "5px 0 0 5px",
|
||||||
|
}}
|
||||||
onChange={(e) => onChangeInput(e.target.value)}
|
onChange={(e) => onChangeInput(e.target.value)}
|
||||||
onFocus={() => setShowList(true)}
|
//onFocus={() => setShowList(true)}
|
||||||
onBlur={() => setTimeout(() => setShowList(false), 200)}
|
//onBlur={() => setTimeout(() => setShowList(false), 200)}
|
||||||
value={
|
value={
|
||||||
showList ? (currentSearch ?? '') : (selectedOptions?.name ?? (hasSuggestion ? `suggest: ${currentSearch}` : ''))
|
showList ? (currentSearch ?? '') : (selectedOptions?.name ?? (hasSuggestion ? `suggest: ${currentSearch}` : ''))
|
||||||
}
|
}
|
||||||
backgroundColor={
|
|
||||||
showList || !selectedOptions ? undefined : 'green.500'
|
|
||||||
}
|
|
||||||
borderRadius="5px 0 0 5px"
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={onRemoveItem}
|
onClick={onRemoveItem}
|
||||||
variant="outline"
|
// TODO: variant="outline"
|
||||||
borderRadius="0 5px 5px 0"
|
style={{
|
||||||
borderWidth="1px 1px 1px 0"
|
borderRadius: "0 5px 5px 0",
|
||||||
|
borderWidth: "1px 1px 1px 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{selectedOptions ? (
|
{
|
||||||
<MdClose color="gray.300" />
|
selectedOptions ? (
|
||||||
) : showList ? (
|
<MdClose color="gray.300" />
|
||||||
<MdKeyboardArrowUp color="gray.300" />
|
) : showList ? (
|
||||||
) : hasSuggestion ? (
|
<MdKeyboardArrowUp color="gray.300" />
|
||||||
<MdEdit color="gray.300" />
|
) : hasSuggestion ? (
|
||||||
) : (
|
<MdEdit color="gray.300" />
|
||||||
<MdKeyboardArrowDown color="gray.300" />
|
) : (
|
||||||
)}
|
<MdKeyboardArrowDown color="gray.300" />
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
{showList && (
|
{
|
||||||
<SelectList
|
showList && (
|
||||||
options={transformedOption}
|
<SelectList
|
||||||
selected={selectedOptions ? [selectedOptions] : []}
|
options={transformedOption}
|
||||||
search={currentSearch}
|
selected={selectedOptions ? [selectedOptions] : []}
|
||||||
onSelectValue={selectValue}
|
search={currentSearch}
|
||||||
onCreate={createNewItem}
|
onSelectValue={selectValue}
|
||||||
/>
|
onCreate={createNewItem}
|
||||||
)}
|
/>
|
||||||
</Flex>
|
)
|
||||||
|
}
|
||||||
|
</Flex >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { LuMusic2, LuPlay } from 'react-icons/lu';
|
|
||||||
|
|
||||||
import { Track } from '@/back-api';
|
import { Track } from '@/back-api';
|
||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
import { ContextMenu, MenuElement } from '@/components/contextMenu/ContextMenu';
|
import { ContextMenu, MenuElement } from '@/components/contextMenu/ContextMenu';
|
||||||
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
|
import { Flex, Span } from '@/ui';
|
||||||
|
|
||||||
export type DisplayTrackProps = {
|
export type DisplayTrackProps = {
|
||||||
track: Track;
|
track: Track;
|
||||||
@@ -18,38 +18,41 @@ export const DisplayTrack = ({
|
|||||||
}: DisplayTrackProps) => {
|
}: DisplayTrackProps) => {
|
||||||
const { trackActive } = useActivePlaylistService();
|
const { trackActive } = useActivePlaylistService();
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full">
|
||||||
<Covers
|
<Covers
|
||||||
data={track?.covers}
|
data={track?.covers}
|
||||||
size="50"
|
size="50"
|
||||||
height="full"
|
height="full"
|
||||||
iconEmpty={
|
/* TODO: iconEmpty={
|
||||||
trackActive?.id === track.id ? LuPlay : LuMusic2
|
trackActive?.id === track.id ? LuPlay : LuMusic2
|
||||||
}
|
} */
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
width="full"
|
width="100%"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
|
overflowX: "hidden",
|
||||||
|
}}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
align="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
noOfLines={[1, 2]}
|
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
[{track.track}] {track.name}
|
[{track.track}] {track.name}
|
||||||
</Text>
|
</Span>
|
||||||
</Flex>
|
</Flex>
|
||||||
<ContextMenu elements={contextMenu} />
|
<ContextMenu elements={contextMenu} />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import { Suspense } from 'react';
|
|
||||||
|
|
||||||
import { Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { LuMusic2, LuPlay } from 'react-icons/lu';
|
|
||||||
|
|
||||||
import { Track } from '@/back-api';
|
import { Track } from '@/back-api';
|
||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
@@ -10,6 +7,7 @@ import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
|||||||
import { useSpecificAlbum } from '@/service/Album';
|
import { useSpecificAlbum } from '@/service/Album';
|
||||||
import { useSpecificArtists } from '@/service/Artist';
|
import { useSpecificArtists } from '@/service/Artist';
|
||||||
import { useSpecificGender } from '@/service/Gender';
|
import { useSpecificGender } from '@/service/Gender';
|
||||||
|
import { Flex, Span } from '@/ui';
|
||||||
|
|
||||||
export type DisplayTrackProps = {
|
export type DisplayTrackProps = {
|
||||||
track: Track;
|
track: Track;
|
||||||
@@ -26,87 +24,98 @@ export const DisplayTrackFull = ({
|
|||||||
const { dataGender } = useSpecificGender(track?.genderId);
|
const { dataGender } = useSpecificGender(track?.genderId);
|
||||||
const { dataArtists } = useSpecificArtists(track?.artists);
|
const { dataArtists } = useSpecificArtists(track?.artists);
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full"
|
||||||
|
data-testid="display-track-full">
|
||||||
<Covers
|
<Covers
|
||||||
data={track?.covers}
|
data={track?.covers}
|
||||||
size="50"
|
size="50"
|
||||||
marginY="auto"
|
marginY="auto"
|
||||||
iconEmpty={
|
/* TODO: iconEmpty={
|
||||||
trackActive?.id === track.id ? LuPlay : LuMusic2
|
trackActive?.id === track.id ? LuPlay : LuMusic2
|
||||||
}
|
} */
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
width="full"
|
width="100%"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
style={{
|
||||||
|
overflowX: "hidden",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
align="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
noOfLines={1}
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={1}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{track.name} {track.track && ` [${track.track}]`}
|
{track.name} {track.track && ` [${track.track}]`}
|
||||||
</Text>
|
</Span>
|
||||||
{dataAlbum && (
|
{dataAlbum && (
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
align="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
//noOfLines={1}
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
noOfLines={1}
|
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text as="span" fontWeight="normal">Album:</Text> {dataAlbum.name}
|
<Span fontWeight="normal">Album:</Span> {dataAlbum.name}
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
{dataArtists && (
|
{dataArtists && (
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
align="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
noOfLines={1}
|
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text as="span" fontWeight="normal">Artist(s):</Text> {dataArtists.map((data) => data.name).join(', ')}
|
<Span fontWeight="normal">Artist(s):</Span> {dataArtists.map((data) => data.name).join(', ')}
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
{dataGender && (
|
{dataGender && (
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
align="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
noOfLines={1}
|
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text as="span" fontWeight="normal">Gender:</Text> {dataGender.name}
|
<Span fontWeight="normal">Gender:</Span> {dataGender.name}
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<ContextMenu elements={contextMenu} />
|
<ContextMenu elements={contextMenu}
|
||||||
|
data-testid="display-track-full_context-menu" />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
27
front/src/components/track/DisplayTrackFullId.tsx
Normal file
27
front/src/components/track/DisplayTrackFullId.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Track } from '@/back-api';
|
||||||
|
import { MenuElement } from '@/components/contextMenu/ContextMenu';
|
||||||
|
import { useSpecificTrack } from '@/service/Track';
|
||||||
|
import { DisplayTrackFull } from './DisplayTrackFull';
|
||||||
|
import { DisplayTrackSkeleton } from './DisplayTrackSkeleton';
|
||||||
|
|
||||||
|
export type DisplayTrackProps = {
|
||||||
|
trackId: Track["id"];
|
||||||
|
onClick?: () => void;
|
||||||
|
contextMenu?: MenuElement[];
|
||||||
|
};
|
||||||
|
export const DisplayTrackFullId = ({
|
||||||
|
trackId,
|
||||||
|
onClick,
|
||||||
|
contextMenu,
|
||||||
|
}: DisplayTrackProps) => {
|
||||||
|
const { dataTrack } = useSpecificTrack(trackId);
|
||||||
|
if (dataTrack) {
|
||||||
|
return (
|
||||||
|
<DisplayTrackFull track={dataTrack} onClick={onClick} contextMenu={contextMenu} />
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<DisplayTrackSkeleton />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,29 +1,32 @@
|
|||||||
import { Flex, Skeleton, SkeletonText } from '@chakra-ui/react';
|
import { Flex } from "@/ui";
|
||||||
|
|
||||||
|
|
||||||
export const DisplayTrackSkeleton = () => {
|
export const DisplayTrackSkeleton = () => {
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full">
|
||||||
<Skeleton
|
{/* <Skeleton
|
||||||
borderRadius="0px"
|
borderRadius="0px"
|
||||||
height="50"
|
height="50"
|
||||||
width="50"
|
width="50"
|
||||||
minWidth="50"
|
minWidth="50"
|
||||||
minHeight="50"
|
minHeight="50"
|
||||||
/>
|
/> */}
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
width="full"
|
width="100%"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
|
overflowX: "hidden"
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<SkeletonText
|
{/* <SkeletonText
|
||||||
skeletonHeight="20px"
|
skeletonHeight="20px"
|
||||||
noOfLines={1}
|
noOfLines={1}
|
||||||
spacing={0}
|
spacing={0}
|
||||||
width="50%"
|
width="50%"
|
||||||
marginY="auto"
|
marginY="auto"
|
||||||
/>
|
/> */}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
0
front/src/components/ui/index.ts
Normal file
0
front/src/components/ui/index.ts
Normal file
39
front/src/components/ui/toaster.tsx
Normal file
39
front/src/components/ui/toaster.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { RestErrorResponse } from "@/back-api";
|
||||||
|
import { HStack } from "@/ui";
|
||||||
|
|
||||||
|
// export const toaster = createToaster({
|
||||||
|
// placement: "bottom-end",
|
||||||
|
// pauseOnPageIdle: true,
|
||||||
|
// })
|
||||||
|
|
||||||
|
// export const toasterAPIError = (error: RestErrorResponse) => {
|
||||||
|
// toaster.create({
|
||||||
|
// title: `[${error.status}] ${error.statusMessage}`,
|
||||||
|
// description: error.message,
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export const Toaster = () => {
|
||||||
|
// return (
|
||||||
|
// <Portal>
|
||||||
|
// <ArkToaster toaster={toaster}>
|
||||||
|
// {(toast) => (
|
||||||
|
// <Toast.Root>
|
||||||
|
// <HStack spacing="1" style={{ width: "100%" }}>
|
||||||
|
// {toast.title && <Toast.Title>{toast.title}</Toast.Title>}
|
||||||
|
// {toast.description && (
|
||||||
|
// <Toast.Description>{toast.description}</Toast.Description>
|
||||||
|
// )}
|
||||||
|
// </HStack>
|
||||||
|
// {toast.action && (
|
||||||
|
// <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
|
||||||
|
// )}
|
||||||
|
// {toast.meta?.closable && <Toast.CloseTrigger />}
|
||||||
|
// </Toast.Root>
|
||||||
|
// )}
|
||||||
|
// </ArkToaster>
|
||||||
|
// </Portal>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import dayjs from 'dayjs';
|
|
||||||
import 'dayjs/locale/fr';
|
|
||||||
import advancedFormat from 'dayjs/plugin/advancedFormat';
|
|
||||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
||||||
import dayOfYear from 'dayjs/plugin/dayOfYear';
|
|
||||||
import duration from 'dayjs/plugin/duration';
|
|
||||||
import isBetween from 'dayjs/plugin/isBetween';
|
|
||||||
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
|
|
||||||
import isToday from 'dayjs/plugin/isToday';
|
|
||||||
import isTomorrow from 'dayjs/plugin/isTomorrow';
|
|
||||||
import isYesterday from 'dayjs/plugin/isYesterday';
|
|
||||||
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
|
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
||||||
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
|
||||||
|
|
||||||
dayjs.locale('fr');
|
|
||||||
dayjs.extend(relativeTime);
|
|
||||||
dayjs.extend(customParseFormat);
|
|
||||||
dayjs.extend(weekOfYear);
|
|
||||||
dayjs.extend(isSameOrAfter);
|
|
||||||
dayjs.extend(isToday);
|
|
||||||
dayjs.extend(isTomorrow);
|
|
||||||
dayjs.extend(isYesterday);
|
|
||||||
dayjs.extend(dayOfYear);
|
|
||||||
dayjs.extend(isBetween);
|
|
||||||
dayjs.extend(advancedFormat);
|
|
||||||
dayjs.extend(quarterOfYear);
|
|
||||||
dayjs.extend(duration);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import './axios';
|
|
||||||
import './dayjs';
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export const BASE_WRAP_SPACING = { base: "5px", md: "10px", lg: "20px" };
|
export const BASE_WRAP_SPACING = "5px"; // { base: "5px", md: "10px", lg: "20px" };
|
||||||
export const BASE_WRAP_WIDTH = { base: "90%", md: "45%", lg: "270px" };
|
export const BASE_WRAP_WIDTH = "90%"; // { base: "90%", md: "45%", lg: "270px" };
|
||||||
export const BASE_WRAP_HEIGHT = { base: "75px", lg: "120px" };
|
export const BASE_WRAP_HEIGHT = "75px"; // { base: "75px", lg: "120px" };
|
||||||
export const BASE_WRAP_ICON_SIZE = { base: "50px", lg: "100px" };
|
export const BASE_WRAP_ICON_SIZE = "50px";// { base: "50px", lg: "100px" };
|
||||||
@@ -25,9 +25,9 @@ const environment_back_prod: Environment = {
|
|||||||
karso: `${serverSSOAddress}/karso/api`,
|
karso: `${serverSSOAddress}/karso/api`,
|
||||||
},
|
},
|
||||||
ssoSite: `${serverSSOAddress}/karso/`,
|
ssoSite: `${serverSSOAddress}/karso/`,
|
||||||
ssoSignIn: `${serverSSOAddress}/karso/signin/karusic-dev/`,
|
ssoSignIn: `${serverSSOAddress}/karso/signin/karusic/`,
|
||||||
ssoSignUp: `${serverSSOAddress}/karso/signup/karusic-dev/`,
|
ssoSignUp: `${serverSSOAddress}/karso/signup/karusic/`,
|
||||||
ssoSignOut: `${serverSSOAddress}/karso/signout/karusic-dev/`,
|
ssoSignOut: `${serverSSOAddress}/karso/signout/karusic/`,
|
||||||
tokenStoredInPermanentStorage: false,
|
tokenStoredInPermanentStorage: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ const environment_local: Environment = {
|
|||||||
ssoSignUp: `${serverSSOAddress}/karso/signup/karusic-dev/`,
|
ssoSignUp: `${serverSSOAddress}/karso/signup/karusic-dev/`,
|
||||||
ssoSignOut: `${serverSSOAddress}/karso/signout/karusic-dev/`,
|
ssoSignOut: `${serverSSOAddress}/karso/signout/karusic-dev/`,
|
||||||
tokenStoredInPermanentStorage: false,
|
tokenStoredInPermanentStorage: false,
|
||||||
//replaceDataToRealServer: true,
|
replaceDataToRealServer: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const environment_full_local: Environment = {
|
const environment_full_local: Environment = {
|
||||||
@@ -80,7 +80,6 @@ const environment_hybrid: Environment = {
|
|||||||
tokenStoredInPermanentStorage: false,
|
tokenStoredInPermanentStorage: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const environment = environment_local;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current environment is for development
|
* Check if the current environment is for development
|
||||||
@@ -90,6 +89,9 @@ export const isDevelopmentEnvironment = () => {
|
|||||||
return import.meta.env.MODE === 'development';
|
return import.meta.env.MODE === 'development';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const environment = isDevelopmentEnvironment() ? environment_local : environment_back_prod;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the current REST api URL. Depend on the VITE_API_BASE_URL env variable.
|
* get the current REST api URL. Depend on the VITE_API_BASE_URL env variable.
|
||||||
* @returns The URL with http(s)://***
|
* @returns The URL with http(s)://***
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
import { Box, Button, Center, Heading, Text } from '@chakra-ui/react';
|
|
||||||
import { MdControlCamera } from 'react-icons/md';
|
import { MdControlCamera } from 'react-icons/md';
|
||||||
|
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex, Link, Text } from '@/ui';
|
||||||
|
|
||||||
export const Error401 = () => {
|
export const Error401 = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter padding="25px">
|
<PageLayoutInfoCenter padding="25px" width="75%">
|
||||||
<Center>
|
<Flex align="center">
|
||||||
<MdControlCamera size="250px" color="red.600" />
|
<MdControlCamera size="250px" color="red.600" />
|
||||||
</Center>
|
</Flex>
|
||||||
<Box textAlign="center">
|
<Flex style={{ textAlign: "center" }}>
|
||||||
<Heading>Erreur 401</Heading>
|
<Text fontSize="px">Erreur 401</Text>
|
||||||
<Text color="red.600">
|
<Text color="red.600">
|
||||||
Vous n'êtes pas autorisé a accéder a ce contenu.
|
Vous n'êtes pas autorisé a accéder a ce contenu.
|
||||||
</Text>
|
</Text>
|
||||||
<Button as="a" variant="link" href="/">
|
<Link href="/">
|
||||||
Retour à l'accueil
|
Retour à l'accueil
|
||||||
</Button>
|
</Link>
|
||||||
</Box>
|
</Flex>
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
import { Box, Button, Center, Heading, Text } from '@chakra-ui/react';
|
import { MdControlCamera } from 'react-icons/md';
|
||||||
import { MdDangerous } from 'react-icons/md';
|
|
||||||
|
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex, Link, Text } from '@/ui';
|
||||||
|
|
||||||
export const Error403 = () => {
|
export const Error403 = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter padding="25px">
|
<PageLayoutInfoCenter padding="25px" width="75%">
|
||||||
<Center>
|
<Flex align="center">
|
||||||
<MdDangerous size="250px" color="orange.600" />
|
<MdControlCamera size="250px" color="red.600" />
|
||||||
</Center>
|
</Flex>
|
||||||
<Box textAlign="center">
|
<Flex style={{ textAlign: "center" }}>
|
||||||
<Heading>Erreur 401</Heading>
|
<Text fontSize="px">Erreur 403</Text>
|
||||||
<Text color="orange.600">Cette page vous est interdite</Text>
|
<Text color="red.600">
|
||||||
<Button as="a" variant="link" href="/">
|
Cette page vous est interdite.
|
||||||
|
</Text>
|
||||||
|
<Link href="/">
|
||||||
Retour à l'accueil
|
Retour à l'accueil
|
||||||
</Button>
|
</Link>
|
||||||
</Box>
|
</Flex>
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
import { Box, Button, Center, Heading, Text } from '@chakra-ui/react';
|
import { MdControlCamera } from 'react-icons/md';
|
||||||
import { MdSignpost } from 'react-icons/md';
|
|
||||||
|
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex, Link, Text } from '@/ui';
|
||||||
|
|
||||||
export const Error404 = () => {
|
export const Error404 = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter padding="25px">
|
<PageLayoutInfoCenter padding="25px" width="75%">
|
||||||
<Center>
|
<Flex align="center">
|
||||||
<MdSignpost size="250px" />
|
<MdControlCamera size="250px" color="red.600" />
|
||||||
</Center>
|
</Flex>
|
||||||
<Box textAlign="center">
|
<Flex style={{ textAlign: "center" }}>
|
||||||
<Heading>Erreur 404</Heading>
|
<Text fontSize="px">Erreur 404</Text>
|
||||||
<Text color="gray.600">
|
<Text color="red.600">
|
||||||
Cette page n'existe plus ou l'URL a changé
|
Cette page n'existe plus ou l'URL a changé.
|
||||||
</Text>
|
</Text>
|
||||||
<Button as="a" variant="link" href="/">
|
<Link href="/">
|
||||||
Retour à l'accueil
|
Retour à l'accueil
|
||||||
</Button>
|
</Link>
|
||||||
</Box>
|
</Flex>
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,48 +1,44 @@
|
|||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Alert,
|
|
||||||
AlertDescription,
|
|
||||||
AlertIcon,
|
|
||||||
AlertTitle,
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Collapse,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import {
|
import {
|
||||||
FallbackProps,
|
FallbackProps,
|
||||||
ErrorBoundary as ReactErrorBoundary,
|
ErrorBoundary as ReactErrorBoundary,
|
||||||
} from 'react-error-boundary';
|
} from 'react-error-boundary';
|
||||||
import { LuChevronDown, LuChevronUp } from 'react-icons/lu';
|
import { LuChevronUp, LuChevronDown } from 'react-icons/lu';
|
||||||
|
|
||||||
const ErrorFallback = ({ error }: FallbackProps) => {
|
const ErrorFallback = ({ error }: FallbackProps) => {
|
||||||
const { isOpen, onToggle } = useDisclosure();
|
const { open, onToggle } = useDisclosure();
|
||||||
return (
|
return (
|
||||||
<Box p="4" m="auto">
|
<Flex direction="column" style={{ padding: 4, margin: "auto", background: "red.500" }}>
|
||||||
<Alert status="error" borderRadius="md">
|
<Text color='red'>An unexpected error has occurred.</Text>
|
||||||
<AlertIcon />
|
<Text>Message: {error.message}</Text>
|
||||||
<Box flex="1">
|
{/*
|
||||||
|
<AlertRoot status="error" borderRadius="md">
|
||||||
|
<Flex style={{ flex: "1" }}>
|
||||||
<AlertTitle>An unexpected error has occurred.</AlertTitle>
|
<AlertTitle>An unexpected error has occurred.</AlertTitle>
|
||||||
<AlertDescription display="block" lineHeight="1.4">
|
<AlertDescription display="block" lineHeight="1.4">
|
||||||
<Button
|
<Button
|
||||||
variant="link"
|
//theme="@secondary"
|
||||||
color="red.800"
|
color="red.800"
|
||||||
size="sm"
|
//size="sm"
|
||||||
rightIcon={isOpen ? <LuChevronUp /> : <LuChevronDown />}
|
|
||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
>
|
>
|
||||||
Show details
|
Show details {open ? <LuChevronUp /> : <LuChevronDown />}
|
||||||
</Button>
|
</Button>
|
||||||
<Collapse in={isOpen} animateOpacity>
|
<Collapsible.Root open={open}>
|
||||||
<Box mt={4} fontFamily="monospace">
|
<Collapsible.Content>
|
||||||
{error.message}
|
<Flex mt={4} fontFamily="monospace">
|
||||||
</Box>
|
{error.message}
|
||||||
</Collapse>
|
</Flex>
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Box>
|
</Flex>
|
||||||
</Alert>
|
</AlertRoot> */}
|
||||||
</Box>
|
</Flex >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { createIcon } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
export const DoubleArrowIcon = createIcon({
|
|
||||||
displayName: 'DoubleArrowIcon',
|
export const DoubleArrowIcon = <></>;
|
||||||
viewBox: '0 0 24 24',
|
// createIcon({
|
||||||
path: (
|
// displayName: 'DoubleArrowIcon',
|
||||||
<path
|
// viewBox: '0 0 24 24',
|
||||||
fillRule="evenodd"
|
// path: (
|
||||||
clipRule="evenodd"
|
// <path
|
||||||
d="M1.293 12.207a1 1 0 0 1 0-1.414l6.364-6.364A1 1 0 0 1 9.07 5.843L4.414 10.5h15.172l-4.657-4.657a1 1 0 0 1 1.414-1.414l6.364 6.364a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414-1.414l4.657-4.657H4.414l4.657 4.657a1 1 0 1 1-1.414 1.414l-6.364-6.364Z"
|
// fillRule="evenodd"
|
||||||
fill="currentColor"
|
// clipRule="evenodd"
|
||||||
/>
|
// d="M1.293 12.207a1 1 0 0 1 0-1.414l6.364-6.364A1 1 0 0 1 9.07 5.843L4.414 10.5h15.172l-4.657-4.657a1 1 0 0 1 1.414-1.414l6.364 6.364a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414-1.414l4.657-4.657H4.414l4.657 4.657a1 1 0 1 1-1.414 1.414l-6.364-6.364Z"
|
||||||
),
|
// fill="currentColor"
|
||||||
});
|
// />
|
||||||
|
// ),
|
||||||
|
// });
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { StrictMode } from 'react';
|
|
||||||
|
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
|
|
||||||
import App from '@/App';
|
import App from '@/App';
|
||||||
|
import { ThemeProvider } from './theme/ThemeContext';
|
||||||
|
import { StrictMode } from 'react';
|
||||||
// Render the app
|
// Render the app
|
||||||
const rootElement = document.getElementById('root');
|
const rootElement = document.getElementById('root');
|
||||||
if (rootElement && !rootElement.innerHTML) {
|
if (rootElement && !rootElement.innerHTML) {
|
||||||
const root = ReactDOM.createRoot(rootElement);
|
const root = ReactDOM.createRoot(rootElement);
|
||||||
root.render(
|
root.render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<ThemeProvider>
|
||||||
|
<App />
|
||||||
|
</ThemeProvider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { AudioPlayer } from '@/components/AudioPlayer';
|
import { AudioPlayer } from '@/components/AudioPlayer';
|
||||||
import { ErrorBoundary } from '@/errors/ErrorBoundary';
|
import { ErrorBoundary } from '@/errors/ErrorBoundary';
|
||||||
import { AppRoutes } from '@/scene/AppRoutes';
|
import { AppRoutes } from '@/scene/AppRoutes';
|
||||||
|
import { Text } from '@/ui';
|
||||||
import { ServiceContextProvider } from '@/service/ServiceContext';
|
import { ServiceContextProvider } from '@/service/ServiceContext';
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { TrackRoutes } from '@/scene/track/TrackRoutes';
|
|||||||
import { useHasRight } from '@/service/session';
|
import { useHasRight } from '@/service/session';
|
||||||
import { SettingsPage } from './home/SettingsPage';
|
import { SettingsPage } from './home/SettingsPage';
|
||||||
import { AddPage } from './home/AddPage';
|
import { AddPage } from './home/AddPage';
|
||||||
|
import { OnAirPage } from './onAir/OnAirPage';
|
||||||
|
|
||||||
export const AppRoutes = () => {
|
export const AppRoutes = () => {
|
||||||
const { isReadable } = useHasRight('user');
|
const { isReadable } = useHasRight('user');
|
||||||
@@ -34,6 +35,7 @@ export const AppRoutes = () => {
|
|||||||
<Route path="help" element={<HelpPage />} />
|
<Route path="help" element={<HelpPage />} />
|
||||||
<Route path="settings" element={<SettingsPage />} />
|
<Route path="settings" element={<SettingsPage />} />
|
||||||
<Route path="add" element={<AddPage />} />
|
<Route path="add" element={<AddPage />} />
|
||||||
|
<Route path="on-air/*" element={<OnAirPage />} />
|
||||||
<Route path="artist/*" element={<ArtistRoutes />} />
|
<Route path="artist/*" element={<ArtistRoutes />} />
|
||||||
<Route path="album/*" element={<AlbumRoutes />} />
|
<Route path="album/*" element={<AlbumRoutes />} />
|
||||||
<Route path="gender/*" element={<GenderRoutes />} />
|
<Route path="gender/*" element={<GenderRoutes />} />
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Box, Button, Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { LuDisc3 } from 'react-icons/lu';
|
|
||||||
import { MdEdit } from 'react-icons/md';
|
import { MdEdit } from 'react-icons/md';
|
||||||
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -10,18 +9,17 @@ import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
|||||||
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { AlbumEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
import { AlbumEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
||||||
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
|
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
|
||||||
import { DisplayTrack } from '@/components/track/DisplayTrack';
|
|
||||||
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
|
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
|
||||||
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
import { useSpecificAlbum } from '@/service/Album';
|
import { useSpecificAlbum } from '@/service/Album';
|
||||||
import { useTracksOfAnAlbum } from '@/service/Track';
|
import { useTracksOfAnAlbum } from '@/service/Track';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export const AlbumDetailPage = () => {
|
export const AlbumDetailPage = () => {
|
||||||
const { albumId } = useParams();
|
const { albumId } = useParams();
|
||||||
const albumIdInt = albumId ? parseInt(albumId, 10) : undefined;
|
const albumIdInt = albumId ? parseInt(albumId, 10) : undefined;
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const { playInList } = useActivePlaylistService();
|
const { playInList } = useActivePlaylistService();
|
||||||
const { dataAlbum } = useSpecificAlbum(albumIdInt);
|
const { dataAlbum } = useSpecificAlbum(albumIdInt);
|
||||||
const { tracksOnAnAlbum } = useTracksOfAnAlbum(albumIdInt);
|
const { tracksOnAnAlbum } = useTracksOfAnAlbum(albumIdInt);
|
||||||
@@ -48,7 +46,7 @@ export const AlbumDetailPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar title="Album detail" />
|
<TopBar title="Album detail" />
|
||||||
<PageLayoutInfoCenter>
|
<PageLayoutInfoCenter width="75%">
|
||||||
Fail to load artist id: {albumId}
|
Fail to load artist id: {albumId}
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
@@ -66,20 +64,23 @@ export const AlbumDetailPage = () => {
|
|||||||
<MdEdit />
|
<MdEdit />
|
||||||
</Button>
|
</Button>
|
||||||
</TopBar>
|
</TopBar>
|
||||||
<PageLayout>
|
<PageLayout
|
||||||
|
data-testid="Album-detail-page_layout">
|
||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
|
||||||
marginX="auto"
|
|
||||||
padding="10px"
|
|
||||||
gap="10px"
|
gap="10px"
|
||||||
|
style={{
|
||||||
|
width: "80%",
|
||||||
|
margin: "0 auto",
|
||||||
|
padding: "10px",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataAlbum?.covers}
|
data={dataAlbum?.covers}
|
||||||
iconEmpty={LuDisc3}
|
// TODO: iconEmpty={LuDisc3}
|
||||||
slideshow
|
slideshow
|
||||||
/>
|
/>
|
||||||
<Flex direction="column" width="80%" marginRight="auto">
|
<Flex direction="column" style={{ width: "80%", marginRight: "auto" }}>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
{dataAlbum?.name}
|
{dataAlbum?.name}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -94,24 +95,27 @@ export const AlbumDetailPage = () => {
|
|||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap={BASE_WRAP_SPACING}
|
gap={BASE_WRAP_SPACING} style={{
|
||||||
marginX="auto"
|
margin: "0 auto",
|
||||||
padding="20px"
|
padding: "20px",
|
||||||
width="80%"
|
width: "80%",
|
||||||
|
}}
|
||||||
|
data-test-id="Album-detail-page_flex-list"
|
||||||
>
|
>
|
||||||
{tracksOnAnAlbum?.map((data) => (
|
{tracksOnAnAlbum?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height="60px"
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackFull
|
<DisplayTrackFull
|
||||||
@@ -126,8 +130,9 @@ export const AlbumDetailPage = () => {
|
|||||||
},
|
},
|
||||||
{ name: 'Add Playlist', onClick: () => { } },
|
{ name: 'Add Playlist', onClick: () => { } },
|
||||||
]}
|
]}
|
||||||
|
data-testid="Album-detail-page_display-detail"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Wrap, WrapItem } from '@chakra-ui/react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { EmptyEnd } from '@/components/EmptyEnd';
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
@@ -10,13 +9,13 @@ import { SearchInput } from '@/components/SearchInput';
|
|||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { DisplayAlbum } from '@/components/album/DisplayAlbum';
|
import { DisplayAlbum } from '@/components/album/DisplayAlbum';
|
||||||
import { useOrderedAlbums } from '@/service/Album';
|
import { useOrderedAlbums } from '@/service/Album';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_SPACING, BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing';
|
import { BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing';
|
||||||
|
import { Button, Flex, HStack } from '@/ui';
|
||||||
|
|
||||||
export const AlbumsPage = () => {
|
export const AlbumsPage = () => {
|
||||||
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
|
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
|
||||||
const { isLoading, dataAlbums } = useOrderedAlbums(filterTitle);
|
const { isLoading, dataAlbums } = useOrderedAlbums(filterTitle);
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const onSelectItem = (albumId: number) => {
|
const onSelectItem = (albumId: number) => {
|
||||||
navigate(`/album/${albumId}`);
|
navigate(`/album/${albumId}`);
|
||||||
@@ -26,7 +25,7 @@ export const AlbumsPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar title="All Albums" />
|
<TopBar title="All Albums" />
|
||||||
<PageLayoutInfoCenter>No Album available</PageLayoutInfoCenter>
|
<PageLayoutInfoCenter width="75%">No Album available</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -37,29 +36,31 @@ export const AlbumsPage = () => {
|
|||||||
<SearchInput onChange={setFilterTitle} />
|
<SearchInput onChange={setFilterTitle} />
|
||||||
</TopBar>
|
</TopBar>
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center">
|
<HStack style={{ flexWrap: "wrap", /*spacing={BASE_WRAP_SPACING}*/ margin: "0 auto", padding: "20px", justifyContent: "center" }}>
|
||||||
{dataAlbums.map((data) => (
|
{dataAlbums.map((data) => (
|
||||||
<WrapItem
|
<Button
|
||||||
width={BASE_WRAP_WIDTH}
|
|
||||||
height={BASE_WRAP_HEIGHT}
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
width: BASE_WRAP_WIDTH,
|
||||||
_hover={{
|
height: BASE_WRAP_HEIGHT,
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover={
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
|
alignContent: "flex-start",
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data.id)}
|
onClick={() => onSelectItem(data.id)}
|
||||||
>
|
>
|
||||||
<DisplayAlbum dataAlbum={data} />
|
<DisplayAlbum dataAlbum={data} />
|
||||||
</WrapItem>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</Wrap>
|
</HStack>
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</PageLayout>
|
</PageLayout >
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Box, Button, Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { LuDisc3, LuUser } from 'react-icons/lu';
|
import { MdEdit } from 'react-icons/md';
|
||||||
import { MdEdit, MdPerson } from 'react-icons/md';
|
|
||||||
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
@@ -15,13 +14,13 @@ import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
|||||||
import { useSpecificAlbum } from '@/service/Album';
|
import { useSpecificAlbum } from '@/service/Album';
|
||||||
import { useSpecificArtist } from '@/service/Artist';
|
import { useSpecificArtist } from '@/service/Artist';
|
||||||
import { useTracksOfAnAlbum } from '@/service/Track';
|
import { useTracksOfAnAlbum } from '@/service/Track';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export const ArtistAlbumDetailPage = () => {
|
export const ArtistAlbumDetailPage = () => {
|
||||||
const { artistId, albumId } = useParams();
|
const { artistId, albumId } = useParams();
|
||||||
const artistIdInt = artistId ? parseInt(artistId, 10) : undefined;
|
const artistIdInt = artistId ? parseInt(artistId, 10) : undefined;
|
||||||
const albumIdInt = albumId ? parseInt(albumId, 10) : undefined;
|
const albumIdInt = albumId ? parseInt(albumId, 10) : undefined;
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const { playInList } = useActivePlaylistService();
|
const { playInList } = useActivePlaylistService();
|
||||||
const { dataArtist } = useSpecificArtist(artistIdInt);
|
const { dataArtist } = useSpecificArtist(artistIdInt);
|
||||||
const { dataAlbum } = useSpecificAlbum(albumIdInt);
|
const { dataAlbum } = useSpecificAlbum(albumIdInt);
|
||||||
@@ -61,14 +60,19 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
{...BUTTON_TOP_BAR_PROPERTY}
|
{...BUTTON_TOP_BAR_PROPERTY}
|
||||||
marginRight="auto"
|
|
||||||
|
style={{
|
||||||
|
marginRight: "auto"
|
||||||
|
}}
|
||||||
onClick={() => navigate(`/artist/${dataArtist.id}`)}
|
onClick={() => navigate(`/artist/${dataArtist.id}`)}
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataArtist?.covers}
|
data={dataArtist?.covers}
|
||||||
size="35px"
|
size="35px"
|
||||||
borderRadius="full"
|
style={{
|
||||||
iconEmpty={MdPerson}
|
borderRadius: "full",
|
||||||
|
}}
|
||||||
|
// TODO: iconEmpty={MdPerson}
|
||||||
/>
|
/>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
{dataArtist?.name}
|
{dataArtist?.name}
|
||||||
@@ -88,17 +92,20 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
style={{
|
||||||
marginX="auto"
|
width: "80%",
|
||||||
padding="10px"
|
margin: "0 auto",
|
||||||
|
padding: "10px",
|
||||||
|
}}
|
||||||
gap="10px"
|
gap="10px"
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataAlbum?.covers}
|
data={dataAlbum?.covers}
|
||||||
iconEmpty={LuDisc3}
|
// TODO: iconEmpty={LuDisc3}
|
||||||
slideshow
|
slideshow
|
||||||
/>
|
/>
|
||||||
<Flex direction="column" width="80%" marginRight="auto">
|
<Flex direction="column"
|
||||||
|
style={{ width: "80%", marginRight: "auto" }}>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
{dataAlbum?.name}
|
{dataAlbum?.name}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -114,23 +121,28 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="20px"
|
gap="20px"
|
||||||
marginX="auto"
|
|
||||||
padding="20px"
|
style={{
|
||||||
width="80%"
|
margin: "0 auto",
|
||||||
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{tracksOnAnAlbum?.map((data) => (
|
{tracksOnAnAlbum?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
|
||||||
as="button"
|
style={{
|
||||||
_hover={{
|
minWidth: "100%",
|
||||||
boxShadow: 'outline-over',
|
height: "60px",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrack
|
<DisplayTrack
|
||||||
@@ -148,7 +160,7 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
{ name: 'Add Playlist', onClick: () => { } },
|
{ name: 'Add Playlist', onClick: () => { } },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Button, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react';
|
|
||||||
import { LuUser } from 'react-icons/lu';
|
|
||||||
import { MdEdit, MdGroup } from 'react-icons/md';
|
import { MdEdit, MdGroup } from 'react-icons/md';
|
||||||
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -12,13 +11,13 @@ import { DisplayAlbumId } from '@/components/album/DisplayAlbumId';
|
|||||||
import { ArtistEditPopUp } from '@/components/popup/ArtistEditPopUp';
|
import { ArtistEditPopUp } from '@/components/popup/ArtistEditPopUp';
|
||||||
import { useSpecificArtist } from '@/service/Artist';
|
import { useSpecificArtist } from '@/service/Artist';
|
||||||
import { useAlbumIdsOfAnArtist } from '@/service/Track';
|
import { useAlbumIdsOfAnArtist } from '@/service/Track';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_HEIGHT, BASE_WRAP_SPACING, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
|
import { BASE_WRAP_HEIGHT, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
|
||||||
|
import { Button, Flex, HStack, Text } from '@/ui';
|
||||||
|
|
||||||
export const ArtistDetailPage = () => {
|
export const ArtistDetailPage = () => {
|
||||||
const { artistId } = useParams();
|
const { artistId } = useParams();
|
||||||
const artistIdInt = artistId ? parseInt(artistId, 10) : undefined;
|
const artistIdInt = artistId ? parseInt(artistId, 10) : undefined;
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const onSelectItem = (albumId: number) => {
|
const onSelectItem = (albumId: number) => {
|
||||||
navigate(`/artist/${artistIdInt}/album/${albumId}`);
|
navigate(`/artist/${artistIdInt}/album/${albumId}`);
|
||||||
@@ -42,7 +41,7 @@ export const ArtistDetailPage = () => {
|
|||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
{...BUTTON_TOP_BAR_PROPERTY}
|
{...BUTTON_TOP_BAR_PROPERTY}
|
||||||
marginRight="auto"
|
style={{ marginRight: "auto" }}
|
||||||
onClick={() => navigate(`/artist/all`)}
|
onClick={() => navigate(`/artist/all`)}
|
||||||
>
|
>
|
||||||
<MdGroup height="full" />
|
<MdGroup height="full" />
|
||||||
@@ -65,13 +64,13 @@ export const ArtistDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
width="80%"
|
||||||
marginX="auto"
|
margin="0 auto"
|
||||||
padding="10px"
|
padding="10px"
|
||||||
gap="10px"
|
gap="10px"
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataArtist?.covers}
|
data={dataArtist?.covers}
|
||||||
iconEmpty={LuUser}
|
// TODO: iconEmpty={LuUser}
|
||||||
slideshow
|
slideshow
|
||||||
/>
|
/>
|
||||||
<Flex direction="column" width="80%" marginRight="auto">
|
<Flex direction="column" width="80%" marginRight="auto">
|
||||||
@@ -89,27 +88,29 @@ export const ArtistDetailPage = () => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center">
|
<HStack style={{ flexWrap: "wrap", /*spacing={BASE_WRAP_SPACING}*/ margin: "0 auto", padding: "20px", justifyContent: "center" }}>
|
||||||
{albumIdsOfAnArtist?.map((data) => (
|
{albumIdsOfAnArtist?.map((data) => (
|
||||||
<WrapItem
|
<Button
|
||||||
width={BASE_WRAP_WIDTH}
|
|
||||||
height={BASE_WRAP_HEIGHT}
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data}
|
key={data}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
alignContent: "flex-start",
|
||||||
_hover={{
|
width: BASE_WRAP_WIDTH,
|
||||||
boxShadow: 'outline-over',
|
height: BASE_WRAP_HEIGHT,
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover={
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
<DisplayAlbumId id={data} key={data} />
|
<DisplayAlbumId id={data} key={data} />
|
||||||
</WrapItem>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</Wrap>
|
</HStack>
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="edit-artist/:artistId" element={<ArtistEditPopUp />} />
|
<Route path="edit-artist/:artistId" element={<ArtistEditPopUp />} />
|
||||||
|
|||||||
@@ -1,56 +1,91 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Flex, Text, Wrap, WrapItem } from '@chakra-ui/react';
|
|
||||||
import { LuUser } from 'react-icons/lu';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { Artist } from '@/back-api';
|
import { Artist, Track } from '@/back-api';
|
||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
import { EmptyEnd } from '@/components/EmptyEnd';
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { SearchInput } from '@/components/SearchInput';
|
import { SearchInput } from '@/components/SearchInput';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { useArtistService, useOrderedArtists } from '@/service/Artist';
|
import { useOrderedArtists } from '@/service/Artist';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_HEIGHT, BASE_WRAP_ICON_SIZE, BASE_WRAP_SPACING, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
|
import { BASE_WRAP_HEIGHT, BASE_WRAP_ICON_SIZE, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
|
||||||
|
import { MdOutlineForkRight } from 'react-icons/md';
|
||||||
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
|
import { shuffleArray } from '@/utils/arrayTools';
|
||||||
|
import { useTrackService } from '@/service/Track';
|
||||||
|
import { DataTools, TypeCheck } from '@/utils/data-tools';
|
||||||
|
import { Button, Flex, HStack, Span, Text } from '@/ui';
|
||||||
|
const LIMIT_RANDOM_VALUES = 25;
|
||||||
|
|
||||||
export const ArtistsPage = () => {
|
export const ArtistsPage = () => {
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const [filterName, setFilterName] = useState<string | undefined>(undefined);
|
const [filterName, setFilterName] = useState<string | undefined>(undefined);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { playInList } = useActivePlaylistService();
|
||||||
const onSelectItem = (data: Artist) => {
|
const onSelectItem = (data: Artist) => {
|
||||||
navigate(`/artist/${data.id}/`);
|
navigate(`/artist/${data.id}/`);
|
||||||
};
|
};
|
||||||
const { dataArtist } = useOrderedArtists(filterName);
|
const { dataArtist } = useOrderedArtists(filterName);
|
||||||
|
const { store: trackStore } = useTrackService();
|
||||||
|
const onRandomPlay = () => {
|
||||||
|
const data = shuffleArray(dataArtist)
|
||||||
|
const playingList: number[] = [];
|
||||||
|
for (let i = 0; i < Math.min(data.length, LIMIT_RANDOM_VALUES); i++) {
|
||||||
|
const selectedArtist: Artist = data[i];
|
||||||
|
const listArtistTracks: Track[] = DataTools.getsWhere(
|
||||||
|
trackStore.data,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
check: TypeCheck.CONTAINS,
|
||||||
|
key: 'artists',
|
||||||
|
value: selectedArtist.id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
if (listArtistTracks.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
playingList.push(listArtistTracks[Math.floor(Math.random() * listArtistTracks.length)].id);
|
||||||
|
}
|
||||||
|
playInList(0, playingList)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar title="All artists">
|
<TopBar title="All artists">
|
||||||
<SearchInput onChange={setFilterName} />
|
<SearchInput onChange={setFilterName} />
|
||||||
|
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onRandomPlay}>
|
||||||
|
<MdOutlineForkRight />
|
||||||
|
</Button>
|
||||||
</TopBar>
|
</TopBar>
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center">
|
<HStack style={{ flexWrap: "wrap", /*spacing={BASE_WRAP_SPACING}*/ margin: "0 auto", padding: "20px", alignContent: "center" }}>
|
||||||
{dataArtist?.map((data) => (
|
{dataArtist?.map((data) => (
|
||||||
<WrapItem
|
<Button
|
||||||
width={BASE_WRAP_WIDTH}
|
|
||||||
height={BASE_WRAP_HEIGHT}
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
width: BASE_WRAP_WIDTH,
|
||||||
_hover={{
|
height: BASE_WRAP_HEIGHT,
|
||||||
boxShadow: 'outline-over',
|
alignContent: "flex-start",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover:{
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="100%" height="full">
|
||||||
<Covers
|
<Covers
|
||||||
data={data.covers}
|
data={data.covers}
|
||||||
size={BASE_WRAP_ICON_SIZE}
|
size={BASE_WRAP_ICON_SIZE}
|
||||||
height="full"
|
style={{ height: "100%" }}
|
||||||
iconEmpty={LuUser}
|
// iconEmpty={LuUser}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
@@ -58,25 +93,30 @@ export const ArtistsPage = () => {
|
|||||||
maxWidth="150px"
|
maxWidth="150px"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{ overflowX: "hidden" }}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
as="span"
|
/*align="left"*/
|
||||||
align="left"
|
/*noOfLines={[1, 2]}*/
|
||||||
fontSize="20px"
|
|
||||||
fontWeight="bold"
|
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
noOfLines={[1, 2]}
|
|
||||||
>
|
>
|
||||||
{data.name}
|
<Span
|
||||||
|
fontSize="20px"
|
||||||
|
fontWeight="bold"
|
||||||
|
userSelect="none"
|
||||||
|
style={{
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data.name}
|
||||||
|
</Span>
|
||||||
|
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</WrapItem>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</Wrap>
|
</HStack>
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Box, Button, Flex, Text } from '@chakra-ui/react';
|
|
||||||
import { LuDisc3 } from 'react-icons/lu';
|
|
||||||
import { MdEdit } from 'react-icons/md';
|
import { MdEdit } from 'react-icons/md';
|
||||||
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -10,18 +9,17 @@ import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
|||||||
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { GenderEditPopUp } from '@/components/popup/GenderEditPopUp';
|
import { GenderEditPopUp } from '@/components/popup/GenderEditPopUp';
|
||||||
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
|
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
|
||||||
import { DisplayTrack } from '@/components/track/DisplayTrack';
|
|
||||||
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
|
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
|
||||||
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
import { useSpecificGender } from '@/service/Gender';
|
import { useSpecificGender } from '@/service/Gender';
|
||||||
import { useTracksOfAGender } from '@/service/Track';
|
import { useTracksOfAGender } from '@/service/Track';
|
||||||
//import { useTracksOfAGender } from '@/service/Track';
|
//import { useTracksOfAGender } from '@/service/Track';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export const GenderDetailPage = () => {
|
export const GenderDetailPage = () => {
|
||||||
const { genderId } = useParams();
|
const { genderId } = useParams();
|
||||||
const genderIdInt = genderId ? parseInt(genderId, 10) : undefined;
|
const genderIdInt = genderId ? parseInt(genderId, 10) : undefined;
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const { playInList } = useActivePlaylistService();
|
const { playInList } = useActivePlaylistService();
|
||||||
const { dataGender } = useSpecificGender(genderIdInt);
|
const { dataGender } = useSpecificGender(genderIdInt);
|
||||||
const { tracksOnAGender } = useTracksOfAGender(genderIdInt);
|
const { tracksOnAGender } = useTracksOfAGender(genderIdInt);
|
||||||
@@ -69,17 +67,19 @@ export const GenderDetailPage = () => {
|
|||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
|
||||||
marginX="auto"
|
|
||||||
padding="10px"
|
|
||||||
gap="10px"
|
gap="10px"
|
||||||
|
style={{
|
||||||
|
width: "80%",
|
||||||
|
margin: "0 auto",
|
||||||
|
padding: "10px",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataGender?.covers}
|
data={dataGender?.covers}
|
||||||
iconEmpty={LuDisc3}
|
// TODO: iconEmpty={LuDisc3}
|
||||||
slideshow
|
slideshow
|
||||||
/>
|
/>
|
||||||
<Flex direction="column" width="80%" marginRight="auto">
|
<Flex direction="column" style={{ width: "80%", marginRight: "auto" }}>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
{dataGender?.name}
|
{dataGender?.name}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -92,23 +92,26 @@ export const GenderDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="20px"
|
gap="20px"
|
||||||
marginX="auto"
|
style={{
|
||||||
padding="20px"
|
margin: "0 auto",
|
||||||
width="80%"
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{tracksOnAGender?.map((data) => (
|
{tracksOnAGender?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height="60px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackFull
|
<DisplayTrackFull
|
||||||
@@ -124,7 +127,7 @@ export const GenderDetailPage = () => {
|
|||||||
{ name: 'Add Playlist', onClick: () => { } },
|
{ name: 'Add Playlist', onClick: () => { } },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Wrap, WrapItem } from '@chakra-ui/react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { EmptyEnd } from '@/components/EmptyEnd';
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
@@ -10,12 +9,12 @@ import { SearchInput } from '@/components/SearchInput';
|
|||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { DisplayGender } from '@/components/gender/DisplayGender';
|
import { DisplayGender } from '@/components/gender/DisplayGender';
|
||||||
import { useOrderedGenders } from '@/service/Gender';
|
import { useOrderedGenders } from '@/service/Gender';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Flex, HStack } from '@/ui';
|
||||||
|
|
||||||
export const GendersPage = () => {
|
export const GendersPage = () => {
|
||||||
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
|
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
|
||||||
const { isLoading, dataGenders } = useOrderedGenders(filterTitle);
|
const { isLoading, dataGenders } = useOrderedGenders(filterTitle);
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const onSelectItem = (genderId: number) => {
|
const onSelectItem = (genderId: number) => {
|
||||||
navigate(`/gender/${genderId}`);
|
navigate(`/gender/${genderId}`);
|
||||||
@@ -36,27 +35,31 @@ export const GendersPage = () => {
|
|||||||
<SearchInput onChange={setFilterTitle} />
|
<SearchInput onChange={setFilterTitle} />
|
||||||
</TopBar>
|
</TopBar>
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center">
|
<HStack style={{
|
||||||
|
// wrap: "wrap",
|
||||||
|
/*spacing="20px"*/ margin: "0 auto 0 auto", padding: "20px", justifyContent: "center"
|
||||||
|
}}>
|
||||||
{dataGenders.map((data) => (
|
{dataGenders.map((data) => (
|
||||||
<WrapItem
|
<Flex align="flex-start"
|
||||||
width="270px"
|
|
||||||
height="120px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
width: "270px",
|
||||||
_hover={{
|
height: "120px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
//background:{useColorModeValue('#FFFFFF88', '#00000088')},
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data.id)}
|
onClick={() => onSelectItem(data.id)}
|
||||||
>
|
>
|
||||||
<DisplayGender dataGender={data} />
|
<DisplayGender dataGender={data} />
|
||||||
</WrapItem>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Wrap>
|
</HStack>
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Input,
|
|
||||||
Table,
|
|
||||||
TableContainer,
|
|
||||||
Tbody,
|
|
||||||
Td,
|
|
||||||
Text,
|
|
||||||
Th,
|
|
||||||
Thead,
|
|
||||||
Tr,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { LuTrash } from 'react-icons/lu';
|
import { LuTrash } from 'react-icons/lu';
|
||||||
import { MdCloudUpload } from 'react-icons/md';
|
import { MdCloudUpload } from 'react-icons/md';
|
||||||
|
|
||||||
@@ -38,6 +25,7 @@ import { useGenderService, useOrderedGenders } from '@/service/Gender';
|
|||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { useTrackService } from '@/service/Track';
|
import { useTrackService } from '@/service/Track';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { Button, Flex, Table, Text } from '@/ui';
|
||||||
|
|
||||||
export class ElementList {
|
export class ElementList {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -127,7 +115,7 @@ export const AddPage = () => {
|
|||||||
updateNeedSend();
|
updateNeedSend();
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeElementFromList = (data: FileParsedElement, value: any): void => {
|
const removeElementFromList = (data: FileParsedElement): void => {
|
||||||
const parsedElementTmp = [...parsedElement];
|
const parsedElementTmp = [...parsedElement];
|
||||||
for (let iii = 0; iii < parsedElementTmp.length; iii++) {
|
for (let iii = 0; iii < parsedElementTmp.length; iii++) {
|
||||||
if (parsedElementTmp[iii] === data) {
|
if (parsedElementTmp[iii] === data) {
|
||||||
@@ -426,15 +414,17 @@ export const AddPage = () => {
|
|||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
width="80%"
|
|
||||||
marginX="auto"
|
|
||||||
padding="10px"
|
|
||||||
gap="10px"
|
gap="10px"
|
||||||
|
style={{
|
||||||
|
width: "80%",
|
||||||
|
margin: "0 auto 0 auto",
|
||||||
|
padding: "10px",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Flex direction="column" width="full">
|
<Flex direction="column" style={{ width: "100%" }}>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Text flex={1}>format:</Text>
|
<Text>format:</Text>
|
||||||
<Text flex={4}>
|
<Text>
|
||||||
The format of the media permit to automatic find meta-data:
|
The format of the media permit to automatic find meta-data:
|
||||||
<br />
|
<br />
|
||||||
Artist~album#idTrack-my name of my media.webm
|
Artist~album#idTrack-my name of my media.webm
|
||||||
@@ -443,15 +433,15 @@ export const AddPage = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Text flex={1}>Media:</Text>
|
<Text>Media:</Text>
|
||||||
<Input
|
{/* <Input
|
||||||
flex={4}
|
flex={4}
|
||||||
type="file"
|
type="file"
|
||||||
placeholder="Select a media file"
|
placeholder="Select a media file"
|
||||||
accept=".webm"
|
accept=".webm"
|
||||||
multiple
|
multiple
|
||||||
onChange={onChangeFile}
|
onChange={onChangeFile}
|
||||||
/>
|
/> */}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
{parsedElement && parsedElement.length !== 0 && (
|
{parsedElement && parsedElement.length !== 0 && (
|
||||||
@@ -483,153 +473,146 @@ export const AddPage = () => {
|
|||||||
addNewItem={addNewAlbum}
|
addNewItem={addNewAlbum}
|
||||||
suggestion={suggestedAlbum}
|
suggestion={suggestedAlbum}
|
||||||
/>
|
/>
|
||||||
<TableContainer>
|
<Table.Root
|
||||||
<Table
|
background="gray.700"
|
||||||
variant="striped"
|
>
|
||||||
colorScheme="teal"
|
<Table.Header>
|
||||||
background="gray.700"
|
<Table.Row>
|
||||||
|
<Table.ColumnHeader>track ID</Table.ColumnHeader>
|
||||||
|
<Table.ColumnHeader style={{ width: "100%" }}>Title</Table.ColumnHeader>
|
||||||
|
<Table.ColumnHeader>actions</Table.ColumnHeader>
|
||||||
|
</Table.Row>
|
||||||
|
</Table.Header>
|
||||||
|
<Table.Body>
|
||||||
|
{parsedElement.map((data) => (
|
||||||
|
<Table.Row key={data.uniqueId}>
|
||||||
|
<Table.Cell>
|
||||||
|
{/* <Input
|
||||||
|
type="number"
|
||||||
|
pattern="[0-9]{0-4}"
|
||||||
|
placeholder="e?"
|
||||||
|
value={data.trackId}
|
||||||
|
onChange={(e) => onTrackId(data, e.target.value)}
|
||||||
|
background={
|
||||||
|
data.trackIdDetected === true
|
||||||
|
? 'darkred'
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/> */}
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
{/* <Input
|
||||||
|
type="text"
|
||||||
|
placeholder="Name of the Media"
|
||||||
|
value={data.title}
|
||||||
|
onChange={(e) => onTitle(data, e.target.value)}
|
||||||
|
background={
|
||||||
|
data.title === '' ? 'darkred' : undefined
|
||||||
|
}
|
||||||
|
/> */}
|
||||||
|
{data.nameDetected === true && (
|
||||||
|
<>
|
||||||
|
<br />
|
||||||
|
<Text style={{ background: "red" }}>
|
||||||
|
^^^This title already exist !!!
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
removeElementFromList(data)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<LuTrash /> Remove
|
||||||
|
</Button>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
))}
|
||||||
|
</Table.Body>
|
||||||
|
</Table.Root>
|
||||||
|
<Flex style={{ margin: "15px 0 15px 0" }}>
|
||||||
|
<Button
|
||||||
|
//theme="@primary"
|
||||||
|
onClick={sendFile}
|
||||||
|
style={{
|
||||||
|
//disabled:!needSend,
|
||||||
|
margin: "0 auto 0 30px"
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Thead>
|
<MdCloudUpload /> Upload
|
||||||
<Tr>
|
</Button>
|
||||||
<Th>track ID</Th>
|
</Flex>
|
||||||
<Th width="full">Title</Th>
|
|
||||||
<Th>actions</Th>
|
|
||||||
</Tr>
|
|
||||||
</Thead>
|
|
||||||
<Tbody>
|
|
||||||
{parsedElement.map((data) => (
|
|
||||||
<Tr key={data.uniqueId}>
|
|
||||||
<Td>
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
pattern="[0-9]{0-4}"
|
|
||||||
placeholder="e?"
|
|
||||||
value={data.trackId}
|
|
||||||
onChange={(e) => onTrackId(data, e.target.value)}
|
|
||||||
backgroundColor={
|
|
||||||
data.trackIdDetected === true
|
|
||||||
? 'darkred'
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
placeholder="Name of the Media"
|
|
||||||
value={data.title}
|
|
||||||
onChange={(e) => onTitle(data, e.target.value)}
|
|
||||||
backgroundColor={
|
|
||||||
data.title === '' ? 'darkred' : undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{data.nameDetected === true && (
|
|
||||||
<>
|
|
||||||
<br />
|
|
||||||
<Text as="span" color="@danger">
|
|
||||||
^^^This title already exist !!!
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<Button
|
|
||||||
onClick={(e) =>
|
|
||||||
removeElementFromList(data, e.target)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<LuTrash /> Remove
|
|
||||||
</Button>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
))}
|
|
||||||
</Tbody>
|
|
||||||
</Table>
|
|
||||||
<Flex marginY="15px">
|
|
||||||
<Button
|
|
||||||
variant="@primary"
|
|
||||||
onClick={sendFile}
|
|
||||||
disabled={!needSend}
|
|
||||||
marginLeft="auto"
|
|
||||||
marginRight="30px"
|
|
||||||
>
|
|
||||||
<MdCloudUpload /> Upload
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
</TableContainer>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{listFileInBdd && (
|
{listFileInBdd && (
|
||||||
<>
|
<Table.Root
|
||||||
<TableContainer>
|
//fontPalette="striped"
|
||||||
<Table
|
//colorScheme="teal"
|
||||||
variant="striped"
|
style={{
|
||||||
colorScheme="teal"
|
background: "gray.700"
|
||||||
background="gray.700"
|
}}
|
||||||
>
|
>
|
||||||
<Thead>
|
<Table.Header>
|
||||||
<Tr>
|
<Table.Row>
|
||||||
<Th>track ID</Th>
|
<Table.ColumnHeader>track ID</Table.ColumnHeader>
|
||||||
<Th width="full">Title</Th>
|
<Table.ColumnHeader style={{ width: "100%" }}>Title</Table.ColumnHeader>
|
||||||
<Th>actions</Th>
|
<Table.ColumnHeader>actions</Table.ColumnHeader>
|
||||||
</Tr>
|
</Table.Row>
|
||||||
</Thead>
|
</Table.Header>
|
||||||
<Tbody>
|
<Table.Body>
|
||||||
{listFileInBdd.map((data) => (
|
{listFileInBdd.map((data) => (
|
||||||
<Tr>
|
<Table.Row>
|
||||||
<Td>
|
<Table.Cell>
|
||||||
<Text
|
<Text
|
||||||
color={
|
color={
|
||||||
data.episodeDetected === true ? 'red' : undefined
|
data.episodeDetected === true ? 'red' : undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{data.trackId}
|
{data.trackId}
|
||||||
</Text>
|
</Text>
|
||||||
</Td>
|
</Table.Cell>
|
||||||
<Td>
|
<Table.Cell>
|
||||||
<Text
|
<Text
|
||||||
color={
|
color={
|
||||||
data.nameDetected === true ? 'red' : undefined
|
data.nameDetected === true ? 'red' : undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{data.title}
|
{data.title}
|
||||||
</Text>
|
</Text>
|
||||||
</Td>
|
</Table.Cell>
|
||||||
<Td></Td>
|
<Table.Cell></Table.Cell>
|
||||||
</Tr>
|
</Table.Row>
|
||||||
))}
|
))}
|
||||||
</Tbody>
|
</Table.Body>
|
||||||
</Table>
|
</Table.Root>
|
||||||
</TableContainer>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{parsedFailedElement && (
|
{parsedFailedElement && (
|
||||||
<>
|
<>
|
||||||
<Text fontSize="30px">Rejected:</Text>
|
<Text fontSize="30px">Rejected:</Text>
|
||||||
<TableContainer>
|
<Table.Root
|
||||||
<Table
|
//colorPalette="striped"
|
||||||
variant="striped"
|
//colorScheme="teal"
|
||||||
colorScheme="teal"
|
style={{ background: "gray.700" }}
|
||||||
background="gray.700"
|
>
|
||||||
>
|
<Table.Header>
|
||||||
<Thead>
|
<Table.Row>
|
||||||
<Tr>
|
<Table.ColumnHeader style={{ maxWidth: "80%" }}>file</Table.ColumnHeader>
|
||||||
<Th maxWidth="80%">file</Th>
|
<Table.ColumnHeader>Reason</Table.ColumnHeader>
|
||||||
<Th>Reason</Th>
|
</Table.Row>
|
||||||
</Tr>
|
</Table.Header>
|
||||||
</Thead>
|
<Table.Body>
|
||||||
<Tbody>
|
{parsedFailedElement.map((data) => (
|
||||||
{parsedFailedElement.map((data) => (
|
<Table.Row key={data.uniqueId}>
|
||||||
<Tr key={data.uniqueId}>
|
<Table.Cell>{data.file.name}</Table.Cell>
|
||||||
<Td>{data.file.name}</Td>
|
<Table.Cell>{data.reason}</Table.Cell>
|
||||||
<Td>{data.reason}</Td>
|
</Table.Row>
|
||||||
</Tr>
|
))}
|
||||||
))}
|
</Table.Body>
|
||||||
</Tbody>
|
</Table.Root>
|
||||||
</Table>
|
|
||||||
</TableContainer>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
|
|
||||||
import { Center, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react';
|
|
||||||
import { LuCrown, LuDisc3, LuEar, LuFileAudio } from 'react-icons/lu';
|
import { LuCrown, LuDisc3, LuEar, LuFileAudio } from 'react-icons/lu';
|
||||||
import { MdGroup } from 'react-icons/md';
|
import { MdGroup } from 'react-icons/md';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
|
||||||
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Div, Flex, HStack, Text } from '@/ui';
|
||||||
|
|
||||||
type HomeListType = {
|
type HomeListType = {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -19,37 +20,36 @@ const homeList: HomeListType[] = [
|
|||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Genders',
|
name: 'Genders',
|
||||||
icon: <LuCrown size="60%" height="full" />,
|
icon: <LuCrown style={{ width: "100px", height: "100px" }} />,
|
||||||
to: 'gender',
|
to: 'gender',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: 'Artists',
|
name: 'Artists',
|
||||||
icon: <MdGroup size="60%" height="full" />,
|
icon: <MdGroup style={{ width: "100px", height: "100px" }} />,
|
||||||
to: 'artist',
|
to: 'artist',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
name: 'Albums',
|
name: 'Albums',
|
||||||
icon: <LuDisc3 size="60%" height="full" />,
|
icon: <LuDisc3 style={{ width: "100px", height: "100px" }} />,
|
||||||
to: 'album',
|
to: 'album',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
name: 'Tracks',
|
name: 'Tracks',
|
||||||
icon: <LuFileAudio size="60%" height="full" />,
|
icon: <LuFileAudio style={{ width: "100px", height: "100px" }} />,
|
||||||
to: 'track',
|
to: 'track',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
name: 'Playlists',
|
name: 'Playlists',
|
||||||
icon: <LuEar size="60%" height="full" />,
|
icon: <LuEar style={{ width: "100px", height: "100px" }} />,
|
||||||
to: 'playlists',
|
to: 'playlists',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const HomePage = () => {
|
export const HomePage = () => {
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const onSelectItem = (data: HomeListType) => {
|
const onSelectItem = (data: HomeListType) => {
|
||||||
navigate(data.to);
|
navigate(data.to);
|
||||||
@@ -58,40 +58,56 @@ export const HomePage = () => {
|
|||||||
<>
|
<>
|
||||||
<TopBar title="Home" />
|
<TopBar title="Home" />
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center">
|
<HStack style={{
|
||||||
|
flexWrap: "wrap",
|
||||||
|
/*spacing:"20px",*/
|
||||||
|
margin: "0 auto",
|
||||||
|
padding: "20px",
|
||||||
|
alignContent: "center"
|
||||||
|
}}>
|
||||||
{homeList.map((data) => (
|
{homeList.map((data) => (
|
||||||
<WrapItem
|
<Flex align="flex-start"
|
||||||
width="200px"
|
margin="auto"
|
||||||
height="190px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
width: "200px",
|
||||||
|
height: "190px",
|
||||||
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
}}
|
||||||
_hover={{
|
_hover={{
|
||||||
boxShadow: 'outline-over',
|
boxShadow: 'outline-over',
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
background: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
<Flex direction="column" width="full" height="full">
|
<Flex
|
||||||
<Center height="full">{data.icon}</Center>
|
direction="column"
|
||||||
<Center>
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
margin: "auto"
|
||||||
|
}}>
|
||||||
|
<Div style={{ margin: "auto", height: "100%", color: "black.50" }}>{data.icon}</Div>
|
||||||
|
<Div style={{ margin: "auto", height: "100%" }}>
|
||||||
<Text
|
<Text
|
||||||
fontSize="25px"
|
fontSize="25px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
textTransform="uppercase"
|
color="black.50"
|
||||||
userSelect="none"
|
style={{
|
||||||
|
textTransform: "uppercase",
|
||||||
|
userSelect: "none",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{data.name}
|
{data.name}
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Div>
|
||||||
</Flex>
|
</Flex>
|
||||||
</WrapItem>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Wrap>
|
</HStack>
|
||||||
</PageLayout>
|
</PageLayout >
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
128
front/src/scene/onAir/OnAirPage.tsx
Normal file
128
front/src/scene/onAir/OnAirPage.tsx
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import { Route, Routes, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { AlbumEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
||||||
|
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
|
||||||
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
||||||
|
import { DisplayTrackFullId } from '@/components/track/DisplayTrackFullId';
|
||||||
|
import { Flex } from '@/ui';
|
||||||
|
|
||||||
|
export const OnAirPage = () => {
|
||||||
|
const { playInList } = useActivePlaylistService();
|
||||||
|
const { playTrackList, trackOffset, setNewPlaylist } = useActivePlaylistService();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const onSelectItem = (trackId: number) => {
|
||||||
|
let currentPlay = 0;
|
||||||
|
if (!playTrackList) {
|
||||||
|
console.log('Fail to get list of on air...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let iii = 0; iii < playTrackList.length; iii++) {
|
||||||
|
if (playTrackList[iii] === trackId) {
|
||||||
|
currentPlay = iii;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
playInList(currentPlay, playTrackList);
|
||||||
|
};
|
||||||
|
const removeTrack = (trackId: number) => {
|
||||||
|
let elementToRemoveOffset = 0;
|
||||||
|
if (!playTrackList) {
|
||||||
|
console.log('Fail to remove element of on air...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newList: number[] = [];
|
||||||
|
for (let iii = 0; iii < playTrackList.length; iii++) {
|
||||||
|
if (playTrackList[iii] === trackId) {
|
||||||
|
elementToRemoveOffset = iii;
|
||||||
|
} else {
|
||||||
|
newList.push(playTrackList[iii])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let newPlayed = trackOffset;
|
||||||
|
if (newPlayed != undefined) {
|
||||||
|
if (elementToRemoveOffset < newPlayed) {
|
||||||
|
newPlayed = newPlayed - 1;
|
||||||
|
}
|
||||||
|
playInList(newPlayed, newList);
|
||||||
|
} else {
|
||||||
|
setNewPlaylist(newList);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(`playTrackList = ${JSON.stringify(playTrackList, null, 2)}`);
|
||||||
|
if (!playTrackList) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TopBar title="Album detail" />
|
||||||
|
<PageLayoutInfoCenter>
|
||||||
|
No data is currently playing...
|
||||||
|
</PageLayoutInfoCenter>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TopBar title="On Air ...">
|
||||||
|
</TopBar>
|
||||||
|
<PageLayout>
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
gap={BASE_WRAP_SPACING}
|
||||||
|
style={{
|
||||||
|
margin: "0 auto",
|
||||||
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!playTrackList && <>No playing</>}
|
||||||
|
{playTrackList && playTrackList?.map((data) => (
|
||||||
|
<Flex
|
||||||
|
key={data}
|
||||||
|
style={{
|
||||||
|
minWidth: "100%",
|
||||||
|
//height:"60px",
|
||||||
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DisplayTrackFullId
|
||||||
|
trackId={data}
|
||||||
|
onClick={() => onSelectItem(data)}
|
||||||
|
contextMenu={[
|
||||||
|
{
|
||||||
|
name: 'Edit',
|
||||||
|
onClick: () => {
|
||||||
|
navigate(`edit-track/${data}`);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Remove from playlist',
|
||||||
|
onClick: () => {
|
||||||
|
removeTrack(data);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
<EmptyEnd />
|
||||||
|
</Flex>
|
||||||
|
<Routes>
|
||||||
|
<Route path="edit-track/:trackId" element={<TrackEditPopUp />} />
|
||||||
|
<Route path="edit-album/:albumId" element={<AlbumEditPopUp />} />
|
||||||
|
</Routes>
|
||||||
|
</PageLayout>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { Center, Heading, Image, Text } from '@chakra-ui/react';
|
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import avatar_generic from '@/assets/images/avatar_generic.svg';
|
import avatar_generic from '@/assets/images/avatar_generic.svg';
|
||||||
@@ -11,6 +10,8 @@ import { SessionState } from '@/service/SessionState';
|
|||||||
import { useSessionService } from '@/service/session';
|
import { useSessionService } from '@/service/session';
|
||||||
import { b64_to_utf8 } from '@/utils/sso';
|
import { b64_to_utf8 } from '@/utils/sso';
|
||||||
|
|
||||||
|
import { Flex, Text, Image } from '@/ui';
|
||||||
|
|
||||||
export const SSOPage = () => {
|
export const SSOPage = () => {
|
||||||
const { data, keepConnected, token } = useParams();
|
const { data, keepConnected, token } = useParams();
|
||||||
console.log(`- data: ${data}`);
|
console.log(`- data: ${data}`);
|
||||||
@@ -47,13 +48,11 @@ export const SSOPage = () => {
|
|||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter width="35%" gap="15px">
|
<PageLayoutInfoCenter width="35%" gap="15px">
|
||||||
<Center w="full">
|
<Text>LOGIN (after SSO)</Text>
|
||||||
<Heading size="xl">LOGIN (after SSO) </Heading>
|
|
||||||
</Center>
|
|
||||||
|
|
||||||
<Center w="full">
|
<Flex width="100%">
|
||||||
<Image src={avatar_generic} boxSize="150px" borderRadius="full" />
|
<Image src={avatar_generic} boxSize="150px" style={{ borderRadius: "full" }} />
|
||||||
</Center>
|
</Flex>
|
||||||
{token === '__CANCEL__' && (
|
{token === '__CANCEL__' && (
|
||||||
<Text>
|
<Text>
|
||||||
<b>ERROR: </b> Request cancel of connection !
|
<b>ERROR: </b> Request cancel of connection !
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import { ReactElement } from 'react';
|
|
||||||
|
|
||||||
import { Flex, Text, Wrap, WrapItem } from '@chakra-ui/react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { DataTools, TypeCheck } from '@/utils/data-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
|
||||||
|
|
||||||
export const alphabet = [
|
export const alphabet = [
|
||||||
'a',
|
'a',
|
||||||
@@ -39,7 +35,6 @@ export const alphabet = [
|
|||||||
const possibilities = [...alphabet, '^^'];
|
const possibilities = [...alphabet, '^^'];
|
||||||
|
|
||||||
export const TrackSelectionPage = () => {
|
export const TrackSelectionPage = () => {
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const onSelectItem = (data: string) => {
|
const onSelectItem = (data: string) => {
|
||||||
navigate(`/track/${data}`);
|
navigate(`/track/${data}`);
|
||||||
@@ -48,24 +43,24 @@ export const TrackSelectionPage = () => {
|
|||||||
<>
|
<>
|
||||||
<TopBar title="All Tracks" />
|
<TopBar title="All Tracks" />
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center">
|
<HStack wrap="wrap" /*spacing="20px"*/ marginX="auto" padding="20px" justify="center">
|
||||||
{possibilities.map((data) => (
|
{possibilities.map((data) => (
|
||||||
<WrapItem
|
<Flex align="flex-start"
|
||||||
width="75px"
|
width="75px"
|
||||||
height="75px"
|
height="75px"
|
||||||
border="1px"
|
border="1px"
|
||||||
borderColor="brand.900"
|
borderColor="brand.900"
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
background={useColorThemeValue('#FFFFFF88', '#00000088')}
|
||||||
key={data}
|
key={data}
|
||||||
padding="5px"
|
padding="5px"
|
||||||
as="button"
|
as="button"
|
||||||
_hover={{
|
_hover={{
|
||||||
boxShadow: 'outline-over',
|
boxShadow: 'outline-over',
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
<Flex direction="column" width="full" height="full">
|
<Flex direction="column" width="100%" height="full">
|
||||||
<Text
|
<Text
|
||||||
margin="auto"
|
margin="auto"
|
||||||
fontSize="25px"
|
fontSize="25px"
|
||||||
@@ -76,9 +71,9 @@ export const TrackSelectionPage = () => {
|
|||||||
{data.toUpperCase()}
|
{data.toUpperCase()}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</WrapItem>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Wrap>
|
</HStack>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
import { ReactElement } from 'react';
|
import { useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { Box, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react';
|
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { EmptyEnd } from '@/components/EmptyEnd';
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { DisplayTrack } from '@/components/track/DisplayTrack';
|
|
||||||
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
|
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
|
||||||
import { DisplayTrackSkeleton } from '@/components/track/DisplayTrackSkeleton';
|
import { DisplayTrackSkeleton } from '@/components/track/DisplayTrackSkeleton';
|
||||||
import { alphabet } from '@/scene/track/TrackSelectionPage';
|
import { alphabet } from '@/scene/track/TrackSelectionPage';
|
||||||
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
import { useTrackService, useTracksWithStartName } from '@/service/Track';
|
import { useTracksWithStartName } from '@/service/Track';
|
||||||
import { useThemeMode } from '@/utils/theme-tools';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Flex } from '@/ui';
|
||||||
|
|
||||||
export const TracksStartLetterDetailPage = () => {
|
export const TracksStartLetterDetailPage = () => {
|
||||||
const { startLetter } = useParams();
|
const { startLetter } = useParams();
|
||||||
const { mode } = useThemeMode();
|
|
||||||
const { isLoading, tracksStartsWith } = useTracksWithStartName(
|
const { isLoading, tracksStartsWith } = useTracksWithStartName(
|
||||||
startLetter !== '^^'
|
startLetter !== '^^'
|
||||||
? startLetter
|
? startLetter
|
||||||
@@ -52,50 +48,55 @@ export const TracksStartLetterDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="20px"
|
gap="20px"
|
||||||
marginX="auto"
|
style={{
|
||||||
padding="20px"
|
margin: "0 auto",
|
||||||
width="80%"
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isLoading &&
|
{isLoading &&
|
||||||
[1, 2, 3, 4]?.map((data) => (
|
[1, 2, 3, 4]?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data}
|
key={data}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height:"60px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackSkeleton />
|
<DisplayTrackSkeleton />
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
{!isLoading &&
|
{!isLoading &&
|
||||||
tracksStartsWith?.map((data) => (
|
tracksStartsWith?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={mode('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height:"60px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: mode('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
background: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackFull
|
<DisplayTrackFull
|
||||||
track={data}
|
track={data}
|
||||||
onClick={() => onSelectItem(data.id)}
|
onClick={() => onSelectItem(data.id)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { Album, AlbumResource } from '@/back-api';
|
import { Album, AlbumResource } from '@/back-api';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { Track, TrackResource } from '@/back-api';
|
import { Track, TrackResource } from '@/back-api';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import { parseToken } from '@/utils/sso';
|
|||||||
|
|
||||||
const TOKEN_KEY = 'karusic-token-key-storage';
|
const TOKEN_KEY = 'karusic-token-key-storage';
|
||||||
|
|
||||||
|
export const USERS_COLLECTION = [
|
||||||
|
{ label: "admin", value: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E" },
|
||||||
|
{ label: "NO_USER", value: "svelte" },
|
||||||
|
];
|
||||||
export const USERS = {
|
export const USERS = {
|
||||||
admin:
|
admin:
|
||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E',
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import { ReactElement, ReactNode } from 'react';
|
import { ReactElement, ReactNode } from 'react';
|
||||||
|
|
||||||
import { ChakraProvider } from '@chakra-ui/react';
|
|
||||||
import { RenderOptions, render } from '@testing-library/react';
|
import { RenderOptions, render } from '@testing-library/react';
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import theme from '@/theme';
|
|
||||||
|
|
||||||
const CustomWrapper = ({ children }: { children: ReactNode }) => {
|
const CustomWrapper = ({ children }: { children: ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
<ChakraProvider theme={theme}>
|
<ChakraProvider value={defaultSystem}>
|
||||||
<BrowserRouter>{children}</BrowserRouter>
|
<BrowserRouter>{children}</BrowserRouter>
|
||||||
</ChakraProvider>
|
</ChakraProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
202
front/src/theme/ThemeContext.tsx
Normal file
202
front/src/theme/ThemeContext.tsx
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
import { createContext, useContext, useState, useEffect, CSSProperties, ReactNode, useCallback } from "react";
|
||||||
|
import { basicColor } from "./colors";
|
||||||
|
|
||||||
|
export type ApplyThemeProperty = {
|
||||||
|
componentType?: String;
|
||||||
|
// define the format of the shape
|
||||||
|
shape?: String;
|
||||||
|
// Define the color model used
|
||||||
|
palette?: String;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ThemeContextProps = {
|
||||||
|
theme: string;
|
||||||
|
themeList: string[];
|
||||||
|
setTheme: (string) => void;
|
||||||
|
toggleTheme: () => void;
|
||||||
|
convertStyle: (style: CSSProperties) => CSSProperties,
|
||||||
|
applyTheme: (style: CSSProperties, theme: ApplyThemeProperty) => CSSProperties,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ThemeContext = createContext<ThemeContextProps>({
|
||||||
|
theme: "error",
|
||||||
|
themeList: ["error"],
|
||||||
|
setTheme: (_: string) => {
|
||||||
|
console.error("Request setTheme without context");
|
||||||
|
},
|
||||||
|
toggleTheme: () => {
|
||||||
|
console.error("Request toggleTheme without context");
|
||||||
|
},
|
||||||
|
convertStyle: (style: CSSProperties): CSSProperties => {
|
||||||
|
console.error("Request convertStyle without context");
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
applyTheme: (style: CSSProperties, _theme: ApplyThemeProperty) => {
|
||||||
|
console.error("Request applyTheme without context");
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const themes = {
|
||||||
|
baseColors: {
|
||||||
|
...basicColor
|
||||||
|
},
|
||||||
|
themeColors: {
|
||||||
|
light: {
|
||||||
|
primary: "#007bff",
|
||||||
|
secondary: "#6c757d",
|
||||||
|
background: "#ffffff",
|
||||||
|
text: "#000000",
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
primary: "#375a7f",
|
||||||
|
secondary: "#444444",
|
||||||
|
background: "#181818",
|
||||||
|
text: "#ffffff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
base: {
|
||||||
|
Button: {
|
||||||
|
border: '1px solid red',
|
||||||
|
},
|
||||||
|
Flex: {
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
outline: {
|
||||||
|
border: '1px solid transparent',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
borderColor: "green"
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
|
||||||
|
},
|
||||||
|
danger: {
|
||||||
|
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export function ThemeProvider({ children, themeList = ["light", "dark"] }: { children: ReactNode, themeList?: string[] }) {
|
||||||
|
const [theme, setTheme] = useState<string>(themeList[1]);
|
||||||
|
const [basicsColor, setBasicsColor] = useState<{ [key: string]: string }>({});
|
||||||
|
|
||||||
|
// update the global CSS wen theme is updated:
|
||||||
|
useEffect(() => {
|
||||||
|
// generates the colors:
|
||||||
|
const baseColor = themes.baseColors;
|
||||||
|
const newBasicsColor: { [key: string]: string } = {}
|
||||||
|
Object.entries(baseColor).forEach(([tableColorName, colorValues]) => {
|
||||||
|
Object.entries(colorValues).forEach(([key, value]) => {
|
||||||
|
const colorName = `${tableColorName}.${key}`;
|
||||||
|
newBasicsColor[colorName] = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setBasicsColor(newBasicsColor);
|
||||||
|
|
||||||
|
const root = document.documentElement;
|
||||||
|
//const currentColorTheme = themes.baseColors[theme];
|
||||||
|
Object.entries(newBasicsColor).forEach(([key, value]) => {
|
||||||
|
const cssKeyValue = `--${key.replace(".", "-")}`;
|
||||||
|
console.log(` generate CSS color: ${cssKeyValue}:${value}`);
|
||||||
|
root.style.setProperty(cssKeyValue, value);
|
||||||
|
});
|
||||||
|
}, [theme, setBasicsColor]);
|
||||||
|
|
||||||
|
const toggleTheme = useCallback(() => {
|
||||||
|
setTheme((previous) => {
|
||||||
|
if (themeList.length <= 1) {
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
for (let iii = 0; iii < themeList.length - 1; iii++) {
|
||||||
|
if (themeList[iii] == theme) {
|
||||||
|
return themeList[iii + 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return themeList[0];
|
||||||
|
})
|
||||||
|
}, [setTheme]);
|
||||||
|
|
||||||
|
const convertElementStyle = useCallback((style: CSSProperties, key: string) => {
|
||||||
|
const value = style[key];
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// console.log(`request convert value: ${value}`);
|
||||||
|
if (basicsColor[value]) {
|
||||||
|
// console.log(`convert value: ${value} in ${basicsColor[value]}`);
|
||||||
|
style[key] = basicsColor[value];
|
||||||
|
}
|
||||||
|
}, [basicsColor]);
|
||||||
|
|
||||||
|
const convertStyle = useCallback((style: CSSProperties): CSSProperties => {
|
||||||
|
//console.log(`plop: ${theme}`);
|
||||||
|
if (!style) {
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
const out = { ...style }
|
||||||
|
convertElementStyle(out, "background");
|
||||||
|
convertElementStyle(out, "backgroundColor");
|
||||||
|
convertElementStyle(out, "borderColor");
|
||||||
|
convertElementStyle(out, "color");
|
||||||
|
return out;
|
||||||
|
}, [convertElementStyle]);
|
||||||
|
|
||||||
|
const applyTheme = useCallback((style: CSSProperties, selectedTheme?: ApplyThemeProperty): CSSProperties => {
|
||||||
|
let out = style;
|
||||||
|
console.log(`apply style ... ${JSON.stringify(selectedTheme, null, 2)}`);
|
||||||
|
// Apply the basic theme of the component:
|
||||||
|
if (selectedTheme?.componentType) {
|
||||||
|
console.log(`detect component type theme ... ${selectedTheme?.componentType}`);
|
||||||
|
const base = themes?.base[selectedTheme.componentType];
|
||||||
|
console.log(` base = ${JSON.stringify(base, null, 2)}`);
|
||||||
|
if (base) {
|
||||||
|
out = { ...base, ...out };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Apply the variant selected:
|
||||||
|
if (selectedTheme?.shape) {
|
||||||
|
const shape = themes?.shape[selectedTheme.shape];
|
||||||
|
if (shape) {
|
||||||
|
out = { ...shape, ...out };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Apply the palette selected:
|
||||||
|
if (selectedTheme?.palette) {
|
||||||
|
const palette = themes?.shape[selectedTheme.palette];
|
||||||
|
if (palette) {
|
||||||
|
const palette2 = palette[theme];
|
||||||
|
if (palette2) {
|
||||||
|
out = { ...palette2, ...out };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertStyle(out);
|
||||||
|
}, [convertStyle]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{ theme, themeList, setTheme, toggleTheme, convertStyle, applyTheme }}>
|
||||||
|
{children}
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const useTheme = () => useContext(ThemeContext);
|
||||||
|
|
||||||
|
export function useColorThemeValue<T>(firstTheme: T, secondTheme: T) {
|
||||||
|
const { theme, themeList } = useTheme()
|
||||||
|
//console.log(`use theme =${theme} ==> ${theme === themeList[0] ? firstTheme : secondTheme}`);
|
||||||
|
return theme === themeList[0] ? firstTheme : secondTheme
|
||||||
|
}
|
||||||
@@ -1,44 +1,4 @@
|
|||||||
type ThemeModel = {
|
// Update me with other Tailwind colors or with https://smart-swatch.netlify.app/
|
||||||
50: string;
|
|
||||||
100: string;
|
|
||||||
200: string;
|
|
||||||
300: string;
|
|
||||||
400: string;
|
|
||||||
500: string;
|
|
||||||
600: string;
|
|
||||||
700: string;
|
|
||||||
800: string;
|
|
||||||
900: string;
|
|
||||||
};
|
|
||||||
const isLightMode = false;
|
|
||||||
const reverseColor = (data: ThemeModel) => {
|
|
||||||
return {
|
|
||||||
50: data[900],
|
|
||||||
100: data[800],
|
|
||||||
200: data[700],
|
|
||||||
300: data[600],
|
|
||||||
400: data[500],
|
|
||||||
500: data[400],
|
|
||||||
600: data[300],
|
|
||||||
700: data[200],
|
|
||||||
800: data[100],
|
|
||||||
900: data[50],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const back = {
|
|
||||||
50: '#ebf4fa',
|
|
||||||
100: '#d1dbe0',
|
|
||||||
200: '#b6c2c9',
|
|
||||||
300: '#99aab4',
|
|
||||||
400: '#7c939e',
|
|
||||||
500: '#637985',
|
|
||||||
600: '#4d5e67',
|
|
||||||
700: '#37444a',
|
|
||||||
800: '#1f292e',
|
|
||||||
900: '#020f12',
|
|
||||||
};
|
|
||||||
|
|
||||||
const brand = {
|
const brand = {
|
||||||
50: '#e3edff',
|
50: '#e3edff',
|
||||||
100: '#b6c9fd',
|
100: '#b6c9fd',
|
||||||
@@ -51,7 +11,8 @@ const brand = {
|
|||||||
800: '#02164a',
|
800: '#02164a',
|
||||||
900: '#00071e',
|
900: '#00071e',
|
||||||
};
|
};
|
||||||
const normalText = {
|
|
||||||
|
const black = {
|
||||||
50: '#f2f2f2',
|
50: '#f2f2f2',
|
||||||
100: '#d9d9d9',
|
100: '#d9d9d9',
|
||||||
200: '#bfbfbf',
|
200: '#bfbfbf',
|
||||||
@@ -88,7 +49,6 @@ const blue = {
|
|||||||
800: '#1e40af',
|
800: '#1e40af',
|
||||||
900: '#1e3a8a',
|
900: '#1e3a8a',
|
||||||
};
|
};
|
||||||
|
|
||||||
const orange = {
|
const orange = {
|
||||||
50: '#fff7ed',
|
50: '#fff7ed',
|
||||||
100: '#ffedd5',
|
100: '#ffedd5',
|
||||||
@@ -113,15 +73,54 @@ const red = {
|
|||||||
800: '#991b1b',
|
800: '#991b1b',
|
||||||
900: '#7f1d1d',
|
900: '#7f1d1d',
|
||||||
};
|
};
|
||||||
|
const yellow = {
|
||||||
|
50: '#ffffda',
|
||||||
|
100: '#ffffad',
|
||||||
|
200: '#ffff7d',
|
||||||
|
300: '#ffff4b',
|
||||||
|
400: '#ffff1a',
|
||||||
|
500: '#e5e600',
|
||||||
|
600: '#b2b300',
|
||||||
|
700: '#7f8000',
|
||||||
|
800: '#4c4d00',
|
||||||
|
900: '#191b00',
|
||||||
|
};
|
||||||
|
const purple = {
|
||||||
|
50: '#ffe3ff',
|
||||||
|
100: '#ffb2ff',
|
||||||
|
200: '#ff80ff',
|
||||||
|
300: '#fe4efe',
|
||||||
|
400: '#fe20fe',
|
||||||
|
500: '#e50ce4',
|
||||||
|
600: '#b204b1',
|
||||||
|
700: '#80007f',
|
||||||
|
800: '#4e004d',
|
||||||
|
900: '#1d001c',
|
||||||
|
};
|
||||||
|
|
||||||
export const colors = {
|
const cyan = {
|
||||||
// Update me with other Tailwind colors or with https://smart-swatch.netlify.app/
|
50: '#d6ffff',
|
||||||
|
100: '#aaffff',
|
||||||
|
200: '#7affff',
|
||||||
|
300: '#47ffff',
|
||||||
|
400: '#1affff',
|
||||||
|
500: '#00e5e6',
|
||||||
|
600: '#00b2b3',
|
||||||
|
700: '#008081',
|
||||||
|
800: '#004d4e',
|
||||||
|
900: '#001b1d',
|
||||||
|
}
|
||||||
|
|
||||||
brand: brand,
|
export const basicColor = {
|
||||||
back: back,
|
brand,
|
||||||
text: normalText,
|
green,
|
||||||
/// ????
|
red,
|
||||||
success: green,
|
orange,
|
||||||
error: red,
|
black,
|
||||||
|
blue,
|
||||||
|
yellow,
|
||||||
|
purple,
|
||||||
|
cyan,
|
||||||
|
back: black,
|
||||||
warning: orange,
|
warning: orange,
|
||||||
} as const;
|
}
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
import { border, defineStyleConfig, keyframes } from '@chakra-ui/react';
|
|
||||||
import { isAccessible, mode, transparentize } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
import { shadows } from '@/theme/foundations/shadows';
|
|
||||||
|
|
||||||
const shimmer = keyframes`
|
|
||||||
100% {
|
|
||||||
transform: translateX(100%);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const customVariant = ({
|
|
||||||
theme,
|
|
||||||
bg,
|
|
||||||
bgHover = bg,
|
|
||||||
bgActive = bgHover,
|
|
||||||
color,
|
|
||||||
colorHover = color,
|
|
||||||
boxColorFocus = '#0x000000',
|
|
||||||
boxShadowHover = 'outline-over',
|
|
||||||
}) => {
|
|
||||||
const isColorAccessible = isAccessible(color, bg, {
|
|
||||||
size: 'large',
|
|
||||||
level: 'AA',
|
|
||||||
})(theme);
|
|
||||||
|
|
||||||
return {
|
|
||||||
bg,
|
|
||||||
color: isColorAccessible ? color : 'black',
|
|
||||||
border: '1px solid #00000000',
|
|
||||||
_focus: {
|
|
||||||
//border: `1px solid ${boxColorFocus}`,
|
|
||||||
border: `1px solid #000000`,
|
|
||||||
},
|
|
||||||
_hover: {
|
|
||||||
bg: bgHover,
|
|
||||||
color: isColorAccessible ? colorHover : 'black',
|
|
||||||
boxShadow: boxShadowHover,
|
|
||||||
_disabled: {
|
|
||||||
bg,
|
|
||||||
boxShadow: 'none',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_active: { bg: bgActive },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default defineStyleConfig({
|
|
||||||
variants: {
|
|
||||||
// Custom variants
|
|
||||||
'@primary': (props) =>
|
|
||||||
customVariant({
|
|
||||||
theme: props.theme,
|
|
||||||
bg: mode('brand.600', 'brand.300')(props),
|
|
||||||
bgHover: mode('brand.700', 'brand.400')(props),
|
|
||||||
bgActive: mode('brand.600', 'brand.300')(props),
|
|
||||||
color: mode('white', 'brand.900')(props),
|
|
||||||
boxColorFocus: mode('brand.100', 'brand.600')(props),
|
|
||||||
}),
|
|
||||||
'@secondary': (props) =>
|
|
||||||
customVariant({
|
|
||||||
theme: props.theme,
|
|
||||||
bg: mode('brand.100', 'brand.900')(props),
|
|
||||||
bgHover: mode('brand.200', 'brand.800')(props),
|
|
||||||
bgActive: mode('brand.300', 'brand.700')(props),
|
|
||||||
color: mode('brand.700', 'brand.50')(props),
|
|
||||||
colorHover: mode('brand.800', 'brand.100')(props),
|
|
||||||
boxColorFocus: mode('brand.900', 'brand.300')(props),
|
|
||||||
}),
|
|
||||||
'@danger': (props) =>
|
|
||||||
customVariant({
|
|
||||||
theme: props.theme,
|
|
||||||
bg: mode('error.600', 'error.600')(props),
|
|
||||||
bgHover: mode('error.700', 'error.500')(props),
|
|
||||||
bgActive: mode('error.600', 'error.500')(props),
|
|
||||||
color: mode('white', 'error.900')(props),
|
|
||||||
boxColorFocus: mode('error.900', 'error.500')(props),
|
|
||||||
}),
|
|
||||||
'@success': (props) =>
|
|
||||||
customVariant({
|
|
||||||
theme: props.theme,
|
|
||||||
bg: mode('green.300', 'green.300')(props),
|
|
||||||
bgHover: mode('green.400', 'green.400')(props),
|
|
||||||
bgActive: mode('green.500', 'green.400')(props),
|
|
||||||
color: mode('white', 'green.900')(props),
|
|
||||||
boxColorFocus: mode('green.900', 'green.400')(props),
|
|
||||||
}),
|
|
||||||
|
|
||||||
'@progress': (props) => ({
|
|
||||||
...customVariant({
|
|
||||||
theme: props.theme,
|
|
||||||
bg: mode(`${props.colorScheme}.500`, `${props.colorScheme}.300`)(props),
|
|
||||||
bgHover: mode(
|
|
||||||
`${props.colorScheme}.600`,
|
|
||||||
`${props.colorScheme}.400`
|
|
||||||
)(props),
|
|
||||||
bgActive: mode(
|
|
||||||
`${props.colorScheme}.700`,
|
|
||||||
`${props.colorScheme}.500`
|
|
||||||
)(props),
|
|
||||||
color: mode('white', `${props.colorScheme}.900`)(props),
|
|
||||||
boxColorFocus: mode(
|
|
||||||
`${props.colorScheme}.900`,
|
|
||||||
`${props.colorScheme}.600`
|
|
||||||
)(props),
|
|
||||||
}),
|
|
||||||
overflow: 'hidden',
|
|
||||||
|
|
||||||
_after: !props.isLoading
|
|
||||||
? {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
transform: 'translateX(-100%)',
|
|
||||||
bgGradient: `linear(90deg, ${transparentize(
|
|
||||||
`${props.colorScheme}.100`,
|
|
||||||
0
|
|
||||||
)(props.theme)} 0, ${transparentize(
|
|
||||||
`${props.colorScheme}.100`,
|
|
||||||
0.2
|
|
||||||
)(props.theme)} 20%, ${transparentize(
|
|
||||||
`${props.colorScheme}.100`,
|
|
||||||
0.5
|
|
||||||
)(props.theme)} 60%, ${transparentize(
|
|
||||||
`${props.colorScheme}.100`,
|
|
||||||
0
|
|
||||||
)(props.theme)})`,
|
|
||||||
animation: `${shimmer} 3s infinite`,
|
|
||||||
content: '""',
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
}),
|
|
||||||
'@menu': (props) => ({
|
|
||||||
bg: mode('back.100', 'back.800')(props),
|
|
||||||
color: mode('brand.900', 'brand.100')(props),
|
|
||||||
borderRadius: 0,
|
|
||||||
border: 0,
|
|
||||||
_hover: { background: mode('back.300', 'back.600')(props) },
|
|
||||||
_focus: { border: 'none' },
|
|
||||||
fontSize: '20px',
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Default variants
|
|
||||||
solid: (props) => ({
|
|
||||||
bg:
|
|
||||||
props.colorScheme === 'gray'
|
|
||||||
? mode('gray.100', 'whiteAlpha.100')(props)
|
|
||||||
: `${props.colorScheme}.600`,
|
|
||||||
_hover: {
|
|
||||||
bg:
|
|
||||||
props.colorScheme === 'gray'
|
|
||||||
? mode('gray.200', 'whiteAlpha.200')(props)
|
|
||||||
: `${props.colorScheme}.700`,
|
|
||||||
},
|
|
||||||
_focus: {
|
|
||||||
boxShadow: `outline-${props.colorScheme}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
light: (props) => ({
|
|
||||||
bg:
|
|
||||||
props.colorScheme === 'gray'
|
|
||||||
? mode('gray.100', 'whiteAlpha.100')(props)
|
|
||||||
: `${props.colorScheme}.100`,
|
|
||||||
color:
|
|
||||||
props.colorScheme === 'gray'
|
|
||||||
? mode('gray.700', 'whiteAlpha.700')(props)
|
|
||||||
: `${props.colorScheme}.700`,
|
|
||||||
_hover: {
|
|
||||||
bg:
|
|
||||||
props.colorScheme === 'gray'
|
|
||||||
? mode('gray.200', 'whiteAlpha.200')(props)
|
|
||||||
: `${props.colorScheme}.200`,
|
|
||||||
color:
|
|
||||||
props.colorScheme === 'gray'
|
|
||||||
? mode('gray.800', 'whiteAlpha.800')(props)
|
|
||||||
: `${props.colorScheme}.800`,
|
|
||||||
},
|
|
||||||
_focus: {
|
|
||||||
boxShadow: `outline-${props.colorScheme}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
ghost: (props) => ({
|
|
||||||
bg: transparentize(`${props.colorScheme}.50`, 0.05)(props.theme),
|
|
||||||
borderRadius: 'full',
|
|
||||||
_hover: {
|
|
||||||
bg: transparentize(`${props.colorScheme}.50`, 0.15)(props.theme),
|
|
||||||
},
|
|
||||||
_focus: {
|
|
||||||
boxShadow: 'none',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { defineStyleConfig } from '@chakra-ui/react';
|
|
||||||
import { mode } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
|
|
||||||
const flexTheme = defineStyleConfig({
|
|
||||||
variants: {
|
|
||||||
'@menu': (props) => ({
|
|
||||||
bg: mode('back.100', 'back.800')(props),
|
|
||||||
color: mode('brand.900', 'brand.100')(props),
|
|
||||||
borderRadius: 0,
|
|
||||||
border: 0,
|
|
||||||
_hover: { background: mode('back.300', 'back.600')(props) },
|
|
||||||
_focus: { border: 'none' },
|
|
||||||
fontSize: '20px',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default flexTheme;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { getColor, mode } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
variants: {
|
|
||||||
outline: (props) => {
|
|
||||||
const focusBorderColor = getColor(
|
|
||||||
props.theme,
|
|
||||||
props.focusBorderColor
|
|
||||||
? props.focusBorderColor
|
|
||||||
: mode('brand.500', 'brand.300')(props)
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
field: {
|
|
||||||
bg: mode('gray.50', 'whiteAlpha.50')(props),
|
|
||||||
borderColor: mode('gray.200', 'whiteAlpha.100')(props),
|
|
||||||
color: mode('gray.800', 'gray.50')(props),
|
|
||||||
_focus: {
|
|
||||||
borderColor: focusBorderColor,
|
|
||||||
boxShadow: `0 0 0 1px ${focusBorderColor}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { numberInputAnatomy } from '@chakra-ui/anatomy';
|
|
||||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
|
|
||||||
import { getColor, mode } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
const { definePartsStyle, defineMultiStyleConfig } =
|
|
||||||
createMultiStyleConfigHelpers(numberInputAnatomy.keys);
|
|
||||||
|
|
||||||
const baseStyle = definePartsStyle((props) => {
|
|
||||||
const focusBorderColor = getColor(
|
|
||||||
props.theme,
|
|
||||||
props.focusBorderColor
|
|
||||||
? props.focusBorderColor
|
|
||||||
: mode('brand.500', 'brand.300')(props)
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
field: {
|
|
||||||
border: 0,
|
|
||||||
_focusVisible: {
|
|
||||||
borderColor: focusBorderColor,
|
|
||||||
boxShadow: `0 0 0 1px ${focusBorderColor}`,
|
|
||||||
ring: '1px',
|
|
||||||
ringColor: focusBorderColor,
|
|
||||||
ringOffset: '1px',
|
|
||||||
ringOffsetColor: focusBorderColor,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export default defineMultiStyleConfig({
|
|
||||||
baseStyle,
|
|
||||||
});
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { getColor, mode } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
variants: {
|
|
||||||
outline: (props) => {
|
|
||||||
const focusBorderColor = getColor(
|
|
||||||
props.theme,
|
|
||||||
props.focusBorderColor
|
|
||||||
? props.focusBorderColor
|
|
||||||
: mode('brand.500', 'brand.300')(props)
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
field: {
|
|
||||||
bg: mode('gray.50', 'whiteAlpha.50')(props),
|
|
||||||
borderColor: mode('blackAlpha.100', 'whiteAlpha.100')(props),
|
|
||||||
_focus: {
|
|
||||||
borderColor: focusBorderColor,
|
|
||||||
boxShadow: `0 0 0 1px ${focusBorderColor}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { getColor, mode } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
variants: {
|
|
||||||
outline: (props) => {
|
|
||||||
const focusBorderColor = getColor(
|
|
||||||
props.theme,
|
|
||||||
props.focusBorderColor
|
|
||||||
? props.focusBorderColor
|
|
||||||
: mode('brand.500', 'brand.300')(props)
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
bg: mode('gray.50', 'whiteAlpha.50')(props),
|
|
||||||
borderColor: mode('blackAlpha.100', 'whiteAlpha.100')(props),
|
|
||||||
_focus: {
|
|
||||||
borderColor: focusBorderColor,
|
|
||||||
boxShadow: `0 0 0 1px ${focusBorderColor}`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { colors } from './colors';
|
|
||||||
import { shadows } from './shadows';
|
|
||||||
|
|
||||||
const foundations = {
|
|
||||||
colors,
|
|
||||||
shadows,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default foundations;
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { transparentize } from '@chakra-ui/theme-tools';
|
|
||||||
|
|
||||||
import { colors } from './colors';
|
|
||||||
|
|
||||||
const createOutline = (colorScheme = 'gray') =>
|
|
||||||
`0 0 0 3px ${transparentize(`${colorScheme}.500`, 0.3)({ colors })}`;
|
|
||||||
|
|
||||||
export const shadows = {
|
|
||||||
outline: createOutline('brand'),
|
|
||||||
'outline-brand': '0 0 0 1px brand.900',
|
|
||||||
'outline-gray': createOutline('gray'),
|
|
||||||
'outline-over': `4px 4px 5px #00000088`,
|
|
||||||
'outline-darkgray': `0 0 0 3px ${transparentize(
|
|
||||||
'gray.500',
|
|
||||||
0.8
|
|
||||||
)({ colors })}`,
|
|
||||||
'outline-success': createOutline('success'),
|
|
||||||
'outline-warning': createOutline('warning'),
|
|
||||||
'outline-error': createOutline('error'),
|
|
||||||
'outline-doing': createOutline('doing'),
|
|
||||||
'outline-paused': createOutline('paused'),
|
|
||||||
layout: '0 0 24px 1px rgba(0, 0, 0, 0.05)',
|
|
||||||
smooth: 'inset 0px 0px 16px rgba(0, 0, 0, 0.05)',
|
|
||||||
// smooth-light is used for dark backgrounds
|
|
||||||
'smooth-light': 'inset 0px 0px 16px rgba(255, 255, 255, 0.1)',
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { theme as default } from './theme';
|
|
||||||
103
front/src/theme/recipes/button.ts
Normal file
103
front/src/theme/recipes/button.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
// https://medium.com/@a.heydari.dev/simplifying-chakra-ui-v3-recipes-vs-chakra-factory-a-developers-perspective-4020b62f1b4d
|
||||||
|
|
||||||
|
// const shimmer = keyframes`
|
||||||
|
// 100% {
|
||||||
|
// transform: translateX(100%);
|
||||||
|
// }
|
||||||
|
// `;
|
||||||
|
|
||||||
|
export const customVariant = ({ bg, bgHover, bgActive, color, colorHover, boxShadowHover }) => {
|
||||||
|
return {
|
||||||
|
bg,
|
||||||
|
color,
|
||||||
|
border: '1px solid transparent',
|
||||||
|
_focus: {
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'black',
|
||||||
|
},
|
||||||
|
_hover: {
|
||||||
|
bg: bgHover,
|
||||||
|
color: colorHover,
|
||||||
|
boxShadow: boxShadowHover,
|
||||||
|
_disabled: {
|
||||||
|
bg,
|
||||||
|
boxShadow: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_active: {
|
||||||
|
bg: bgActive,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttonTheme = {
|
||||||
|
primary:
|
||||||
|
customVariant({
|
||||||
|
bg: { _light: 'brand.600', _dark: 'brand.300' },
|
||||||
|
bgHover: { _light: 'brand.700', _dark: 'brand.400' },
|
||||||
|
bgActive: { _light: 'brand.600', _dark: 'brand.300' },
|
||||||
|
color: { _light: 'white', _dark: 'brand.900' },
|
||||||
|
colorHover: { _light: 'brand.800', _dark: 'brand.100' },
|
||||||
|
boxShadowHover: 'outline-over'
|
||||||
|
}),
|
||||||
|
secondary:
|
||||||
|
customVariant({
|
||||||
|
bg: { _light: 'brand.100', _dark: 'brand.900' },
|
||||||
|
bgHover: { _light: 'brand.200', _dark: 'brand.800' },
|
||||||
|
bgActive: { _light: 'brand.300', _dark: 'brand.700' },
|
||||||
|
color: { _light: 'brand.700', _dark: 'brand.50' },
|
||||||
|
colorHover: { _light: 'brand.800', _dark: 'brand.100' },
|
||||||
|
boxShadowHover: 'outline-over',
|
||||||
|
}),
|
||||||
|
danger:
|
||||||
|
customVariant({
|
||||||
|
bg: { _light: 'error.600', _dark: 'error.600' },
|
||||||
|
bgHover: { _light: 'error.700', _dark: 'error.500' },
|
||||||
|
bgActive: { _light: 'error.600', _dark: 'error.500' },
|
||||||
|
color: { _light: 'white', _dark: 'error.900' },
|
||||||
|
colorHover: { _light: 'error.700', _dark: 'error.900' },
|
||||||
|
boxShadowHover: 'outline-over',
|
||||||
|
}),
|
||||||
|
success:
|
||||||
|
customVariant({
|
||||||
|
bg: { _light: 'green.300', _dark: 'green.300' },
|
||||||
|
bgHover: { _light: 'green.400', _dark: 'green.400' },
|
||||||
|
bgActive: { _light: 'green.500', _dark: 'green.400' },
|
||||||
|
color: { _light: 'white', _dark: 'green.900' },
|
||||||
|
colorHover: { _light: 'green.500', _dark: 'green.900' },
|
||||||
|
boxShadowHover: 'outline-over',
|
||||||
|
}),
|
||||||
|
progress:
|
||||||
|
{
|
||||||
|
bg: { _light: `brand.500`, _dark: `brand.300` },
|
||||||
|
overflow: 'hidden',
|
||||||
|
/*
|
||||||
|
_after: !props.isLoading
|
||||||
|
? {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
transform: 'translateX(-100%)',
|
||||||
|
bgGradient: `linear(90deg, brand.100/0 0%, brand.100/2 20%, brand.100/5 60%, v.100/0`,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
|
||||||
|
menu: {
|
||||||
|
bg: 'back.100',
|
||||||
|
color: 'brand.900',
|
||||||
|
borderRadius: 0,
|
||||||
|
border: 0,
|
||||||
|
_hover: { background: 'back.300' },
|
||||||
|
_focus: { border: 'none' },
|
||||||
|
fontSize: '20px',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default buttonTheme;
|
||||||
29
front/src/theme/recipes/drawer.ts
Normal file
29
front/src/theme/recipes/drawer.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const drawerRecipe = {
|
||||||
|
base: {
|
||||||
|
bg: { _light: 'white', _dark: 'gray.800' },
|
||||||
|
color: { _light: 'gray.900', _dark: 'whiteAlpha.900' },
|
||||||
|
boxShadow: { _light: 'lg', _dark: 'dark-lg' },
|
||||||
|
padding: 4,
|
||||||
|
borderRadius: 'md',
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
solid: {
|
||||||
|
bg: { _light: 'blue.500', _dark: 'blue.300' },
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
outline: {
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: { _light: 'gray.300', _dark: 'whiteAlpha.300' },
|
||||||
|
bg: { _light: 'white', _dark: 'gray.900' },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'solid',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default drawerRecipe;
|
||||||
20
front/src/theme/recipes/flex.ts
Normal file
20
front/src/theme/recipes/flex.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const flexTheme = {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
'@menu': {
|
||||||
|
bg: { _light: 'back.100', _dark: 'back.800' },
|
||||||
|
color: { _light: 'brand.900', _dark: 'brand.100' },
|
||||||
|
borderRadius: 0,
|
||||||
|
border: 0,
|
||||||
|
_hover: { background: { _light: 'back.300', _dark: 'back.600' } },
|
||||||
|
_focus: { border: 'none' },
|
||||||
|
fontSize: '20px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default flexTheme;
|
||||||
@@ -2,11 +2,12 @@ export { default as Badge } from './badge';
|
|||||||
export { default as Button } from './button';
|
export { default as Button } from './button';
|
||||||
export { default as Checkbox } from './checkbox';
|
export { default as Checkbox } from './checkbox';
|
||||||
export { default as Input } from './input';
|
export { default as Input } from './input';
|
||||||
export { default as NumberInput } from './numberInput';
|
//export { default as NumberInput } from './numberInput.ts_';
|
||||||
export { default as Popover } from './popover';
|
export { default as Popover } from './popover';
|
||||||
export { default as Radio } from './radio';
|
export { default as Radio } from './radio';
|
||||||
export { default as Select } from './select';
|
export { default as Select } from './select';
|
||||||
export { default as Switch } from './switch';
|
export { default as Switch } from './switch';
|
||||||
export { default as Textarea } from './textarea';
|
export { default as Textarea } from './textarea';
|
||||||
export { default as Modal } from './modal';
|
//export { default as Modal } from './modal';
|
||||||
export { default as Flex } from './flex';
|
export { default as Flex } from './flex';
|
||||||
|
export { default as Drawer } from './drawer';
|
||||||
20
front/src/theme/recipes/input.ts
Normal file
20
front/src/theme/recipes/input.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
const inputTheme = {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
outline: {
|
||||||
|
field: {
|
||||||
|
bg: { _light: 'gray.50', _dark: 'whiteAlpha.50' },
|
||||||
|
borderColor: { _light: 'gray.200', _dark: 'whiteAlpha.100' },
|
||||||
|
color: { _light: 'gray.800', _dark: 'gray.50' },
|
||||||
|
_focus: {
|
||||||
|
borderColor: { _light: 'gray.800', _dark: 'gray.50' },
|
||||||
|
boxShadow: `0 0 0 1px gray.800`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default inputTheme;
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import { modalAnatomy as parts } from '@chakra-ui/anatomy';
|
|
||||||
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
|
|
||||||
|
|
||||||
const { definePartsStyle, defineMultiStyleConfig } =
|
const { definePartsStyle, defineMultiStyleConfig } =
|
||||||
createMultiStyleConfigHelpers(parts.keys);
|
createMultiStyleConfigHelpers(parts.keys);
|
||||||
19
front/src/theme/recipes/select.ts
Normal file
19
front/src/theme/recipes/select.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
const selectTheme = {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
outline: {
|
||||||
|
field: {
|
||||||
|
bg: { _light: 'gray.50', _dark: 'whiteAlpha.50' },
|
||||||
|
borderColor: { _light: 'blackAlpha.100', _dark: 'whiteAlpha.100' },
|
||||||
|
_focus: {
|
||||||
|
borderColor: { _light: 'brand.500', _dark: 'brand.300' },
|
||||||
|
boxShadow: `0 0 0 1px black`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default selectTheme;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user