洗い出し:https://halved-coelurus-ca1.notion.site/26251c6c78d5809b983cea7181dadcde?source=copy_link
https://www.notion.so/2-25c51c6c78d580848361cc4f4d0da7e7?source=copy_link
aaaaa
<!DOCTYPE html>
<html xmlns:th="<http://www.thymeleaf.org>">
<head>
<meta charset="UTF-8">
<title>動物検索</title>
<link rel="stylesheet" href="main-style.css" type="text/css">
</head>
<body>
<div class="container add-control">
<input type="radio" id="tab1" class="radio" name="tab" checked="checked"><label class="tab-title title1"
for="tab1">未回答</label>
<input type="radio" id="tab2" class="radio" name="tab"><label class="tab-title title2" for="tab2">作成物</label>
<input type="radio" id="tab3" class="radio" name="tab"><label class="tab-title title3" for="tab3">tab3</label>
<div class="tab-body">
<div class="body1">
<!-- <h1>未回答のアンケート</h1> -->
<ul class="card-display">
<li ><a href=""><div class=image-wrapper ><img src="image.png" alt="ユニバ" > <div class="text-overlay">未回答のアンケート</div></div></a></li>
<li ><a href=""><div class=image-wrapper ><img src="image.png" alt="ユニバ" > <div class="text-overlay">未回答のアンケート</div></div></a></li>
<li ><a href=""><div class=image-wrapper ><img src="image.png" alt="ユニバ" > <div class="text-overlay">未回答のアンケート</div></div></a></li>
<li ><a href=""><div class=image-wrapper ><img src="image.png" alt="ユニバ" > <div class="text-overlay">未回答のアンケート</div></div></a></li>
<li ><a href=""><div class=image-wrapper ><img src="image.png" alt="ユニバ" > <div class="text-overlay">未回答のアンケート</div></div></a></li>
<li ><a href=""><div class=image-wrapper ><img src="image.png" alt="ユニバ" > <div class="text-overlay">未回答のアンケート</div></div></a></li>
<!-- <li class="card-display2"><a href="" >未回答のアンケート</a></li> -->
<!-- <a href="" class="card-display">未回答のアンケート</a> -->
</ul>
</div>
<div class="body2">
<h1>虫を検索</h1>
<form method="get" action="/search">
<input type="text" name="keyword" placeholder="動物名" th:value="${keyword}">
<button type="submit">検索</button>
</form>
<div th:if="${animals}">
<h2>検索結果:</h2>
<ul>
<li th:each="animal : ${animals}" th:text="${animal.name + '(' + animal.type + ')'}"></li>
</ul>
</div>
</div>
<div class="body3">body3 body3 body3</div>
</div>
</div>
</body>
</html>
/* .title1,
.body1 {
border: 2px solid rgb(135, 136, 138);
}
.title2,
.body2 {
border: 2px solid rgb(135, 136, 138);
}
.title3,
.body3 {
border: 2px solid rgb(135, 136, 138);
} */
.tab-title {
/* border-bottom: 2rem; */
padding: .3em .5em;
/* border-radius: .3em .3em 0 0; */
/* text-align: center; */
font-size: 2rem;
/* display: table; */
display: flex;
/* width: 100%; */
/* background-color: #f3f3f3; */
}
.tab-body>div {
width: 100%;
height: 200px;
border-radius: 0 .3em .3em .3em;
padding: 1em;
}
/* radio non-display */
.container .radio {
display: none;
gap: 10px;
}
/* tabs position */
.container {
display: flex;
flex-wrap: wrap;
position: relative;
}
.container::after {
content: "";
width: 90%;
}
.container .tab-title {
position: relative;
border-bottom: 2px solid transparent;
top: 2px;
left: 2px;
}
.container .tab-title:hover {
cursor: pointer;
}
.container .tab-body {
order: 1;
width: 100%;
}
/* tab's body init */
.add-control .tab-body>div {
display: none;
}
/* selected tab's color change */
.add-control .radio:checked+.tab-title {
color: #4603fd;
border-bottom-color: #4603fd;
}
.add-control #tab1:checked~.title1 {
/* background: rgb(135, 136, 138); */
}
.add-control #tab2:checked~.title2 {
/* background: rgb(135, 136, 138); */
}
.add-control #tab3:checked~.title3 {
/* background: rgb(135, 136, 138); */
}
/* tabs control */
.add-control #tab1:checked~.tab-body>.body1 {
display: flex;
}
.add-control #tab2:checked~.tab-body>.body2 {
display: block;
}
.add-control #tab3:checked~.tab-body>.body3 {
display: block;
}
.card-display {
display: flex;
gap: 20px;
flex-wrap: wrap;
list-style: none;
/* padding-left: 0; */
/* width:fit-content;
height:fit-content;
gap: 10px;
padding: 3rem 1rem 3rem 1rem;
border-radius: 5px;
background-color: aliceblue; */
}
.card-display2 {
display: flex;
min-width: fit-content;
min-height: fit-content;
gap: 10px;
padding: 3rem 1rem 3rem 1rem;
border-radius: 5px;
background-color: aliceblue;
margin: 1rem;
}
.text-overlay {
position: absolute;
bottom: 0px;
/* 下に配置。topにすれば上に表示 */
left: 0px;
right: 0px;
color: rgb(27, 27, 27);
background-color: rgba(252, 252, 252, 0.6);
/* 半透明背景で文字を読みやすく */
padding: 10% ;
font-size: 1.2rem;
border-radius: 7px 7px 0 0;
}
.image-wrapper {
position: relative;
display: flex;
min-width: 100%;
}
.image-wrapper img {
min-width: 100%;
display: block;
}
import React from "react";
import "./button.css";
function BaseButton ({ label, onClick, className }) {
return (
<button className={className}
onClick={onClick}
>
{label}
</button>
);
};
export default BaseButton;
//functionとconstの書き方の違いはこれだけ
// const BaseButton = ({ label, onClick, className }) => {
// return (
// <button className={className}
// onClick={onClick}
// >
// {label}
// </button>
// );
// };
// export default BaseButton;
.base-button {
margin:1rem;
background-color:aqua;
border-radius: 10px;
border:none;
}
.base-button::after{
content: 'してね?';
color: red;
}
.base-button:hover{
background-color: antiquewhite;
}
.reverse-button {
margin:1rem;
background-color:rgb(0, 255, 115);
border-radius: 10px;
border:none;
}
.reverse-button::after{
content: 'してね?';
color: rgb(255, 0, 179);
}
.reverse-button:hover{
background-color: rgb(230, 133, 8);
}
<div>
<h1>Reactボタンコンポーネントの例</h1>
<BaseButton label="クリックしてね" onClick={handleClick} className="reverse-button"/>
</div>
import { useState } from 'react';
import { QRCodeSVG } from 'qrcode.react';
const QRCodeGenerator = () => {
const [url, setUrl] = useState('<https://www.dentsusoken.com/>');
return (
<div>
<h1>QRコード生成</h1>
<input
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="URLを入力してください"
/>
<QRCodeSVG value={url} size={130} />
</div>
);
};
export default QRCodeGenerator;
import "./styles.css";
import React, { useState } from 'react'; // 吹き出し用のCSSをここに記述
const Copy = () => {
const [showFukidashi, setShowFukidashi] = useState(false);
const copyText = 'このテキストをクリップボードにコピー';
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(copyText);
setShowFukidashi(true);
// 2秒後に吹き出しを非表示
setTimeout(() => {
setShowFukidashi(false);
}, 2000);
} catch (err) {
console.error('コピーに失敗しました:', err);
}
};
return (
<div className="copy-box">
<div className="copy-txt">{copyText}</div>
<button
className={`copy-btn ${showFukidashi ? '-add-fukidashi' : ''}`}
onClick={handleCopy}
>
コピー
</button>
</div>
);
};
export default Copy;
.progress-container {
width: 100%;
height: 30px;
position: relative;
background-color: #eee;
border-radius: 15px;
overflow: hidden;
}
.progress-track {
width: 100%;
height: 100%;
position: relative;
background-color: #ddd;
border-radius: 15px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: #4caf50;
position: relative;
display: flex;
align-items: center;
justify-content: flex-end;
transition: width 0.3s ease-in-out;
}
/* .progress-icon {
position: absolute;
right: -15px;
top: 50%;
transform: translateY(-50%);
font-size: 20px;
} */
.progress-img {
position: absolute;
right: -15px; /* 進捗バーの先頭から少し外に出す */
top: 50%;
transform: translateY(-50%);
height: 24px; /* 画像サイズ調整 */
width: 24px;
object-fit: contain;
}
import React from "react";
import "./styles.css"; // スタイルは別ファイルで管理
const ProgressBar = ({ progress }) => {
return (
<div className="progress-container">
<div className="progress-track">
<div
className="progress-fill"
style={{ width: `${progress}%` }}
>
{/* <div className="progress-icon">🌟</div> */}
<img src={"./iz.jpeg"} alt="progress icon" className="progress-img" />
</div>
</div>
</div>
);
};
export default ProgressBar;
.copy-box {
position: relative;
display: inline-block;
}
.copy-btn {
padding: 8px 16px;
cursor: pointer;
}
/* 吹き出し用のスタイル */
.copy-btn.-add-fukidashi::after {
content: 'コピーしました!';
position: absolute;
top: -30px;
left: 50%;
transform: translateX(-50%);
background: #333;
color: #fff;
padding: 6px 10px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
}
qr-wrapper {
position: relative;
width: 200px;
height: 200px;
}
.qrcode {
width: 100%;
height: 100%;
display: block;
}
.qrcode-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px; /* アイコンサイズ調整 */
height: 40px;
border-radius: 8px;
background-color: white; /* 目立たせたい場合に追加可能 */
box-shadow: 0 0 6px rgba(0, 0, 0, 0.2); /* 立体感の追加例 */
}
<div className="qr-wrapper">
<QRCodeSVG value={url} className="qrcode"/>
<img src={"./iz.jpeg"} alt="progress icon" className="qrcode-icon" />
</div>
.progress-img {
position: absolute;
right: -15px; /* 進捗バーの先頭から少し外に出す */
top: 50%;
transform: translateY(-50%);
height: 24px; /* 画像サイズ調整 */
width: 24px;
object-fit: contain;
animation: shake 0.5s infinite;
}
@keyframes shake {
0% { transform: translateX(0); }
25% { transform: translateX(-5px); }
50% { transform: translateX(5px); }
75% { transform: translateX(-5px); }
100% { transform: translateX(0); }
}
reactメモ
SWRの読み込み表示処理の際、useStateを使うことが多いがなぜ
SWRの読み込み表示処理でuseStateを使うことが多い理由は以下のようなものがあります:
SWRはデータフェッチングに特化しているため、ローディング状態やエラー状態などのUIの表示を制御するためにuseStateが必要になることがあります。SWRは{data, error, isLoading}などの状態を返しますが、追加のUI状態管理にはuseStateが便利です。