Revamp into todo list

I never really ended up finding a use for this before,
now I want a shared grocerly list and Google ToDo is BS and doesn't support sharing so... I did it myself
main
Pk11 1 year ago
parent d1369305f3
commit f5c9723f78

@ -1,22 +1,20 @@
# count.ピケ.コム # list.ピケ.コム
シンプルなアイテム数トラッカーページです。 シンプルなTo-Doリスト
## ホスト ## ホスト
1. これをインストール: 1. これをインストール:
- PHP (7.3.31を使う) - PHP (7.3.31を使う)
- PostgreSQL (11.14を使う) - PostgreSQL (11.14を使う)
2. このリポジトリをクローン、`git clone https://git.xn--rck9c.xn--tckwe/pk11/count.git` 2. このリポジトリをクローン、`git clone https://git.xn--rck9c.xn--tckwe/pk11/list.git`
3. `vars.php.example`を`vars.php`にコピー 3. `vars.php.example`を`vars.php`にコピー
4. `vars.php`を返照 4. `vars.php`を返照
5. 以下のテーブルを指定のデータベースに作成: 5. 以下のテーブルを指定のデータベースに作成:
```sql ```sql
CREATE TABLE items ( CREATE TABLE items (
item_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, item_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
priority INT, priority INT DEFAULT 0,
count INT, done BOOL DEFAULT FALSE,
dec_amount INT,
inc_amount INT,
description VARCHAR(2048), description VARCHAR(2048),
key VARCHAR(64) key VARCHAR(64)
); );

@ -0,0 +1,145 @@
* { box-sizing: border-box; }
@keyframes rainbow {
from { backdrop-filter: hue-rotate(0deg); -webkit-backdrop-filter: hue-rotate(0deg); }
to { backdrop-filter: hue-rotate(360deg); -webkit-backdrop-filter: hue-rotate(360deg); }
}
body {
background-color: #ebc;
background: url(/assets/images/bg.gif);
background-attachment: fixed;
min-height: 100vh;
color: #201;
margin: 0;
padding: 1px 0.5rem 1rem 0.5rem;
animation: 10s linear 0 rainbow;
animation-iteration-count: infinite;
}
header {
margin-bottom: 1rem;
}
kbd {
background: #fde;
border: 2px outset #fde;
padding: 0 2px;
}
form {
margin-bottom: 0.25rem;
}
hr {
border-top: 1px solid #c99;
border-bottom: 0;
margin: 0.5rem 2rem;
}
h1, h2, h3 {
margin-bottom: 0;
}
h1:first-child, h2:first-child, h3:first-child {
margin-top: 0;
}
h2 > small, h3 > small {
font-size: 16px;
}
input:not(:last-child),
button:not(:last-child),
label:not(:last-child) {
margin-right: 0.25rem;
}
input, button {
color: black;
border: 2px outset #fde;
background-color: #fde;
}
input:not(:disabled):active, button:not(:disabled):active,
input[type=text], input:not([type]), input[type=number] {
border-style: inset;
}
input:disabled, button:disabled {
opacity: 50%;
}
.container {
max-width: 640px;
}
.center {
margin-left: auto;
margin-right: auto;
display: block;
}
.block {
background-color: #fcd;
border: 5px outset #dab;
margin-bottom: 10px;
padding: 0 5px;
}
footer {
background-color: #ebc;
border: 5px inset #dab;
padding: 10px;
}
footer p:first-of-type {
margin-top: 0;
}
footer p:last-of-type {
margin-bottom: 0;
}
img.btn {
margin: 0 2px;
}
.fl {
float: left;
}
.list-unstyled {
list-style: none;
padding: 0;
margin: 0;
}
.alert {
border: 3px inset #fde;
margin: 1rem;
padding: 0 0.25rem;
}
.bg-green {
background-color: #cfc;
border-color: #dfd;
}
.bg-blue {
background-color: #ccf;
border-color: #ddf;
}
.bg-red {
background-color: #faa;
border-color: #fbb;
}
.width-90 { width: 90% }
.d-flex { display: flex }
.flex-fill { flex: 1 1 auto !important }
.text-left { text-align: left }
.mb-1 { margin-bottom: 0.25rem }
.mb-2 { margin-bottom: 0.5rem }
.mb-3 { margin-bottom: 1rem }

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 B

@ -33,10 +33,8 @@
* *
* CREATE TABLE items ( * CREATE TABLE items (
* item_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, * item_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
* priority INT, * priority INT DEFAULT 0,
* count INT, * done BOOL DEFAULT FALSE,
* dec_amount INT,
* inc_amount INT,
* description VARCHAR(2048), * description VARCHAR(2048),
* key VARCHAR(64) * key VARCHAR(64)
* ); * );
@ -55,34 +53,19 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>アイテム数トラッカー</title> <title>To-Doリスト</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous"> <link rel="stylesheet" href="/assets/css/style.css">
<style> <meta name="theme-color" content="#facade">
main {
max-width: 768px;
margin-bottom: 5rem;
}
h2 {
border-bottom: 1px solid lightgray;
}
.red {
color: red;
}
</style>
</head> </head>
<body> <body>
<?php <?php
// formの変数 // formの変数
$itemMenu = isset($_GET['item-add']) || isset($_POST['item-edit']);
$itemEdit = $_POST['item-edit']; $itemEdit = $_POST['item-edit'];
$itemInc = $_POST['item-inc']; $itemDone = $_POST['item-done'];
$itemDec = $_POST['item-dec'];
$itemRemove = $_POST['item-remove']; $itemRemove = $_POST['item-remove'];
$keyMenu = isset($_GET['key-menu']); $keyMenu = isset($_GET['key-menu']);
$keySet = $_POST['key-set']; $keySet = $_REQUEST['key-set'];
$setDescription = $_POST['set-description']; $setDescription = $_POST['set-description'];
// cookieの変数 // cookieの変数
@ -104,20 +87,15 @@
} }
?> ?>
<header> <header class="center container">
<nav class="navbar navbar-expand-sm navbar-light bg-light"> <h1>To-Doリスト</h1>
<div class="container-fluid"> [<a href="<?php echo $_SERVER['PHP_SELF']; ?>">home</a>]
<a class="navbar-brand" href="<?php echo $_SERVER['PHP_SELF']; ?>">アイテム数トラッカー</a> [<a href="?key-menu">key</a>]
<ul class="navbar-nav"> [<a href="?source">source</a>]
<li class="nav-item"><a class="nav-link" href="?item-add">追加</a></li> [<a href="//xn--rck9c.xn--tckwe">back</a>]
<li class="nav-item"><a class="nav-link" href="?key-menu"><?php echo empty($key) ? 'キー' : ($shortKey . 'さん'); ?></a></li>
<li class="nav-item"><a class="nav-link" href="?source">ソース</a></li>
</ul>
</div>
</nav>
</header> </header>
<main class="mt-3 container-fluid"> <main class="center container block">
<?php <?php
date_default_timezone_set('America/Chicago'); date_default_timezone_set('America/Chicago');
@ -126,57 +104,37 @@
or die('Could not connect: ' . pg_last_error()); or die('Could not connect: ' . pg_last_error());
if($itemMenu) { // アイテムを追加 if(isset($itemEdit)) { // アイテムの編集
if($itemEdit) { $query = 'SELECT item_id, description, priority FROM items WHERE items.key=$1 AND item_id=$2 LIMIT 1';
$query = 'SELECT item_id, count, dec_amount, inc_amount, description, priority FROM items WHERE items.key=$1 AND item_id=$2 LIMIT 1'; $res = pg_query_params($query, [$key, $itemEdit]) or die('Query failed: ' . pg_last_error());
$res = pg_query_params($query, [$key, $itemEdit]) or die('Query failed: ' . pg_last_error()); $row = pg_fetch_array($res);
$row = pg_fetch_array($res);
}
echo '<h2>アイテムの' . ($itemEdit ? '編集' : '追加') . '</h2>'; echo '<h2>アイテムの編集<small>/edit item</small></h2>';
echo '<form method="post" action="' . $_SERVER['PHP_SELF'] . '">'; echo '<form method="post" action="' . $_SERVER['PHP_SELF'] . '">';
echo '<div class="input-group mb-3">'; echo '<div class="mb-3 d-flex">';
echo '<label for="set-description" class="input-group-text">説明</label>'; echo '<label for="set-description"><ruby>説明<rp> (</rp><rt>description</rt><rp>)</rp></ruby></label>';
echo '<input id="set-description" name="set-description" class="form-control" value="' . $row['description'] . '" required>'; echo '<input id="set-description" name="set-description" class="flex-fill" value="' . $row['description'] . '" required>';
echo '</div>'; echo '</div>';
echo '<div class="input-group mb-3">'; echo '<div class="mb-3 d-flex">';
echo '<label for="set-count" class="input-group-text">アイテム数</label>'; echo '<label for="set-priority"><ruby>優先<rp> (</rp><rt>priority</rt><rp>)</rp></ruby></label>';
echo '<input type="number" id="set-count" name="set-count" class="form-control" value="' . ($row['count'] ?? 0) . '">'; echo '<input type="number" id="set-priority" name="set-priority" class="flex-fill" value="' . ($row['priority'] ?? 0) . '">';
echo '</div>';
echo '<div class="input-group mb-3">';
echo '<label for="set-inc" class="input-group-text">増加量</label>';
echo '<input type="number" id="set-inc" name="set-inc" class="form-control" value="' . ($row['inc_amount'] ?? 1) . '">';
echo '</div>';
echo '<div class="input-group mb-3">';
echo '<label for="set-dec" class="input-group-text">減少量</label>';
echo '<input type="number" id="set-dec" name="set-dec" class="form-control" value="' . ($row['dec_amount'] ?? 1) . '">';
echo '</div>';
echo '<div class="input-group mb-3">';
echo '<label for="set-priority" class="input-group-text">優先</label>';
echo '<input type="number" id="set-priority" name="set-priority" class="form-control" value="' . ($row['priority'] ?? 0) . '">';
echo '</div>'; echo '</div>';
echo '<input type="hidden" name="item-id" value="' . $row['item_id'] . '">'; echo '<input type="hidden" name="item-id" value="' . $row['item_id'] . '">';
echo '<input type="submit" class="btn btn-outline-secondary me-2" value="' . ($itemEdit ? '設定' : '追加') . '">'; echo '<input type="submit" class="bg-green" value="設定">';
if($itemEdit) echo '<button type="submit" class="bg-red" name="item-remove" value="' . $itemEdit . '">削除</button>';
echo '<button type="submit" class="btn btn-outline-danger" name="item-remove" value="' . $itemEdit . '">削除</button>';
echo '</form>'; echo '</form>';
} else if($keyMenu) { //キーを設定 } else if($keyMenu) { //キーを設定
echo '<h2>キーの設定</h2>'; echo '<h2>キーの設定<small>/set key</small></h2>';
echo '<form method="post" action="' . $_SERVER['PHP_SELF'] . '">'; echo '<form method="post" action="' . $_SERVER['PHP_SELF'] . '">';
echo '<div class="input-group mb-3">'; echo '<label for="key-set"><ruby>キー<rp> (</rp><rt>key</rt><rp>)</rp></ruby></label>';
echo '<label for="key-set" class="input-group-text">キー</label>'; echo '<input id="key-set" name="key-set" value="' . $_COOKIE['key'] . '">';
echo '<input type="password" id="key-set" name="key-set" class="form-control" value="' . $_COOKIE['key'] . '">'; echo '<input type="submit" value="設定" class="bg-green">';
echo '<input type="submit" class="btn btn-outline-secondary" value="設定">';
echo '</div>';
echo '</form>'; echo '</form>';
echo '<p>アプリを使用するには、キーを設定する必要があります。キーを持つ誰でもあなたのアイテムを見ることができますので、秘密にしておきましょう。</p>'; echo '<p>アプリを使用するには、キーを設定する必要がありま一覧を見ることができますので、秘密にしておきましょう。</p>';
} else { // HPを表示 } else { // HPを表示
if(!empty($key)) { if(!empty($key)) {
if(isset($itemRemove)) { // アイテムを削除 if(isset($itemRemove)) { // アイテムを削除
@ -187,47 +145,30 @@
$desc = $row['description']; $desc = $row['description'];
$query = 'DELETE FROM items WHERE item_id=$1'; $query = 'DELETE FROM items WHERE item_id=$1';
pg_query_params($query, [$itemRemove]); pg_query_params($query, [$itemRemove]);
echo "<div class=\"alert alert-danger\">{$desc}は削除しました。</div>"; echo "<div class=\"alert bg-red\">{$desc}は削除しました。</div>";
} else {
echo "<div class=\"alert alert-warning\">アイテムはありません。</div>";
}
} else if(isset($itemInc)) { // アイテムを増加する
$query = 'SELECT description, inc_amount, count FROM items WHERE items.key=$1 AND item_id=$2';
$res = pg_query_params($query, [$key, $itemInc]) or die('Query failed: ' . pg_last_error());
$row = pg_fetch_array($res);
if($row) {
$desc = $row['description'];
$count = $row['count'] + $row['inc_amount'];
$query = 'UPDATE items SET count=$1 WHERE item_id=$2';
pg_query_params($query, [$count, $itemInc]) or die('Query failed: ' . pg_last_error());
echo "<div class=\"alert alert-success\">{$desc}は{$count}に増加しました。</div>";
} else { } else {
echo "<div class=\"alert alert-warning\">アイテムはありません。</div>"; echo "<div class=\"alert bg-blue\">アイテムはありません。</div>";
} }
} else if(isset($itemDec)) { // アイテムを減少する } else if(isset($itemDone)) { // アイテム完了
$query = 'SELECT description, dec_amount, count FROM items WHERE items.key=$1 AND item_id=$2'; $query = 'SELECT description, done FROM items WHERE items.key=$1 AND item_id=$2';
$res = pg_query_params($query, [$key, $itemDec]) or die('Query failed: ' . pg_last_error()); $res = pg_query_params($query, [$key, $itemDone]) or die('Query failed: ' . pg_last_error());
$row = pg_fetch_array($res); $row = pg_fetch_array($res);
if($row) { if($row) {
$desc = $row['description']; $desc = $row['description'];
$count = $row['count'] - $row['dec_amount']; $query = 'UPDATE items SET done = NOT done WHERE item_id=$1';
$query = 'UPDATE items SET count=$1 WHERE item_id=$2'; pg_query_params($query, [$itemDone]) or die('Query failed: ' . pg_last_error());
pg_query_params($query, [$count, $itemDec]) or die('Query failed: ' . pg_last_error()); $doneText = $row['done'] == 'f' ? '完了しました' : '完了にしませんでした';
echo "<div class=\"alert alert-success\">{$desc}は{$count}に減少しました</div>"; echo "<div class=\"alert bg-green\">{$desc}が{$doneText}。</div>";
} else { } else {
echo "<div class=\"alert alert-warning\">アイテムはありません。</div>"; echo "<div class=\"alert bg-red\">アイテムはありません。</div>";
} }
} else if(isset($keySet)) { } else if(isset($keySet)) {
if(!empty($keySet)) { if(!empty($keySet)) {
echo "<div class=\"alert alert-info\">ようこそ、{$shortKey}さん。</div>"; echo "<div class=\"alert bg-blue\">リスト{$shortKey}に変更しました。</div>";
} else {
echo "<div class=\"alert alert-info\">さようなら、{$shortKey}さん。</div>";
} }
} else if(isset($setDescription)) { // アイテムを編集・追加する } else if(isset($setDescription)) { // アイテムを編集・追加する
$itemId = $_POST['item-id']; $itemId = $_POST['item-id'];
$setCount = $_POST['set-count'];
$setInc = $_POST['set-inc'];
$setDec = $_POST['set-dec'];
$setPriority = $_POST['set-priority']; $setPriority = $_POST['set-priority'];
if($itemId) { if($itemId) {
@ -235,24 +176,24 @@
$res = pg_query_params($query, [$key, $itemId]) or die('Query failed: ' . pg_last_error()); $res = pg_query_params($query, [$key, $itemId]) or die('Query failed: ' . pg_last_error());
} }
if(pg_num_rows($res) == 0) { if(!$res || pg_num_rows($res) == 0) {
$query = 'INSERT INTO items (priority, count, dec_amount, inc_amount, description, key) VALUES ($1, $2, $3, $4, $5, $6)'; $query = 'INSERT INTO items (description, key) VALUES ($1, $2)';
pg_query_params($query, [$setPriority, $setCount, $setDec, $setInc, $setDescription, $key]); pg_query_params($query, [$setDescription, $key]);
echo "<div class=\"alert alert-success\">{$setDescription}は追加しました。</div>"; echo "<div class=\"alert bg-green\">{$setDescription}は追加しました。</div>";
} else { } else {
$query = 'UPDATE items SET priority=$1, count=$2, dec_amount=$3, inc_amount=$4, description=$5 WHERE items.key=$6 AND item_id=$7'; $query = 'UPDATE items SET priority=$1, description=$2 WHERE items.key=$3 AND item_id=$4';
pg_query_params($query, [$setPriority, $setCount, $setDec, $setInc, $setDescription, $key, $itemId]); pg_query_params($query, [$setPriority, $setDescription, $key, $itemId]);
echo "<div class=\"alert alert-success\">{$setDescription}は更新しました。</div>"; echo "<div class=\"alert bg-green\">{$setDescription}は更新しました。</div>";
} }
} }
// アイテム一覧 // アイテム一覧
$query = 'SELECT item_id, count, description, priority FROM items WHERE items.key=$1 ORDER BY items.priority DESC, items.description ASC'; $query = 'SELECT item_id, description, priority FROM items WHERE items.key=$1 AND done=FALSE ORDER BY items.priority DESC, items.description ASC';
$res = pg_query_params($query, [$key]) or die('Query failed: ' . pg_last_error()); $res = pg_query_params($query, [$key]) or die('Query failed: ' . pg_last_error());
echo '<h2>アイテム一覧</h2>'; echo '<h2>アイテム一覧<small>/item list</small></h2>';
if(pg_num_rows($res) > 0) { if(pg_num_rows($res) > 0) {
echo '<form action="' . $_SERVER['PHP_SELF'] . '">'; echo '<form method="post" action="' . $_SERVER['PHP_SELF'] . '">';
echo '<ul class="list-unstyled">'; echo '<ul class="list-unstyled">';
$priority = -1; $priority = -1;
while($row = pg_fetch_array($res)) { while($row = pg_fetch_array($res)) {
@ -261,16 +202,50 @@
$priority = $row['priority']; $priority = $row['priority'];
echo '<li class="mb-1 d-flex">'; echo '<li class="mb-1 d-flex">';
echo '<button type="submit" formmethod="post" name="item-edit" value="' . $row['item_id'] . '" class="btn btn-sm btn-secondary flex-fill me-1 text-start">' . $row['description'] . ' ー ' . $row['count'] . '</button>'; echo '<button type="submit" name="item-done" value="' . $row['item_id'] . '" class="bg-green"></button>';
echo '<button type="submit" formmethod="post" name="item-inc" value="' . $row['item_id'] . '" title="' . $row['description'] . 'の増加する" aria-label="' . $row['description'] . 'の増加する" class="btn btn-sm btn-outline-secondary me-1"></button>'; echo '<button type="submit" name="item-edit" value="' . $row['item_id'] . '" class="text-left flex-fill">' . $row['description'] . '</button>';
echo '<button type="submit" formmethod="post" name="item-dec" value="' . $row['item_id'] . '" title="' . $row['description'] . 'の減少する" aria-label="' . $row['description'] . 'の減少する" class="btn btn-sm btn-outline-secondary me-1"></button>'; echo '<button type="submit" name="item-remove" value="' . $row['item_id'] . '" class="bg-red">×</button>';
echo '</li>'; echo '</li>';
} }
echo '</ul>'; echo '</ul>';
echo '</form>'; echo '</form>';
} }
// 追加ボタン
echo '<form method="post" action="' . $_SERVER['PHP_SELF'] . '" class="d-flex">';
echo '<button type="submit" name="item-done" class="bg-green" disabled></button>';
echo '<input name="set-description" class="flex-fill" placeholder="新しい" required>';
echo '<input type="submit" value="+" class="bg-green">';
echo '</form>';
// 完了一覧
$query = 'SELECT item_id, description FROM items WHERE items.key=$1 AND done=TRUE ORDER BY items.description ASC';
$res = pg_query_params($query, [$key]) or die('Query failed: ' . pg_last_error());
echo '<h3>完了されたアイテム<small>/completed items</small></h3>';
if(pg_num_rows($res) > 0) {
echo '<form method="post" action="' . $_SERVER['PHP_SELF'] . '">';
echo '<ul class="list-unstyled">';
$priority = -1;
while($row = pg_fetch_array($res)) {
if($priority != $row['priority'] && $priority != -1)
echo '<hr>';
$priority = $row['priority'];
echo '<li class="mb-1 d-flex">';
echo '<button type="submit" name="item-done" value="' . $row['item_id'] . '"></button>';
echo '<button type="submit" name="item-edit" value="' . $row['item_id'] . '" class="text-left flex-fill">' . $row['description'] . '</button>';
echo '<button type="submit" name="item-remove" value="' . $row['item_id'] . '" class="bg-red">×</button>';
echo '</li>';
}
echo '</ul>';
echo '</form>';
}
} else { } else {
echo '<div class="alert alert-info"><a href="?key-menu">キーを設定してください。</a></div>'; echo '<div class="alert bg-blue"><a href="?key-menu">キーを設定してください。</a></div>';
} }
} }

Loading…
Cancel
Save