Commit 4897efd5 authored by Yuanyu He's avatar Yuanyu He
Browse files

CSSPart

parents
#frozen-btn {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
button {
border: 0;
margin: 20px;
text-transform: uppercase;
font-size: 20px;
font-weight: bold;
padding: 15px 50px;
border-radius: 50px;
color: white;
outline: none;
position: relative;
}
button:before{
content: '';
display: block;
background: linear-gradient(to left, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.4) 50%);
background-size: 210% 100%;
background-position: right bottom;
height: 100%;
width: 100%;
position: absolute;
top: 0;
bottom:0;
right:0;
left: 0;
border-radius: 50px;
transition: all 1s;
-webkit-transition: all 1s;
}
.green {
background-image: linear-gradient(to right, #25aae1, #40e495);
box-shadow: 0 4px 15px 0 rgba(49, 196, 190, 0.75);
}
.purple {
background-image: linear-gradient(to right, #6253e1, #852D91);
box-shadow: 0 4px 15px 0 rgba(236, 116, 149, 0.75);
}
.purple:hover:before {
background-position: left bottom;
}
.green:hover:before {
background-position: left bottom;
}
\ No newline at end of file
2022-10-intern-training-program @ cd324a5e
Subproject commit cd324a5eff770475b5c8859baa4637d71530e944
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" type="text/css" href="./css/index.css" />
</head>
<style type="text/css">
*{
margin: 0;
padding: 0;
outline: none;
box-sizing: border-box;
}
body{
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: linear-gradient(-135deg,#c850c0,#4158d0);
}
.wrapper{
width: 450px;
background-color: #fff;
padding: 30px;
box-shadow: 0px 0px 10px rgba(0,0,0,0.1);
}
.wrapper .input-data{
width: 100%;
height: 40px;
position: relative;
}
.wrapper .input-data input{
width: 100%;
height: 100%;
border: none;
border-bottom: 2px solid silver;
font-size: 17px;
}
.input-data input:focus ~ label,
.input-data input:valid ~ label{
transform: translateY(-20px);
font-size: 15px;
color: #4158D0;
}
.wrapper .input-data label{
position: absolute;
bottom: 10px;
left: 0;
color: grey;
pointer-events: none;
transition: all 0.3s ease;
}
.wrapper .input-data .underline{
position: absolute;
bottom: 0px;
height: 2px;
width: 100%;
}
.input-data .underline:before{
position: absolute;
content: "";
height: 100%;
width: 100%;
background: #4158D0;
transform: scaleX(0);
transition:transform 0.3s ease;
}
.input-data input:focus ~ .underline:before,
.input-data input:valid ~ .underline:before{
transform: scaleX(1);
}
</style>
<body>
<div class="wrapper">
<div class="input-data">
<input type="text" required="" />
<div class="underline"></div>
<label>Name</label>
</div>
</div>
</body>
</html>
This diff is collapsed.
body {
font-family: 'STLiti';
font-size: large;
background-image: url('./plant.jpg');
background-position: center center; /* 背景图垂直、水平居中*/
background-repeat: no-repeat; /* 背景图不平铺*/
background-attachment: fixed; /* 内容大于背景,位置相对于viewpoint固定*/
background-size: cover; /* 背景图基于容器大小伸缩*/
/*
-webkit-filter: blur(5px);
-moz-filter: blur(5px);
-o-filter: blur(5px);
-ms-filter: blur(5px);
filter: blur(5px);*/
}
#btn-submit {
font-family: 'STLiti';
display: flex;
align-items: center;
justify-content: center;
margin: 15px auto;
margin-bottom: 0px;
}
button {
border: 0;
text-transform: uppercase;
font-size: 15px;
font-weight: bold;
padding: 10px 50px;
border-radius: 50px;
color: white;
outline: none;
position: relative;
background-image: linear-gradient(to right, #25aae1, #40e495);
box-shadow: 0 4px 15px 0 rgba(49, 196, 190, 0.75);
}
button::before {
content: '';
display: block;
background: linear-gradient(to left, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.4) 50%);
background-size: 210% 100%;
background-position: right bottom;
height: 100%;
width: 100%;
position: absolute;
top: 0;
bottom:0;
right:0;
left: 0;
border-radius: 50px;
transition: all 1s;
-webkit-transition: all 1s;
}
button:hover::before {
background-position: left bottom;
}
.wrapper {
width: 300px;
margin: 0 auto;
background-color: #fff;
margin-top: 30px;
margin-bottom: 10px;
padding: 15px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
/*box-shadow: 0 4px 15px 0 rgba(49, 196, 190, 0.75);*/
}
/*
.wrapper:hover {
background: #2c3e50;
transition-delay: 0ms;
}
*/
.wrapper .todo-header {
width: 100%;
height: 40px;
position: relative;
}
.wrapper .todo-header input {
outline: none;
width: 100%;
height: 100%;
border: none;
border-bottom: 2px solid silver;
font-size: 17px;
}
.todo-header input:focus ~ label,
.todo-header input:valid ~ label {
transform: translateY(-20px);
font-size: 15px;
color: #4158D0;
}
.wrapper .todo-header label {
position: absolute;
bottom: 10px;
left: 0;
color: grey;
pointer-events: none;
transition: all 0.3s ease;
}
.wrapper .todo-header .underline {
position: absolute;
bottom: -4px;
height: 2px;
width: 100%;
}
.todo-header .underline::before {
position: absolute;
content: "";
height: 100%;
width: 100%;
background: #4158D0;
transform: scaleX(0);
transition: transform 0.3s ease;
}
.todo-header input:focus ~ .underline::before,
.todo-header input:valid ~ .underline::before {
transform: scaleX(1);
}
.todo-record {
width: 540px;
height: auto;
line-height: auto;
padding-left: 20px;
padding-top: 20px;
padding-bottom: 5px;
border-radius: 10px;
/* border-left: 5px solid silver;*/
transition: all 0.2s linear 0s;
margin: 0 auto;
/* box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);*/
box-shadow: 0 4px 15px 0 rgba(49, 196, 190, 0.75);
}
/*
.todo-record:hover {
border-left: 5px solid gray;
border-radius: 0px;
background-color: white;
box-shadow: 9px 9px 12px #858585,
-9px -9px 12px #ffffff;
}*/
.todo-line {
height: 2px;
background-color: silver;
margin-top: 5px;
margin-left: -3px;
margin-right: 20px;
}
.todo-record-content {
margin-top: 5px;
}
:root {
--borderColor: gray;
}
.todo-record {
position: relative;
height: auto;
margin: auto;
border: 2px solid silver;
cursor: pointer;
background-color: rgba(0, 0, 0, 0.1);
}
.todo-record::before,::after {
content: "";
position: absolute;
width: 40px;
height: 30px;
transition: 0.3s ease-in-out;
}
.todo-record::before {
top: -5px;
left: -5px;
border-top: 2px solid var(--borderColor);
border-left: 2px solid var(--borderColor);
}
.todo-record::after {
right: -5px;
bottom: -5px;
border-bottom: 2px solid var(--borderColor);
border-right: 2px solid var(--borderColor);
}
.todo-record:hover::before,
.todo-record:hover::after {
width: calc(100% + 9px);
height: calc(100% + 9px);
}
.todo-record:hover strong {
font-size: 25px;
}
.todo-record strong {
pointer-events: none;
transition: all 0.3s ease;
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TODO List</title>
<script src="index.js" type="module"></script>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="img"></div>
<!-- shell command input part -->
<div class="wrapper">
<div class="todo-header">
<input class="todo-header-input" type="text" id="input-command" required=""></input>
<div class="underline"></div>
<label>Command</label>
</div>
<!-- this is optional: -->
<button id="btn-submit">Submit</button>
</div>
<br>
<div class="todo-app">
<!-- todo card display part -->
<div class="todo-body" id="list-todo">
<!--
<div id="todo-1" x-resolved="1">
<strong>title</strong>
<span>&nbsp;(id=1)</span>
<p>
content
</p>
<i>Remaining time: ???</i>
</div>
-->
</div>
</div>
</body>
</html>
// @ts-check
/// <reference path="./shim.d.ts" />
/// <reference path="./date-fns.d.ts" />
import { format } from "https://esm.run/date-fns";
import { differenceInDays } from "https://esm.run/date-fns";
/**
* @param {Date} from
* @param {Date} to
* @return {string}
*/
function getTimeDiffString(from, to) {
if(from > to) {
alert('Dealine has passed!');
throw new Error('from must be less than to');
}
return differenceInDays(to, from).toLocaleString();
}
/**
* @param {number} id
* @param {string} title
* @param {string} content
* @param {Date} deadline
* @param {number} resolved
*/
function addTodoToDOM(id, title, content, deadline, resolved) {
// bonus: save all todos into localStorage
let obj = { "title": title, "content": content, "deadline": deadline, "resolved": resolved }
localStorage.setItem(id.toLocaleString(), JSON.stringify(obj))
const newId = "todo-" + id;
const todoElem = document.createElement("div");
const todoBr = document.createElement("br");
const todoTitleElem = document.createElement("strong");
const todoIdElem = document.createElement("span");
const todoLine = document.createElement("div");
const todoContentElem = document.createElement("p");
const todoDeadlineTimeElem = document.createElement("p");
const todoDeadlineElem = document.createElement("i");
const todoNextElem = document.createElement("p");
todoElem.id = newId;
todoElem.className = "todo-record";
todoLine.className = "todo-line";
todoElem.setAttribute("x-resolved", resolved.toLocaleString());
if (resolved) {
todoElem.style.color = "gray";
}
todoTitleElem.id = "title" + id;
todoTitleElem.className = "todo-record-title";
todoContentElem.id = "content" + id;
todoContentElem.className = "todo-record-content";
todoDeadlineTimeElem.id = "deadline" + id;
todoDeadlineElem.id = "time" + id;
todoIdElem.textContent = " (id=" + id + ") ";
todoTitleElem.textContent = title;
todoContentElem.textContent = content;
todoDeadlineTimeElem.textContent = "Deadline: " + format(deadline, "yyyy-MM-dd");
todoDeadlineElem.textContent = "Remaining time: " + getTimeDiffString(new Date, deadline) + " days";
// todoElem.appendChild(todoBr);
todoElem.appendChild(todoNextElem);
todoElem.appendChild(todoTitleElem);
todoElem.appendChild(todoIdElem);
todoElem.appendChild(todoLine);
todoElem.appendChild(todoContentElem);
todoElem.appendChild(todoDeadlineTimeElem);
todoElem.appendChild(todoDeadlineElem);
todoElem.appendChild(todoNextElem);
const parentElem = document.getElementById("list-todo");
if (!parentElem) {
alert("Failed to get input element");
return;
}
parentElem.appendChild(todoElem);
parentElem.appendChild(todoBr);
}
/**
* @param {string} id
* @param {string} part
* @param {string} newContent
*/
function modifyTodoDOM(id, part, newContent) {
if (localStorage.hasOwnProperty(id)) {
const todo = document.getElementById(part + id);
const getVal = JSON.parse(localStorage.getItem(id) || '0');
if (!todo) {
alert('Id or element does not exist!');
return;
}
if (part === "title") {
getVal.title = newContent;
todo.textContent = newContent ;
// 错误写法:todo?.textContent -> 赋值表达式的左侧不能是可选属性访问
} else if(part === "content") {
getVal.content = newContent;
todo.textContent = newContent;
} else if(part === "deadline") {
getVal.deadline = newContent;
todo.textContent = "Deadline: " + newContent
const remain = document.getElementById("time" + id);
if (remain) {
remain.textContent = "Remaining time: " + getTimeDiffString(new Date, new Date(newContent)) + " days";
}
}
let obj = { "title": getVal.title, "content": getVal.content, "deadline": getVal.deadline, "resolved": getVal.resolved }
localStorage.setItem(id, JSON.stringify(obj))
updateOverdueStatus(id);
} else {
alert(id);
alert('Id does not exist!');
return;
}
}
/**
* @param {string} id
*/
function deleteTodoDOM(id) {
const todo = document.getElementById("todo-" + id);
localStorage.removeItem(id);
window.location.reload();
}
/**
* @param {string} id
*/
function resolveTodo(id) {
const todo = document.getElementById("todo-" + id);
if (!todo) {
return;
}
todo.setAttribute("x-resolved", "1");
todo.style.color = "gray"; // set color to gray
const getVal = JSON.parse(localStorage.getItem(id) || '0');
let obj = { "title": getVal.title, "content": getVal.content, "deadline": getVal.deadline, "resolved": 1 }
localStorage.setItem(id, JSON.stringify(obj))
}
/**
* @param {string} id
*/
function updateOverdueStatus(id) {
const todo = document.getElementById("todo-" + id);
if (!todo) {
return;
}
if (todo.getAttribute("resolved") === "1") {
return;
}
const todoDeadlineElemSet = todo.getElementsByTagName("p"); // ref: index.html example todo div
/* if (todoDeadlineElemSet.length !== 1) {
alert("Failed to get deadline element: unexpected number of <???> elements");
}*/
const todoDeadline = todoDeadlineElemSet[1].textContent; // get text content of element
if(!todoDeadline) {
return;
}
const deadline = getTimeDiffString(new Date, new Date(todoDeadline)); // use date-fns here to parse date string
if (parseInt(deadline) < 10) {
const todoTime = todo.getElementsByClassName("");
todo.style.color = "red"; // set color to red
}
}
var id = 0;
function initializeTodoApp() {
// bonus: load all saved todos from localStorage
let res = []
for (let i = 0; i < localStorage.length; i++) {
const getKey = localStorage.key(i);
if (getKey != null) {
let getVal = JSON.parse(localStorage.getItem(getKey) || '0');
// res.push(getVal); // 可能导致 reload后乱序问题???
res[parseInt(getKey) - 1] = getVal
}
}
localStorage.clear();
for (let i = 0; i < res.length; i++) {
let obj = res[i];
if (obj) {
addTodoToDOM(++id, obj.title, obj.content, new Date(obj.deadline), parseInt(obj.resolved));
updateOverdueStatus(id.toLocaleString());
}
}
const addTodoRegex = /^add(\s+)([\w\W]*)(\s+)([\w\W]*)(\s+)(\d{4}[\-\/](\d{2}|\d{1})[\-\/](\d{2}|\d{1}))$/;
const modifyTodoRegex = /^modify(\s+)(\d+)(\s+)(\w+)[(:)(=)(\s+)]([\w\W]*)$/;
const resolveTodoRegex = /^resolve(\s+)(\d+)/;
const deleteTodoRegex = /^delete(\s+)(\d+)/;
const shellInputElem = /** @type {HTMLInputElement | null} */ (document.getElementById("input-command"));
if (shellInputElem === null) {
alert("Failed to get input element");
return;
}
// set event listener
shellInputElem.addEventListener("keyup", function (ev) {
if (ev.key === "Enter") {
var inputContent = shellInputElem.value
inputContent = inputContent.replace(':', ' ');
inputContent = inputContent.replace('=', ' ');
if (addTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
addTodoToDOM(++id, str[1], str[2], new Date(str[3]), 0);
updateOverdueStatus(id.toLocaleString());
} else if (modifyTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
modifyTodoDOM(str[1], str[2], str[3]);
} else if (deleteTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
deleteTodoDOM(str[1]);
} else if (resolveTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
resolveTodo(str[1]);
} else {
alert('Invalid Command!');
}
shellInputElem.value = '';
}
})
document.getElementById("btn-submit")?.addEventListener("click", function () {
var inputContent = shellInputElem.value
inputContent = inputContent.replace(':', ' ');
inputContent = inputContent.replace('=', ' ');
if (addTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
addTodoToDOM(++id, str[1], str[2], new Date(str[3]), 0);
} else if (modifyTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
modifyTodoDOM(str[1], str[2], str[3]);
} else if (deleteTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
deleteTodoDOM(str[1]);
} else if (resolveTodoRegex.test(inputContent)) {
const str = inputContent.split(/\s+/);
resolveTodo(str[1]);
} else {
alert('Invalid Command!');
}
shellInputElem.value = '';
})
}
window.addEventListener("load", initializeTodoApp);
// add title content 2022-12-31
// modify 1 title name
\ No newline at end of file
declare module "https://esm.run/date-fns" {
export * from "date-fns";
}
From 0c4d7820bb62a30969aeb3ee293cf0ed765bee61 Mon Sep 17 00:00:00 2001
From: XieJiSS <XieJiSS@users.noreply.github.com>
Date: Sat, 14 Jan 2023 22:31:53 +0800
Subject: [PATCH] feat: skeleton part 2
---
index.css | 29 +++++++++++++++++++++++++++++
index.html | 32 +++++++++++++++++---------------
index.js | 47 ++++++++++++++++++++++++++++-------------------
3 files changed, 74 insertions(+), 34 deletions(-)
diff --git a/index.css b/index.css
index e69de29..4bee0a1 100644
--- a/index.css
+++ b/index.css
@@ -0,0 +1,29 @@
+.todo-app {
+ /* 使用 margin: auto 实现这个元素的水平居中(但内容仍然是左对齐) */
+}
+
+div.todo-header {
+
+}
+
+.todo-body {
+
+}
+
+.todo-record {
+
+}
+
+.todo-record .todo-record-title {
+
+}
+
+???
+
+.todo-record[x-resolved="1"] {
+
+}
+
+.todo-header-input {
+
+}
diff --git a/index.html b/index.html
index f24a533..65feeb3 100644
--- a/index.html
+++ b/index.html
@@ -11,22 +11,24 @@
</head>
<body>
- <!-- shell command input part -->
- <div>
- <input id="input-??????" placeholder="??????"></input>
- <!-- this is optional: -->
- <!-- <button id="btn-??????">??????</button> -->
- </div>
+ <div class="todo-app">
+ <!-- shell command input part -->
+ <div class="todo-header">
+ <input class="todo-header-input" placeholder="??????"></input>
+ <!-- this is optional: -->
+ <!-- <button id="btn-??????">??????</button> -->
+ </div>
- <!-- todo card display part -->
- <div id="list-??????">
- <div id="todo-1" x-resolved="1">
- <strong>title</strong>
- <span>&nbsp;(id=1)</span>
- <p>
- content
- </p>
- <i>Remaining time: ???</i>
+ <!-- todo card display part -->
+ <div class="todo-body" id="list-??????">
+ <div class="todo-record" id="todo-1" x-resolved="1">
+ <strong class="todo-record-title">title</strong>
+ <span ???>&nbsp;(id=1)</span>
+ <p ???>
+ content
+ </p>
+ <i ???>Remaining time: ???</i>
+ </div>
</div>
</div>
</body>
diff --git a/index.js b/index.js
index b65b172..1d1d086 100644
--- a/index.js
+++ b/index.js
@@ -34,6 +34,8 @@ function addTodoToDOM(id, title, content, deadline) {
const todoDeadlineElem = document.createElement("???");
todoElem.id = newId;
+ // NEW: (other similar usecase omitted)
+ todoElem.classList.add("???");
todoTitleElem.textContent = ???;
...
@@ -56,29 +58,32 @@ function resolveTodo(id) {
}
todo.setAttribute("x-resolved", "1");
+ // THIS SHOULD BE REMOVED:
todo.style.color = "???"; // set color to gray
}
-/**
- * @param {number} id
- */
-function updateOverdueStatus(id) {
- const todo = document.getElementById("todo-" + ???);
- if (!todo) {
- return;
- }
- if (todo.getAttribute("x-resolved") === "1") {
- return;
- }
+// THIS FUNCTION IS UPDATED:
+function updateOverdueStatus() {
+ // NEW:
+ const todoElements = document.querySelectorAll('div.???:not([???])');
+ for (???) {
+ if (!todo) {
+ continue;
+ }
+ // THIS CAN BE OMITTED
+ if (todo.getAttribute("x-resolved") === "1") {
+ continue;
+ }
- const todoDeadlineElemSet = todo.getElementsByTagName("???"); // ref: index.html example todo div
- if (todoDeadlineElemSet.length !== 1) {
- alert("Failed to get deadline element: unexpected number of <???> elements");
- }
- const todoDeadline = todoDeadlineElemSet[0].???; // get text content of element
- const deadline = ???; // use date-fns here to parse date string
- if (deadline > ???) {
- todo.style.??? = "???"; // set color to red
+ const todoDeadlineElemSet = todo.getElementsByTagName("???"); // ref: index.html example todo div
+ if (todoDeadlineElemSet.length !== 1) {
+ alert("Failed to get deadline element: unexpected number of <???> elements");
+ }
+ const todoDeadline = todoDeadlineElemSet[0].???; // get text content of element
+ const deadline = ???; // use date-fns here to parse date string
+ if (deadline > ???) {
+ todo.style.??? = "???"; // set color to red
+ }
}
}
@@ -92,7 +97,11 @@ function initializeTodoApp() {
const deleteTodoRegex = ???;
+ // THIS SHOULD BE REMOVED:
const shellInputElem = /** @type {HTMLInputElement | null} */ (document.getElementById("???"));
+ // NEW:
+ const shellInputElem = /** @type {HTMLInputElement | null} */ (document.querySelector("???"));
+
if (shellInputElem === null) {
alert("Failed to get input element");
return;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment