Merge branch 'add-custom-wish' into develop

This commit is contained in:
grandeljay 2022-02-27 02:55:33 +01:00
commit 786b1adbd6
12 changed files with 349 additions and 332 deletions

View file

@ -1,30 +0,0 @@
<?php
/**
* Generate cache for wish
*
* @author Jay Trees <github.jay@grandel.anonaddy.me>
*/
use wishthis\EmbedCache;
$api = true;
$response = array(
'success' => false,
);
require '../../index.php';
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
$cache = new EmbedCache($_GET['wish_url']);
$info = $cache->get(true);
$response['success'] = true;
$response['data'] = $info;
break;
}
header('Content-type: application/json; charset=utf-8');
echo json_encode($response);
die();

View file

@ -6,7 +6,7 @@
* @author Jay Trees <github.jay@grandel.anonaddy.me> * @author Jay Trees <github.jay@grandel.anonaddy.me>
*/ */
use wishthis\User; use wishthis\{User, Wish, EmbedCache};
$api = true; $api = true;
$response = array( $response = array(
@ -16,6 +16,31 @@ $response = array(
require '../../index.php'; require '../../index.php';
switch ($_SERVER['REQUEST_METHOD']) { switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
if (isset($_GET['wish_id'], $_GET['wishlist_user'])) {
$columns = $database
->query('SELECT *
FROM `wishes`
WHERE `id` = ' . $_GET['wish_id'] . ';')
->fetch();
$wish = new wish($columns);
$response = array(
'info' => $wish,
'html' => $wish->getCard($_GET['wishlist_user'], true)
);
} elseif (isset($_GET['wish_url'])) {
$cache = new EmbedCache($_GET['wish_url']);
$info = $cache->get(true);
$exists = $cache->exists() ? 'true' : 'false';
$response = array(
'info' => $info
);
}
break;
case 'POST': case 'POST':
if (isset($_POST['wishlist_id'], $_POST['wish_url'])) { if (isset($_POST['wishlist_id'], $_POST['wish_url'])) {
/** /**
@ -24,9 +49,13 @@ switch ($_SERVER['REQUEST_METHOD']) {
$database->query('INSERT INTO `wishes` $database->query('INSERT INTO `wishes`
( (
`wishlist`, `wishlist`,
`title`,
`description`,
`url` `url`
) VALUES (' ) VALUES ('
. $_POST['wishlist_id'] . ', . $_POST['wishlist_id'] . ',
"' . $_POST['wish_title'] . '",
"' . $_POST['wish_description'] . '",
"' . $_POST['wish_url'] . '" "' . $_POST['wish_url'] . '"
) )
;'); ;');

View file

@ -144,17 +144,19 @@ img {
max-height: calc(2 * 1.28571429em); max-height: calc(2 * 1.28571429em);
overflow: hidden; overflow: hidden;
} }
.ui.card > .content > .description { .ui.card > .content > .description {
max-height: calc(3em * var(--lineHeight)); max-height: calc(3em * var(--lineHeight));
overflow: hidden; overflow: hidden;
} }
@media (hover: hover) { @media (hover: hover) {
.ui.card > .content:not(.extra) {
margin-bottom: calc(3em * var(--lineHeight));
}
.ui.card > .content > .description { .ui.card > .content > .description {
position: absolute; position: absolute;
left: 1em; left: 1em;
right: 1em; right: 1em;
max-height: calc(3em * var(--lineHeight));
} }
} }

View file

@ -20,8 +20,8 @@ $(function() {
$.fn.api.settings.api = { $.fn.api.settings.api = {
'get wishlists' : '/src/api/wishlists.php', 'get wishlists' : '/src/api/wishlists.php',
'delete wishlist' : '/src/api/wishlists.php', 'delete wishlist' : '/src/api/wishlists.php',
'update wish status': '/src/api/wishes.php', 'update wish status' : '/src/api/wishes.php',
'delete wish' : '/src/api/wishes.php', 'delete wish' : '/src/api/wishes.php',
}; };
/** Default callbacks */ /** Default callbacks */

View file

@ -7,8 +7,6 @@ $(function() {
}) })
.then(response => response.json()) .then(response => response.json())
.then(response => { .then(response => {
console.log(response);
if (response.success) { if (response.success) {
showStatistic( showStatistic(
$('#wishes .value'), $('#wishes .value'),
@ -51,7 +49,6 @@ function showStatistic(elementStatistic, amount, timeout) {
interval += interval * 0.1; interval += interval * 0.1;
} }
console.log(interval);
setTimeout(count, interval); setTimeout(count, interval);
} }
}, },

View file

@ -120,114 +120,35 @@ $(function () {
card = $(card); card = $(card);
var href = card.find('.content [href]').prop('href'); var href = card.find('.content [href]').prop('href');
var wish_id = card.data('id');
var refresh = card.find('button.refresh'); var refresh = card.find('button.refresh');
if (!href) {
return;
}
card.addClass('loading'); card.addClass('loading');
card.attr('data-cache', true); card.attr('data-cache', true);
fetch('/src/api/cache.php?wish_id=' + wish_id + '&wish_url=' + href, { var wishlistIndex = $('.ui.dropdown.wishlists select').prop('selectedIndex') - 1;
var wishlist_user = wishlists[wishlistIndex].user;
fetch('/src/api/wishes.php?wish_id=' + card.data('id') + '&wishlist_user=' + wishlist_user, {
method: 'GET' method: 'GET'
}) })
.then(response => response.json()) .then(handleFetchError)
.then(response => { .then(handleFetchResponse)
if (response.success) { .then(function(response) {
var info = response.data; card.html(response.html);
})
/** .catch(function(error) {
* Elements console.log(error);
*/ })
var elementImage = card.children('.image'); .finally(function() {
var elementContent = card.children('.content').first(); card.attr('data-cache', 'true');
var elementDetails = card.children('.extra.content.details'); card.removeClass('loading');
var elementButtons = card.children('.extra.content.buttons');
/**
* Image
*/
if (info.image) {
if (!elementImage.length) {
card.prepend(
'<div class="image">' +
'<img class="preview" src="' + info.image + '" loading="lazy">' +
'</div>'
);
} else {
elementImage.children('img').attr('src', info.image);
}
}
/** Favicon */
if (info.favicon) {
var elementFavicon = elementImage.children('img.favicon');
if (!elementFavicon.length) {
elementImage.children().first().after(
'<img class="favicon" src="' + info.favicon + '" loading="lazy">'
);
} else {
elementFavicon.attr('src', info.favicon);
}
}
/** Provider name */
if (info.providerName) {
var elementProviderName = elementImage.children('span.provider');
if (!elementProviderName.length) {
$('<span class="provider">' + info.providerName + '</span>').insertBefore(elementImage.children().last());
} else {
elementProviderName.text(info.providerName);
}
}
/**
* Header
*/
var elementContentHeader = elementContent.children('.header');
var elementContentHeaderTitle = elementContentHeader.children('a');
/** Title */
if (info.title) {
elementContentHeaderTitle.text(info.title);
}
/**
* Meta
*/
var elementContentMeta = elementContent.children('.meta');
if (info.keywords.length) {
if (!elementContentMeta.length) {
elementContent.append(
'<div class="meta">' + info.keywords.join(', ') + '</div>'
);
}
}
/**
* Description
*/
var elementContentDescription = elementContent.children('.description');
if (info.description) {
if (!elementContentDescription.length) {
elementContent.append(
'<div class="description">' + info.description + '</div>' +
'<div class="description-fade"></div>'
);
}
}
/**
* Finish
*/
card.removeClass('loading');
progress.progress('increment');
}
refresh.removeClass('working');
}); });
refresh.removeClass('working');
} }
/** /**
@ -235,7 +156,7 @@ $(function () {
*/ */
$(document).on('click', '.ui.button.refresh', function (event) { $(document).on('click', '.ui.button.refresh', function (event) {
var button = $(event.currentTarget); var button = $(event.currentTarget);
var card = button.closest('.ui.card'); var card = button.closest('.ui.card');
button.addClass('working'); button.addClass('working');
@ -380,24 +301,21 @@ $(function () {
var modalWishlistWishAdd = $('.ui.modal.wishlist-wish-add'); var modalWishlistWishAdd = $('.ui.modal.wishlist-wish-add');
modalWishlistWishAdd.find('[name="wishlist_id"]').val($('.ui.dropdown.wishlists').dropdown('get value')); modalWishlistWishAdd.find('[name="wishlist_id"]').val($('.ui.dropdown.wishlists').dropdown('get value'));
modalWishlistWishAdd.find('.primary.approve.button').addClass('disabled');
modalWishlistWishAdd modalWishlistWishAdd
.modal({ .modal({
onApprove: function (button) { onApprove: function (buttonAdd) {
button.addClass('loading'); buttonAdd.addClass('loading');
var form = $('.ui.form.wishlist-wish-fetch'); var form = $('.form.wishlist-wish-add');
var formData = new URLSearchParams(); var formData = new URLSearchParams(new FormData(form[0]));
formData.append('wishlist_id', form.find('input[name="wishlist_id"]').val());
formData.append('wish_url', form.find('input[name="wish_url"]').val());
fetch('/src/api/wishes.php', { fetch('/src/api/wishes.php', {
method: 'POST', method: 'POST',
body: formData body: formData
}) })
.then(response => response.json()) .then(handleFetchError)
.then(response => { .then(handleFetchResponse)
.then(function(response) {
if (response.success) { if (response.success) {
$('body').toast({ $('body').toast({
class: 'success', class: 'success',
@ -410,7 +328,10 @@ $(function () {
modalWishlistWishAdd.modal('hide'); modalWishlistWishAdd.modal('hide');
} }
button.removeClass('loading'); buttonAdd.removeClass('loading');
})
.catch(function(error) {
console.log(error);
}); });
return false; return false;
@ -420,85 +341,94 @@ $(function () {
}); });
/** Fetch */ /** Fetch */
$(document).on('submit', '.wishlist-wish-fetch', function (event) { $(document).on('click', '#wishlist-wish-add-url-validate', function () {
event.preventDefault(); var buttonValidate = $(this);
var inputWishURL = buttonValidate.prev();
var form = $(event.currentTarget); var elementModalAdd = $('.ui.modal.wishlist-wish-add');
var href = form.find('[name="wish_url"]').val(); var elementButtons = elementModalAdd.find('.actions .button');
var elementTitle = elementModalAdd.find('[name="wish_title"]');
var elementDescription = elementModalAdd.find('[name="wish_description"]');
var elementModalAdd = $('.ui.modal.wishlist-wish-add'); buttonValidate.addClass('disabled loading');
var elementButtons = elementModalAdd.find('.actions .button');
var elementImage = elementModalAdd.find('.image img');
form.addClass('loading');
elementButtons.addClass('disabled'); elementButtons.addClass('disabled');
fetch('/src/api/cache.php?wish_url=' + href, { fetch('/src/api/wishes.php?wish_url=' + inputWishURL.val(), {
method: 'GET' method: 'GET'
}) })
.then(response => response.json()) .then(handleFetchError)
.then(response => { .then(handleFetchResponse)
if (response.success) { .then(function(response) {
var info = response.data; var info = response.info;
/** /**
* Image * Title
*/ */
if (info.image && elementImage.length) { if (info.title && elementTitle.length) {
elementImage.attr('src', info.image); elementTitle.val(info.title);
}
/**
* URL
*/
if (info.url && info.url !== href) {
var elementModalFetch = $('.ui.modal.wishlist-wish-fetch');
elementModalFetch.find('input.current').val(href);
elementModalFetch.find('input.proposed').val(info.url);
elementButtons.addClass('disabled');
elementModalFetch
.modal({
allowMultiple: true,
closable: false,
onApprove: function (buttonFetch) {
var formData = new URLSearchParams();
formData.append('wish_url_current', href);
formData.append('wish_url_proposed', info.url);
buttonFetch.addClass('loading');
fetch('/src/api/wishes.php', {
method: 'PUT',
body: formData
})
.then(response => response.json())
.then(response => {
if (response.success) {
form.find('input[type="url"]').val(info.url);
elementModalFetch.modal('hide');
}
buttonFetch.removeClass('loading');
});
return false;
},
onHide: function() {
form.removeClass('loading');
elementButtons.removeClass('disabled');
}
})
.modal('show');
} else {
form.removeClass('loading');
elementButtons.removeClass('disabled');
}
} }
/**
* Description
*/
if (info.description && elementDescription.length) {
elementDescription.val(info.description);
}
/**
* URL
*/
if (info.url && info.url !== inputWishURL.val()) {
var elementModalFetch = $('.ui.modal.wishlist-wish-fetch');
elementModalFetch.find('input.current').val(inputWishURL.val());
elementModalFetch.find('input.proposed').val(info.url);
elementButtons.addClass('disabled');
elementModalFetch
.modal({
allowMultiple: true,
closable: false,
onApprove: function (buttonFetch) {
var formData = new URLSearchParams();
formData.append('wish_url_current', inputWishURL.val());
formData.append('wish_url_proposed', info.url);
buttonFetch.addClass('loading');
fetch('/src/api/wishes.php', {
method: 'PUT',
body: formData
})
.then(response => response.json())
.then(response => {
if (response.success) {
inputWishURL.val(info.url);
elementModalFetch.modal('hide');
}
buttonFetch.removeClass('loading');
});
return false;
},
onHide: function() {
buttonValidate.removeClass('disabled loading');
elementButtons.removeClass('disabled');
}
})
.modal('show');
} else {
buttonValidate.removeClass('disabled loading');
elementButtons.removeClass('disabled');
}
})
.catch(function(error) {
console.log(error);
}); });
}); });
/** /**

View file

@ -16,8 +16,6 @@ class EmbedCache
* Private * Private
*/ */
private string $directory = ROOT . '/src/cache'; private string $directory = ROOT . '/src/cache';
private string $noImage = '/src/assets/img/no-image.svg';
private string $filepath; private string $filepath;
private function getIdentifier(): string private function getIdentifier(): string
@ -39,9 +37,9 @@ class EmbedCache
public function get(bool $generateCache = false): mixed public function get(bool $generateCache = false): mixed
{ {
$info = null; $info = null;
$maxAge = 2592000; // 30 days $maxAge = 2592000; // 30 days
$age = file_exists($this->getFilepath()) ? time() - filemtime($this->getFilepath()) : $maxAge; $age = file_exists($this->getFilepath()) ? time() - filemtime($this->getFilepath()) : $maxAge;
if ($this->exists() && $age <= $maxAge && false === $generateCache) { if ($this->exists() && $age <= $maxAge && false === $generateCache) {
$info = json_decode(file_get_contents($this->getFilepath())); $info = json_decode(file_get_contents($this->getFilepath()));
@ -60,7 +58,7 @@ class EmbedCache
$info_simplified->favicon = ''; $info_simplified->favicon = '';
$info_simplified->feeds = array(); $info_simplified->feeds = array();
$info_simplified->icon = ''; $info_simplified->icon = '';
$info_simplified->image = $this->noImage; $info_simplified->image = '';
$info_simplified->keywords = array(); $info_simplified->keywords = array();
$info_simplified->language = ''; $info_simplified->language = '';
$info_simplified->languages = array(); $info_simplified->languages = array();
@ -84,7 +82,7 @@ class EmbedCache
$info_simplified->favicon = (string) $info->favicon; $info_simplified->favicon = (string) $info->favicon;
$info_simplified->feeds = (array) $info->feeds; $info_simplified->feeds = (array) $info->feeds;
$info_simplified->icon = (string) $info->icon; $info_simplified->icon = (string) $info->icon;
$info_simplified->image = $info->image ? (string) $info->image : $this->noImage; $info_simplified->image = (string) $info->image;
$info_simplified->keywords = (array) $info->keywords; $info_simplified->keywords = (array) $info->keywords;
$info_simplified->language = (string) $info->language; $info_simplified->language = (string) $info->language;
$info_simplified->languages = (array) $info->languages; $info_simplified->languages = (array) $info->languages;
@ -98,7 +96,7 @@ class EmbedCache
} catch (\Throwable $ex) { } catch (\Throwable $ex) {
$generateCache = false; $generateCache = false;
$info_simplified->title = $ex->getMessage(); $info_simplified->description = $ex->getMessage();
} }
} }

149
src/classes/wish.php Normal file
View file

@ -0,0 +1,149 @@
<?php
/**
* A wish
*
* @author Jay Trees <github.jay@grandel.anonaddy.me>
*/
namespace wishthis;
class Wish
{
public int $id;
public int $wishlist;
public ?string $title;
public ?string $description;
public ?string $url;
public ?string $status;
public function __construct(int|array $wish)
{
global $database;
$columns = array();
if (is_int($wish)) {
$wish = $database
->query('SELECT *
FROM `wishes`
WHERE `id` = ' . $wish . ';')
->fetch();
$columns = $wish;
} elseif (is_array($wish)) {
$columns = $wish;
}
if ($columns) {
foreach ($columns as $key => $value) {
$this->$key = $value;
}
}
}
public function getCard(int $ofUser, bool $generateCache = false): string
{
ob_start();
/**
* Card
*/
$userIsCurrent = isset($_SESSION['user']['id']) && intval($_SESSION['user']['id']) === $ofUser;
if ($this->url) {
$cache = new EmbedCache($this->url);
$info = $cache->get($generateCache);
$exists = $cache->exists() || !$this->url ? 'true' : 'false';
} else {
$exists = 'true';
}
$title = $this->title ?? $info->title ?? null;
$description = $this->description ?? $info->description ?? null;
$url = $this->url ?? $info->url ?? null;
$image = $info->image ?? '/src/assets/img/no-image.svg';
$favicon = $info->favicon ?? null;
$providerName = $info->providerName ?? null;
$keywords = $info->keywords ?? null;
?>
<div class="ui fluid card stretch" data-id="<?= $this->id ?>" data-cache="<?= $exists ?>">
<div class="overlay"></div>
<div class="image">
<?php if ($image) { ?>
<img class="preview" src="<?= $image ?>" loading="lazy" />
<?php } ?>
<?php if ($favicon) { ?>
<img class="favicon" src="<?= $favicon ?>" loading="lazy" />
<?php } ?>
<?php if ($providerName) { ?>
<span class="provider"><?= $providerName ?></span>
<?php } ?>
<?php if ($userIsCurrent && $url) { ?>
<button class="ui icon button refresh">
<i class="refresh icon"></i>
</button>
<?php } ?>
</div>
<div class="content">
<?php if ($title) { ?>
<div class="header">
<?php if ($url) { ?>
<a href="<?= $url ?>" target="_blank"><?= $title ?></a>
<?php } else { ?>
<?= $title ?>
<?php } ?>
</div>
<?php } ?>
<?php if ($keywords) { ?>
<div class="meta">
<?= implode(', ', $keywords) ?>
</div>
<?php } ?>
<?php if ($description) { ?>
<div class="description">
<?= $description ?>
</div>
<div class="description-fade"></div>
<?php } ?>
</div>
<div class="extra content buttons">
<?php if (!$userIsCurrent) { ?>
<a class="ui small primary labeled icon button commit">
<i class="shopping cart icon"></i>
Commit
</a>
<?php } ?>
<?php if ($url) { ?>
<a class="ui small labeled icon button" href="<?= $url ?>" target="_blank">
<i class="external icon"></i>
Visit
</a>
<?php } ?>
<?php if ($userIsCurrent) { ?>
<a class="ui small labeled red icon button delete">
<i class="trash icon"></i>
Delete
</a>
<?php } ?>
</div>
</div>
<?php
$html = ob_get_clean();
return $html;
}
}

View file

@ -54,10 +54,15 @@ class Wishlist
/** /**
* Get Wishes * Get Wishes
*/ */
$this->wishes = $database->query('SELECT * $this->wishes = $database
FROM `wishes` ->query('SELECT *
WHERE `wishlist` = ' . $this->id . ';') FROM `wishes`
->fetchAll(); WHERE `wishlist` = ' . $this->id . ';')
->fetchAll();
foreach ($this->wishes as &$wish) {
$wish = new Wish($wish);
}
} }
public function getCards($options = array()): string public function getCards($options = array()): string
@ -71,7 +76,7 @@ class Wishlist
if ($exclude) { if ($exclude) {
$wishes = array_filter($this->wishes, function ($wish) use ($exclude) { $wishes = array_filter($this->wishes, function ($wish) use ($exclude) {
return !in_array($wish['status'], $exclude); return !in_array($wish->status, $exclude);
}); });
} else { } else {
$wishes = $this->wishes; $wishes = $this->wishes;
@ -80,94 +85,14 @@ class Wishlist
/** /**
* Cards * Cards
*/ */
$userIsCurrent = isset($_SESSION['user']) && $this->data['user'] === $_SESSION['user']['id'];
$cardIndex = 0;
if (!empty($wishes)) { ?> if (!empty($wishes)) { ?>
<div class="ui three column doubling stackable grid"> <div class="ui three column doubling stackable grid">
<?php foreach ($wishes as $wish) { <?php foreach ($wishes as $wish) { ?>
$cache = new EmbedCache($wish['url']);
$info = $cache->get(false);
$exists = $cache->exists() ? 'true' : 'false';
?>
<div class="column"> <div class="column">
<div class="ui fluid card stretch" data-id="<?= $wish['id'] ?>" data-index="<?= $cardIndex ?>" data-cache="<?= $exists ?>"> <?= $wish->getCard($this->data['user'], false) ?>
<div class="overlay"></div>
<div class="image">
<?php if ($info->image) { ?>
<img class="preview" src="<?= $info->image ?>" loading="lazy"/>
<?php } ?>
<?php if ($info->favicon) { ?>
<img class="favicon" src="<?= $info->favicon ?>" loading="lazy"/>
<?php } ?>
<?php if ($info->providerName) { ?>
<span class="provider"><?= $info->providerName ?></span>
<?php } ?>
<?php if ($userIsCurrent) { ?>
<button class="ui icon button refresh">
<i class="refresh icon"></i>
</button>
<?php } ?>
</div>
<div class="content">
<?php if ($info->title) { ?>
<div class="header">
<?php if ($info->url) { ?>
<a href="<?= $info->url ?>" target="_blank"><?= $info->title ?></a>
<?php } else { ?>
<?= $info->title ?>
<?php } ?>
</div>
<?php } ?>
<?php if ($info->keywords) { ?>
<div class="meta">
<?= implode(', ', $info->keywords) ?>
</div>
<?php } ?>
<?php if ($info->description) { ?>
<div class="description">
<?= $info->description ?>
</div>
<div class="description-fade"></div>
<?php } ?>
</div>
<div class="extra content buttons">
<?php if (!$userIsCurrent) { ?>
<a class="ui small primary labeled icon button commit">
<i class="shopping cart icon"></i>
Commit
</a>
<?php } ?>
<?php if ($info->url) { ?>
<a class="ui small labeled icon button" href="<?= $info->url ?>" target="_blank">
<i class="external icon"></i>
View
</a>
<?php } ?>
<?php if ($userIsCurrent) { ?>
<a class="ui small labeled red icon button delete">
<i class="trash icon"></i>
Delete
</a>
<?php } ?>
</div>
</div>
</div> </div>
<?php } ?> <?php } ?>
</div> </div>
<? $cardIndex++ ?>
<?php } else { ?> <?php } else { ?>
<div class="ui container"> <div class="ui container">
<div class="sixteen wide column"> <div class="sixteen wide column">

View file

@ -138,15 +138,17 @@ switch ($step) {
* Wishes * Wishes
*/ */
$database->query('CREATE TABLE `wishes` ( $database->query('CREATE TABLE `wishes` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT, `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`wishlist` INT NOT NULL, `wishlist` INT NOT NULL,
`type` VARCHAR(32) NULL DEFAULT NULL, `title` VARCHAR(128) NULL DEFAULT NULL,
`url` VARCHAR(255) NULL DEFAULT NULL, `description` TEXT NULL DEFAULT NULL,
`status` VARCHAR(32) NULL DEFAULT NULL, `url` VARCHAR(255) NULL DEFAULT NULL,
`status` VARCHAR(32) NULL DEFAULT NULL,
FOREIGN KEY (`wishlist`) FOREIGN KEY (`wishlist`)
REFERENCES `wishlists` (`id`) REFERENCES `wishlists` (`id`)
ON DELETE CASCADE ON DELETE CASCADE
);'); );');
$database->query('CREATE INDEX `idx_url` ON `wishes` (`url`);');
/** /**
* Options * Options

View file

@ -111,7 +111,7 @@ $page->navigation();
<div class="column"> <div class="column">
<h2 class="ui header">Authentication</h2> <h2 class="ui header">Authentication</h2>
<p> <p>
Prove you are a Human, Lizard-person or Zuck-Like creature. Prove you are a Human, Lizard-person or Zuck-like creature.
Please name a planet from our solar system. Please name a planet from our solar system.
</p> </p>

View file

@ -127,28 +127,43 @@ $page->navigation();
<div class="header"> <div class="header">
Add a wish Add a wish
</div> </div>
<div class="image content"> <div class="content">
<div class="ui medium image">
<img src="/src/assets/img/no-image.svg" loading="lazy" />
</div>
<div class="description"> <div class="description">
<div class="ui header">Wish</div> <div class="ui header">Wish</div>
<p>Fill out the below fields to add your new wish.</p> <p>Fill out any or all of the below fields to add your new wish.</p>
<form class="ui form wishlist-wish-fetch" method="post"> <form class="ui form wishlist-wish-add" method="post">
<input type="hidden" name="wishlist_id" /> <input type="hidden" name="wishlist_id" />
<div class="field"> <div class="field">
<label>URL</label> <label>Title</label>
<input type="url" name="wish_url" /> <input type="text" name="wish_title" maxlength="128" />
</div> </div>
<input class="ui button" type="submit" value="Fetch" /> <div class="field">
<label>Description</label>
<textarea name="wish_description"></textarea>
</div>
<div class="field">
<label>URL</label>
<div class="ui action input url">
<input type="url" name="wish_url" maxlength="255" />
<button class="ui button"
id="wishlist-wish-add-url-validate"
type="button"
>
Validate
</button>
</div>
</div>
</form> </form>
</div> </div>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui primary approve button disabled"> <div class="ui primary approve button">
Add Add
</div> </div>
<div class="ui deny button"> <div class="ui deny button">