mirror of
https://github.com/ldxw/cdn.git
synced 2026-08-14 04:51:24 +08:00
444 lines
12 KiB
HTML
444 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<title>白昼黑夜切换器</title>
|
||
<link
|
||
rel="stylesheet"
|
||
href="https://cdn.oplist.org/gh/ldxw/cdn@master/code/html/react-day-night-toggle-theme-animation/css/normalize-5.0.0.min.css"
|
||
/>
|
||
<style>
|
||
@import url("https://fonts.googleapis.com/css?family=Gloria+Hallelujah");
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
body {
|
||
background: #7ec0ee;
|
||
margin: 0;
|
||
padding: 0;
|
||
height: 100vh;
|
||
width: 100vw;
|
||
overflow: hidden;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 3rem;
|
||
font-family: "Gloria Hallelujah", cursive;
|
||
font-weight: bold;
|
||
color: #fafafa;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="root">Loading...</div>
|
||
<!-- 修正CDN链接格式,删除多余空引号 -->
|
||
<script src="https://cdn.jsdmirror.cn/npm/react@16.3.0-alpha.1/umd/react.development.js"></script>
|
||
<script src="https://cdn.jsdmirror.cn/npm/react-dom@16.3.0-alpha.1/umd/react-dom.development.js"></script>
|
||
<script src="https://cdn.jsdmirror.cn/npm/styled-components@2.2.1/dist/styled-components.min.js"></script>
|
||
<script>
|
||
function _defineProperty(obj, key, value) {
|
||
if (key in obj) {
|
||
Object.defineProperty(obj, key, {
|
||
value: value,
|
||
enumerable: true,
|
||
configurable: true,
|
||
writable: true,
|
||
});
|
||
} else {
|
||
obj[key] = value;
|
||
}
|
||
return obj;
|
||
}
|
||
function _extends() {
|
||
_extends =
|
||
Object.assign ||
|
||
function (target) {
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
var source = arguments[i];
|
||
for (var key in source) {
|
||
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
||
target[key] = source[key];
|
||
}
|
||
}
|
||
}
|
||
return target;
|
||
};
|
||
return _extends.apply(this, arguments);
|
||
}
|
||
const {
|
||
React,
|
||
ReactDOM,
|
||
styled: { default: styled, keyframes },
|
||
} = window;
|
||
|
||
const { createContext, Component } = React;
|
||
const { render } = ReactDOM;
|
||
|
||
const THEME_CONSTANTS = {
|
||
NIGHT: "night",
|
||
DAY: "day",
|
||
};
|
||
|
||
// 修正时间判断逻辑(原d<6语法错误,应取getHours())
|
||
const d = new Date();
|
||
const hours = d.getHours();
|
||
const defaultValue =
|
||
hours < 6 || hours > 19 ? THEME_CONSTANTS.NIGHT : THEME_CONSTANTS.DAY;
|
||
const ThemeContext = createContext(defaultValue);
|
||
|
||
const $night = "#111";
|
||
const $day = "#7ec0ee";
|
||
const $starColor = "#fefcd7";
|
||
const $sunColor = "#f9fa57";
|
||
const $size = 25;
|
||
const $transitionDuration = 0.75;
|
||
const $skyChangeDuration = 0.5;
|
||
const $positionX = 20;
|
||
const $positionY = 10;
|
||
|
||
const Container = styled.div`
|
||
background-color: ${(p) =>
|
||
p.theme === THEME_CONSTANTS.NIGHT ? $night : $day};
|
||
height: 100vh;
|
||
transition: background ${$skyChangeDuration} ease;
|
||
width: 100vw;
|
||
`;
|
||
|
||
// 修正BigStar组件,补充闭合花括号
|
||
const BigStar = styled.div`
|
||
border-radius: 100%;
|
||
height: ${$size}vh;
|
||
left: ${$positionX}vw;
|
||
position: absolute;
|
||
top: ${$positionY}vh;
|
||
transition: transform ${$transitionDuration}s ease 0s;
|
||
width: ${$size}vh;
|
||
z-index: 2;
|
||
`;
|
||
|
||
// 修正extend语法对齐
|
||
const Moon = BigStar.extend`
|
||
background-color: ${$starColor};
|
||
box-shadow: 0px 0px 50px #eee;
|
||
overflow: hidden;
|
||
transform: ${(p) =>
|
||
p.theme === THEME_CONSTANTS.NIGHT
|
||
? "scale(1)"
|
||
: "scale(0.5) translateX(-75vw) translateY(-120vh)"};
|
||
&:after {
|
||
box-shadow: inset 10px 10px 10px #bbb;
|
||
border-radius: 100%;
|
||
content: "";
|
||
display: block;
|
||
height: 100%;
|
||
width: 100%;
|
||
}
|
||
`;
|
||
|
||
const Craters = styled.div`
|
||
background-color: #ddd;
|
||
border-radius: 100%;
|
||
opacity: 0.5;
|
||
position: absolute;
|
||
top: 15%;
|
||
left: 15%;
|
||
height: ${$size * 0.25}vh;
|
||
width: ${$size * 0.25}vh;
|
||
|
||
&:before {
|
||
background-color: #ddd;
|
||
content: "";
|
||
display: block;
|
||
border-radius: 100%;
|
||
height: 50%;
|
||
width: 50%;
|
||
position: absolute;
|
||
top: 110%;
|
||
}
|
||
|
||
&:after {
|
||
background-color: #ddd;
|
||
content: "";
|
||
display: block;
|
||
border-radius: 100%;
|
||
height: 30%;
|
||
width: 30%;
|
||
position: absolute;
|
||
top: 80%;
|
||
right: 110%;
|
||
}
|
||
`;
|
||
|
||
const CloudMove = keyframes`
|
||
0% {
|
||
transform: translateX(300%);
|
||
opacity: 0;
|
||
}
|
||
50% {
|
||
opacity: .75;
|
||
}
|
||
25%, 75% {
|
||
opacity: 0;
|
||
}
|
||
100% {
|
||
transform: translateX(-300%);
|
||
opacity: 0;
|
||
}
|
||
`;
|
||
|
||
const Star = styled.div`
|
||
background: ${(p) =>
|
||
p.theme === THEME_CONSTANTS.NIGHT ? $starColor : $day};
|
||
border-radius: 100%;
|
||
height: ${(p) => p.size}px;
|
||
left: ${(p) => p.x}vw;
|
||
position: absolute;
|
||
top: ${(p) => p.y}vh;
|
||
opacity: ${(p) => (p.theme === THEME_CONSTANTS.NIGHT ? 1 : 0)};
|
||
transition: background ${$transitionDuration}s ease 0s,
|
||
opacity ${$transitionDuration}s ease 0s;
|
||
width: ${(p) => p.size}px;
|
||
z-index: 1;
|
||
`;
|
||
|
||
// 修正extend语法对齐
|
||
const Sun = BigStar.extend`
|
||
background-color: ${$sunColor};
|
||
box-shadow: 0px 0px 150px yellow;
|
||
transform: ${(p) =>
|
||
p.theme === THEME_CONSTANTS.NIGHT
|
||
? "scale(0.5) translateX(75vw) translateY(200vh)"
|
||
: "scale(1)"};
|
||
`;
|
||
|
||
const Features = styled.div`
|
||
height: 50%;
|
||
width: 50%;
|
||
position: absolute;
|
||
right: 15%;
|
||
bottom: 15%;
|
||
transition: opacity 0.15s ease 0s;
|
||
transition-delay: 0.75s;
|
||
opacity: ${(p) => (p.show ? "1" : "0")};
|
||
`;
|
||
|
||
const Blink = keyframes`
|
||
0%, 5%, 7%, 100% {
|
||
transform: scaleY(1);
|
||
}
|
||
6% {
|
||
transform: scaleY(0);
|
||
}
|
||
`;
|
||
|
||
const Eye = styled.div`
|
||
border-radius: 100%;
|
||
height: 15%;
|
||
width: 15%;
|
||
background-color: black;
|
||
position: absolute;
|
||
top: 25%;
|
||
animation: ${Blink} 10s infinite 1s;
|
||
transform-origin: center;
|
||
|
||
&:after {
|
||
background-color: #fff;
|
||
border-radius: 100%;
|
||
content: "";
|
||
height: 40%;
|
||
width: 40%;
|
||
position: absolute;
|
||
top: 5%;
|
||
right: 30%;
|
||
display: block;
|
||
}
|
||
`;
|
||
|
||
const LeftEye = Eye.extend`
|
||
left: 25%;
|
||
`;
|
||
|
||
const RightEye = Eye.extend`
|
||
left: 75%;
|
||
`;
|
||
|
||
const Smile = styled.div`
|
||
width: 55%;
|
||
height: 25%;
|
||
border-style: solid;
|
||
border-width: 4px;
|
||
border-top-color: transparent;
|
||
border-left-color: transparent;
|
||
border-right-color: transparent;
|
||
border-bottom-color: black;
|
||
border-radius: 100%;
|
||
position: absolute;
|
||
top: 35%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
`;
|
||
|
||
const Face = ({ show }) =>
|
||
React.createElement(
|
||
Features,
|
||
{ show: show },
|
||
React.createElement(LeftEye, null),
|
||
React.createElement(RightEye, null),
|
||
React.createElement(Smile, null)
|
||
);
|
||
|
||
const ThemeToggleInput = styled.input`
|
||
cursor: pointer;
|
||
z-index: 3;
|
||
height: 100%;
|
||
width: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
opacity: 0;
|
||
&:checked ~ div {
|
||
transform: translateX(20px);
|
||
}
|
||
`;
|
||
|
||
const ThemeToggleContainer = styled.div`
|
||
left: 10px;
|
||
position: fixed;
|
||
top: 10px;
|
||
width: 50px;
|
||
height: 30px;
|
||
border: 4px solid
|
||
${(p) => (p.theme === THEME_CONSTANTS.NIGHT ? "#fff" : "dodgerblue")};
|
||
border-radius: 30px;
|
||
transition: border-color 0.25s ease 0s;
|
||
`;
|
||
|
||
const ThemeToggleSwitch = styled.div`
|
||
height: 20px;
|
||
width: 20px;
|
||
background: ${(p) =>
|
||
p.theme === THEME_CONSTANTS.NIGHT ? $starColor : $sunColor};
|
||
border-radius: 100%;
|
||
position: absolute;
|
||
top: 50%;
|
||
margin-top: -10px;
|
||
left: 1px;
|
||
transform: translateX(0px);
|
||
transition: background 0.25s ease 0s, transform 0.25s ease 0s;
|
||
`;
|
||
|
||
const ThemeToggle = ({ onChange, checked }) =>
|
||
React.createElement(
|
||
ThemeContext.Consumer,
|
||
null,
|
||
(theme) =>
|
||
React.createElement(
|
||
ThemeToggleContainer,
|
||
{ theme: theme },
|
||
React.createElement(ThemeToggleInput, {
|
||
type: "checkbox",
|
||
onChange: onChange,
|
||
checked: checked,
|
||
title: "Toggle theme",
|
||
}),
|
||
React.createElement(ThemeToggleSwitch, { theme: theme })
|
||
)
|
||
);
|
||
|
||
const BackDrop = ({ stars }) =>
|
||
React.createElement(
|
||
ThemeContext.Consumer,
|
||
null,
|
||
(theme) =>
|
||
React.createElement(
|
||
Container,
|
||
{ theme: theme },
|
||
React.createElement(
|
||
Sun,
|
||
{ theme: theme },
|
||
React.createElement(Face, {
|
||
show: theme === THEME_CONSTANTS.DAY,
|
||
})
|
||
),
|
||
React.createElement(
|
||
Moon,
|
||
{ theme: theme },
|
||
React.createElement(Face, {
|
||
show: theme === THEME_CONSTANTS.NIGHT,
|
||
}),
|
||
React.createElement(Craters, null)
|
||
),
|
||
stars.map((star, idx) =>
|
||
React.createElement(
|
||
Star,
|
||
_extends({ key: `star--${idx}` }, star, { theme: theme })
|
||
)
|
||
)
|
||
)
|
||
);
|
||
|
||
const generateItems = (
|
||
numberOfItems = 5,
|
||
sizeLimit = 10,
|
||
animationDuration = 10
|
||
) => {
|
||
const items = [];
|
||
for (let i = 0; i < numberOfItems; i++) {
|
||
items.push({
|
||
animated: Math.random() > 0.75,
|
||
delay: Math.floor(Math.random() * animationDuration),
|
||
duration: Math.floor(Math.random() * animationDuration + 5),
|
||
size: Math.floor(Math.random() * sizeLimit + 1),
|
||
x: Math.floor(Math.random() * 100 + 1),
|
||
y: Math.floor(Math.random() * 100 + 1),
|
||
});
|
||
}
|
||
return items;
|
||
};
|
||
|
||
class App extends Component {
|
||
constructor(...args) {
|
||
super(...args);
|
||
_defineProperty(this, "state", {
|
||
theme: defaultValue,
|
||
});
|
||
_defineProperty(
|
||
this,
|
||
"toggle",
|
||
(e) => {
|
||
const { theme } = this.state;
|
||
this.setState({
|
||
theme:
|
||
theme === THEME_CONSTANTS.NIGHT
|
||
? THEME_CONSTANTS.DAY
|
||
: THEME_CONSTANTS.NIGHT,
|
||
});
|
||
}
|
||
);
|
||
}
|
||
|
||
// 修正render方法定义(原写在constructor内,不符合React规范)
|
||
render() {
|
||
const { stars } = this.props;
|
||
const { theme } = this.state;
|
||
return React.createElement(
|
||
ThemeContext.Provider,
|
||
{ value: theme },
|
||
React.createElement(BackDrop, { stars: stars }),
|
||
React.createElement(ThemeToggle, {
|
||
checked: theme === THEME_CONSTANTS.NIGHT, // 修正checked判断逻辑
|
||
onChange: this.toggle,
|
||
})
|
||
);
|
||
}
|
||
}
|
||
|
||
_defineProperty(App, "defaultProps", { stars: generateItems(20, 4) });
|
||
render(
|
||
React.createElement(App, null),
|
||
document.querySelector("#root")
|
||
);
|
||
</script>
|
||
</body>
|
||
</html>
|