完成基本的几个页面样式
parent
fb48b7d2c5
commit
56054da74a
@ -1,37 +0,0 @@
|
||||
import { createEffect, createSignal, JSXElement, onCleanup, onMount, useTransition } from "solid-js"
|
||||
|
||||
export type CardProps = {
|
||||
title?: string | JSXElement,
|
||||
children?: any
|
||||
}
|
||||
|
||||
export const Card = (props: CardProps) => {
|
||||
const [outerHeight, setOuterHeight] = createSignal<number>(0)
|
||||
let innerElem: HTMLDivElement | undefined
|
||||
|
||||
onMount(() => {
|
||||
if (innerElem) {
|
||||
setOuterHeight(innerElem?.offsetHeight)
|
||||
}
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (innerElem) {
|
||||
setOuterHeight(innerElem?.offsetHeight)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div class="p-5 mb-4 bg-light rounded-3">
|
||||
<div class="container-fluid py-5">
|
||||
<div class="card-wrapper" style={{ height: outerHeight() + 'px' }}>
|
||||
<div class="card-inner" ref={innerElem}>
|
||||
<h1 class="display-5 fw-bold">{props.title}</h1>
|
||||
<p class="col-md-8 fs-4">点击下方按钮开始播放</p>
|
||||
<button class="btn btn-primary btn-lg" type="button">Example button</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
export const ConnectingWell = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1 class="display-5 fw-bold">正在准备</h1>
|
||||
<p class="col-md-8 fs-4">播放器正在连接到服务器</p>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
.height-transition-container {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transition: height 350ms ease-in-out;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.height-transition-inner {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import { createSignal, JSXElement } from "solid-js"
|
||||
import { Transition } from "solid-transition-group"
|
||||
import "./index.scss";
|
||||
|
||||
export type HeightTransitionProps = {
|
||||
children: JSXElement
|
||||
}
|
||||
|
||||
export const HeightTransition = (props: HeightTransitionProps) => {
|
||||
const [outerHeight, setOuterHeight] = createSignal<number | undefined>()
|
||||
|
||||
return (
|
||||
<div class="height-transition-container" style={{ height: outerHeight() ? outerHeight() + 'px' : undefined }}>
|
||||
<div class="height-transition-inner">
|
||||
<Transition
|
||||
name="fade-left"
|
||||
onEnter={(el, done) => {
|
||||
setOuterHeight((el as any).offsetHeight);
|
||||
setTimeout(done, 400);
|
||||
}}
|
||||
onExit={(el, done) => {
|
||||
setOuterHeight((el as any).offsetHeight);
|
||||
setTimeout(done, 400);
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
export const PlayerWell = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1 class="display-5 fw-bold">播放器已准备完成</h1>
|
||||
<p class="col-md-8 fs-4">当前状态: 等待播放</p>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import { Match, mergeProps, Switch } from "solid-js";
|
||||
import { Transition } from "solid-transition-group"
|
||||
|
||||
export type ServerStatusType = 'connecting' | 'connected' | 'error'
|
||||
|
||||
export type ServerStatusProps = {
|
||||
type?: ServerStatusType,
|
||||
error?: string
|
||||
}
|
||||
|
||||
export const ServerStatus = (srcProps: ServerStatusProps) => {
|
||||
const props = mergeProps({
|
||||
type: 'connecting',
|
||||
}, srcProps)
|
||||
|
||||
return (
|
||||
<div class="anim-scroll-container">
|
||||
<Transition name="slide-up">
|
||||
<Switch>
|
||||
<Match when={props.type === "connecting"}>
|
||||
<div class="text-primary d-flex align-items-center">
|
||||
<div class="spinner-grow spinner-grow-sm me-2" role="status"></div>
|
||||
<span>正在连接服务器</span>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={props.type === "connected"}>
|
||||
<div class="text-success"><i class="bi bi-check-circle"></i> 已连接到服务器</div>
|
||||
</Match>
|
||||
<Match when={props.type === "error"}>
|
||||
<div class="text-danger"> 无法连接到服务器{props.error && (': ' + props.error)}</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
.success-animation {
|
||||
display: inline-block;
|
||||
padding: 6px;
|
||||
|
||||
.checkmark {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
--bs-bg-opacity: 1;
|
||||
stroke-width: 3px;
|
||||
stroke: rgb(var(--bs-success-rgb));
|
||||
stroke-miterlimit: 10;
|
||||
box-shadow: inset 0px 0px 0px rgb(var(--bs-success-rgb));
|
||||
animation: successAnimIconFill .4s ease-in-out .4s forwards;
|
||||
|
||||
&__circle {
|
||||
stroke-dasharray: 166;
|
||||
stroke-dashoffset: 166;
|
||||
stroke-width: 3px;
|
||||
stroke-miterlimit: 10;
|
||||
stroke: rgb(var(--bs-success-rgb));
|
||||
fill: rgb(var(--bs-white-rgb));
|
||||
animation: successAnimIconStroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards;
|
||||
}
|
||||
|
||||
&__check {
|
||||
transform-origin: 50% 50%;
|
||||
stroke-dasharray: 48;
|
||||
stroke-dashoffset: 48;
|
||||
animation: successAnimIconStroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.6s forwards;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes successAnimIconStroke {
|
||||
100% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes successAnimIconFill {
|
||||
100% {
|
||||
box-shadow: inset 0px 0px 0px 30px #4bb71b;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import "./index.scss"
|
||||
|
||||
export const SuccessAnimateIcon = () => {
|
||||
return (
|
||||
<div class="success-animation">
|
||||
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
|
||||
<circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" />
|
||||
<path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" />
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
};
|
@ -1,2 +1,4 @@
|
||||
@import "./libs/bootstrap/scss/bootstrap.scss";
|
||||
@import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
|
||||
@import "./styles/animate.scss";
|
@ -0,0 +1,94 @@
|
||||
.anim-scroll-container {
|
||||
overflow-y: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.slide-up {
|
||||
&-enter-active {
|
||||
transform: translate3d(0, 100%, 0);
|
||||
transition: transform 350ms ease-in-out;
|
||||
}
|
||||
|
||||
&-enter-to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
&-exit-active {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: transform 350ms ease-in-out;
|
||||
}
|
||||
|
||||
&-exit-to {
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.fade {
|
||||
&-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&-enter-active {
|
||||
display: inherit;
|
||||
opacity: 0;
|
||||
transition: opacity 150ms linear;
|
||||
}
|
||||
|
||||
&-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-exit {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-exit-active {
|
||||
opacity: 1;
|
||||
transition: opacity 150ms linear;
|
||||
}
|
||||
|
||||
&-exit-to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-left {
|
||||
&-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&-enter-active {
|
||||
display: inherit;
|
||||
opacity: 0;
|
||||
transform: translate3d(5%, 0, 0);
|
||||
transition: opacity 250ms linear, transform 250ms ease-in-out;
|
||||
}
|
||||
|
||||
&-enter-to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
&-exit {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-exit-active {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: opacity 250ms linear, transform 250ms ease-in-out;
|
||||
}
|
||||
|
||||
&-exit-to {
|
||||
opacity: 0;
|
||||
transform: translate3d(-5%, 0, 0);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue