This commit is contained in:
Flatlogic Bot 2026-04-16 00:49:59 +00:00
parent 2de33ba813
commit 98725a1b7c
7 changed files with 318 additions and 29 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 KiB

View File

@ -18757,6 +18757,7 @@ CREATE TABLE IF NOT EXISTS tbl_sccharacteritems (
cl_sccharacteritem_scobjs_id INT UNSIGNED DEFAULT NULL, cl_sccharacteritem_scobjs_id INT UNSIGNED DEFAULT NULL,
cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL, cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL,
cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '', cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '',
cl_sccharacteritem_quantity INT UNSIGNED DEFAULT NULL,
cl_sccharacteritem_note TEXT DEFAULT NULL, cl_sccharacteritem_note TEXT DEFAULT NULL,
cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_sccharacteritem_character (cl_sccharacteritem_character_id), KEY idx_sccharacteritem_character (cl_sccharacteritem_character_id),

View File

@ -236,6 +236,7 @@ CREATE TABLE IF NOT EXISTS tbl_sccharacteritems (
cl_sccharacteritem_scobjs_id INT UNSIGNED DEFAULT NULL, cl_sccharacteritem_scobjs_id INT UNSIGNED DEFAULT NULL,
cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL, cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL,
cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '', cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '',
cl_sccharacteritem_quantity INT UNSIGNED DEFAULT NULL,
cl_sccharacteritem_note TEXT DEFAULT NULL, cl_sccharacteritem_note TEXT DEFAULT NULL,
cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_sccharacteritem_character (cl_sccharacteritem_character_id), KEY idx_sccharacteritem_character (cl_sccharacteritem_character_id),

View File

@ -138,6 +138,7 @@ function sccharacters_bootstrap(): void
cl_sccharacteritem_scobjs_id INT UNSIGNED DEFAULT NULL, cl_sccharacteritem_scobjs_id INT UNSIGNED DEFAULT NULL,
cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL, cl_sccharacteritem_scitemcustom_id INT(11) DEFAULT NULL,
cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '', cl_sccharacteritem_slot VARCHAR(120) NOT NULL DEFAULT '',
cl_sccharacteritem_quantity INT UNSIGNED DEFAULT NULL,
cl_sccharacteritem_note TEXT DEFAULT NULL, cl_sccharacteritem_note TEXT DEFAULT NULL,
cl_sccharacteritem_sort_order INT UNSIGNED NOT NULL DEFAULT 0, cl_sccharacteritem_sort_order INT UNSIGNED NOT NULL DEFAULT 0,
cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, cl_sccharacteritem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
@ -175,6 +176,13 @@ function sccharacters_bootstrap(): void
); );
} }
if (!sccharacters_column_exists($db, 'tbl_sccharacteritems', 'cl_sccharacteritem_quantity')) {
$db->exec(
'ALTER TABLE tbl_sccharacteritems
ADD COLUMN cl_sccharacteritem_quantity INT UNSIGNED NULL AFTER cl_sccharacteritem_slot'
);
}
if (!sccharacters_column_exists($db, 'tbl_sccharacteritems', 'cl_sccharacteritem_sort_order')) { if (!sccharacters_column_exists($db, 'tbl_sccharacteritems', 'cl_sccharacteritem_sort_order')) {
$db->exec( $db->exec(
'ALTER TABLE tbl_sccharacteritems 'ALTER TABLE tbl_sccharacteritems

View File

@ -221,7 +221,7 @@ $character_items_by_category = sccharacters_sort_items_by_category_order(
.equipment-sections { .equipment-sections {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem; gap: 2.2rem;
} }
.equipment-section { .equipment-section {
@ -233,7 +233,6 @@ $character_items_by_category = sccharacters_sort_items_by_category_order(
.equipment-section-head { .equipment-section-head {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
gap: 0.8rem; gap: 0.8rem;
} }
@ -243,6 +242,19 @@ $character_items_by_category = sccharacters_sort_items_by_category_order(
letter-spacing: 0.08em; letter-spacing: 0.08em;
text-transform: uppercase; text-transform: uppercase;
font-size: 1rem; font-size: 1rem;
display: flex;
align-items: center;
gap: 0.85rem;
width: 100%;
}
.equipment-section-title::after {
content: '';
flex: 1 1 auto;
height: 2px;
background: currentColor;
border-radius: 999px;
opacity: 0.95;
} }
.grid { .grid {
@ -346,7 +358,6 @@ $character_items_by_category = sccharacters_sort_items_by_category_order(
</div> </div>
</section> </section>
<h2 class="section-title">Équipement</h2>
<?php if ($character_items === []): ?> <?php if ($character_items === []): ?>
<div class="message"> <div class="message">
<p class="muted">Ce personnage na pas encore déquipement attribué.</p> <p class="muted">Ce personnage na pas encore déquipement attribué.</p>
@ -357,7 +368,6 @@ $character_items_by_category = sccharacters_sort_items_by_category_order(
<section class="equipment-section"> <section class="equipment-section">
<div class="equipment-section-head"> <div class="equipment-section-head">
<h3 class="equipment-section-title"><?php echo htmlspecialchars(sccharacters_item_category_label((string) $category_key), ENT_QUOTES, 'UTF-8'); ?></h3> <h3 class="equipment-section-title"><?php echo htmlspecialchars(sccharacters_item_category_label((string) $category_key), ENT_QUOTES, 'UTF-8'); ?></h3>
<span class="tag muted"><?php echo count($category_items); ?> objet(s)</span>
</div> </div>
<div class="grid"> <div class="grid">
<?php foreach ($category_items as $item_row): ?> <?php foreach ($category_items as $item_row): ?>
@ -380,6 +390,10 @@ $character_items_by_category = sccharacters_sort_items_by_category_order(
$type, $type,
$subtype $subtype
); );
$quantity = isset($item_row['cl_sccharacteritem_quantity']) && (int) $item_row['cl_sccharacteritem_quantity'] > 0
? (int) $item_row['cl_sccharacteritem_quantity']
: null;
$title = $quantity !== null ? $quantity . 'x ' . $name : $name;
$note = trim((string) ($item_row['cl_sccharacteritem_note'] ?? '')); $note = trim((string) ($item_row['cl_sccharacteritem_note'] ?? ''));
$stats = $is_custom ? ($custom_stats_by_itemcustom[(int) ($item_row['cl_sccharacteritem_scitemcustom_id'] ?? 0)] ?? []) : []; $stats = $is_custom ? ($custom_stats_by_itemcustom[(int) ($item_row['cl_sccharacteritem_scitemcustom_id'] ?? 0)] ?? []) : [];
?> ?>
@ -390,7 +404,7 @@ $character_items_by_category = sccharacters_sort_items_by_category_order(
<div class="thumb-fallback"></div> <div class="thumb-fallback"></div>
<?php endif; ?> <?php endif; ?>
<div class="card-body"> <div class="card-body">
<h3><?php echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8'); ?></h3> <h3><?php echo htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); ?></h3>
<div class="tags"> <div class="tags">
<span class="tag <?php echo $is_custom ? 'tag-primary' : ''; ?>"><?php echo $is_custom ? 'Objet perso.' : 'Base dobjets'; ?></span> <span class="tag <?php echo $is_custom ? 'tag-primary' : ''; ?>"><?php echo $is_custom ? 'Objet perso.' : 'Base dobjets'; ?></span>
<span class="tag"><?php echo htmlspecialchars(sccharacters_item_category_label($category), ENT_QUOTES, 'UTF-8'); ?></span> <span class="tag"><?php echo htmlspecialchars(sccharacters_item_category_label($category), ENT_QUOTES, 'UTF-8'); ?></span>

View File

@ -36,6 +36,26 @@ function sccharacters_clean_text(?string $value): string
return trim((string) $value); return trim((string) $value);
} }
function sccharacters_normalize_item_quantity($value): ?int
{
if ($value === null) {
return null;
}
$value = trim((string) $value);
if ($value === '' || !preg_match('/^\d+$/', $value)) {
return null;
}
$quantity = (int) $value;
if ($quantity <= 0) {
return null;
}
return min($quantity, 999999);
}
function sccharacters_is_valid_url(string $value): bool function sccharacters_is_valid_url(string $value): bool
{ {
if ($value === '') { if ($value === '') {
@ -203,7 +223,7 @@ function sccharacters_parse_item_key(string $item_key): ?array
]; ];
} }
function sccharacters_merge_selected_items(array $staged_items, array $selected_items, array $item_slots, array $item_notes): array function sccharacters_merge_selected_items(array $staged_items, array $selected_items, array $item_slots, array $item_notes, array $item_quantities = []): array
{ {
$selected_items = array_values(array_unique(array_map('strval', $selected_items))); $selected_items = array_values(array_unique(array_map('strval', $selected_items)));
$staged_count = 0; $staged_count = 0;
@ -221,6 +241,7 @@ function sccharacters_merge_selected_items(array $staged_items, array $selected_
'source_id' => $parsed['source_id'], 'source_id' => $parsed['source_id'],
'category' => sccharacters_clean_text($item_slots[$item_key] ?? ''), 'category' => sccharacters_clean_text($item_slots[$item_key] ?? ''),
'note' => sccharacters_clean_text($item_notes[$item_key] ?? ''), 'note' => sccharacters_clean_text($item_notes[$item_key] ?? ''),
'quantity' => sccharacters_normalize_item_quantity($item_quantities[$item_key] ?? null),
]; ];
$staged_count++; $staged_count++;
} }
@ -627,6 +648,7 @@ function sccharacters_attach_item(
string $source, string $source,
int $source_id, int $source_id,
string $requested_category, string $requested_category,
?int $quantity,
string $note, string $note,
?string &$error_message = null ?string &$error_message = null
): bool { ): bool {
@ -671,6 +693,7 @@ function sccharacters_attach_item(
cl_sccharacteritem_scobjs_id, cl_sccharacteritem_scobjs_id,
cl_sccharacteritem_scitemcustom_id, cl_sccharacteritem_scitemcustom_id,
cl_sccharacteritem_slot, cl_sccharacteritem_slot,
cl_sccharacteritem_quantity,
cl_sccharacteritem_note, cl_sccharacteritem_note,
cl_sccharacteritem_sort_order cl_sccharacteritem_sort_order
) VALUES ( ) VALUES (
@ -679,6 +702,7 @@ function sccharacters_attach_item(
:scobjs_id, :scobjs_id,
NULL, NULL,
:slot, :slot,
:quantity,
:note, :note,
:sort_order :sort_order
)' )'
@ -688,6 +712,7 @@ function sccharacters_attach_item(
'source' => 'base', 'source' => 'base',
'scobjs_id' => $source_id, 'scobjs_id' => $source_id,
'slot' => $category, 'slot' => $category,
'quantity' => $quantity,
'note' => $note !== '' ? $note : null, 'note' => $note !== '' ? $note : null,
'sort_order' => $sort_order, 'sort_order' => $sort_order,
]); ]);
@ -728,6 +753,7 @@ function sccharacters_attach_item(
cl_sccharacteritem_scobjs_id, cl_sccharacteritem_scobjs_id,
cl_sccharacteritem_scitemcustom_id, cl_sccharacteritem_scitemcustom_id,
cl_sccharacteritem_slot, cl_sccharacteritem_slot,
cl_sccharacteritem_quantity,
cl_sccharacteritem_note, cl_sccharacteritem_note,
cl_sccharacteritem_sort_order cl_sccharacteritem_sort_order
) VALUES ( ) VALUES (
@ -736,6 +762,7 @@ function sccharacters_attach_item(
NULL, NULL,
:scitemcustom_id, :scitemcustom_id,
:slot, :slot,
:quantity,
:note, :note,
:sort_order :sort_order
)' )'
@ -745,6 +772,7 @@ function sccharacters_attach_item(
'source' => 'custom', 'source' => 'custom',
'scitemcustom_id' => $source_id, 'scitemcustom_id' => $source_id,
'slot' => $category, 'slot' => $category,
'quantity' => $quantity,
'note' => $note !== '' ? $note : null, 'note' => $note !== '' ? $note : null,
'sort_order' => $sort_order, 'sort_order' => $sort_order,
]); ]);
@ -756,6 +784,79 @@ function sccharacters_attach_item(
return false; return false;
} }
function sccharacters_update_character_item(
PDO $db,
int $owner_auth_id,
int $character_id,
int $character_item_id,
string $requested_category,
?int $quantity,
string $note,
?string &$error_message = null
): bool {
if ($character_id <= 0 || $owner_auth_id <= 0 || $character_item_id <= 0) {
$error_message = 'Paramètres de mise à jour invalides.';
return false;
}
$stmt_item = $db->prepare(
"SELECT
ci.cl_sccharacteritem_id,
ci.cl_sccharacteritem_source,
bo.cl_scobjs_type AS cl_sccharacteritem_base_type,
bo.cl_scobjs_subtype AS cl_sccharacteritem_base_subtype,
oo.cl_scobjs_type AS cl_sccharacteritem_custom_type,
oo.cl_scobjs_subtype AS cl_sccharacteritem_custom_subtype
FROM tbl_sccharacteritems ci
INNER JOIN tbl_sccharacters c ON c.cl_sccharacter_id = ci.cl_sccharacteritem_character_id
LEFT JOIN tbl_scobjs bo ON bo.cl_scobjs_id = ci.cl_sccharacteritem_scobjs_id
LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = ci.cl_sccharacteritem_scitemcustom_id
LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id
WHERE ci.cl_sccharacteritem_id = :character_item_id
AND c.cl_sccharacter_id = :character_id
AND c.cl_sccharacter_owner_auth_id = :owner_auth_id
LIMIT 1"
);
$stmt_item->execute([
'character_item_id' => $character_item_id,
'character_id' => $character_id,
'owner_auth_id' => $owner_auth_id,
]);
$item_row = $stmt_item->fetch();
if (!$item_row) {
$error_message = 'Objet introuvable ou non autorisé.';
return false;
}
$is_custom = (string) ($item_row['cl_sccharacteritem_source'] ?? '') === 'custom';
$item_type = $is_custom
? (string) ($item_row['cl_sccharacteritem_custom_type'] ?? '')
: (string) ($item_row['cl_sccharacteritem_base_type'] ?? '');
$item_subtype = $is_custom
? (string) ($item_row['cl_sccharacteritem_custom_subtype'] ?? '')
: (string) ($item_row['cl_sccharacteritem_base_subtype'] ?? '');
$category = sccharacters_resolve_item_category($requested_category, $item_type, $item_subtype);
$stmt_update = $db->prepare(
'UPDATE tbl_sccharacteritems
SET cl_sccharacteritem_slot = :slot,
cl_sccharacteritem_quantity = :quantity,
cl_sccharacteritem_note = :note
WHERE cl_sccharacteritem_id = :character_item_id
AND cl_sccharacteritem_character_id = :character_id'
);
$stmt_update->execute([
'slot' => $category,
'quantity' => $quantity,
'note' => $note !== '' ? $note : null,
'character_item_id' => $character_item_id,
'character_id' => $character_id,
]);
return true;
}
$flash = auth_flash_get(); $flash = auth_flash_get();
$flash_type = $flash['type'] ?? ''; $flash_type = $flash['type'] ?? '';
$flash_message = $flash['message'] ?? ''; $flash_message = $flash['message'] ?? '';
@ -1048,6 +1149,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$character_id = (int) ($_POST['character_id'] ?? 0); $character_id = (int) ($_POST['character_id'] ?? 0);
$obj_id = (int) ($_POST['base_obj_id'] ?? 0); $obj_id = (int) ($_POST['base_obj_id'] ?? 0);
$requested_category = sccharacters_clean_text($_POST['item_slot'] ?? ''); $requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
$quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
$note = sccharacters_clean_text($_POST['item_note'] ?? ''); $note = sccharacters_clean_text($_POST['item_note'] ?? '');
$item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base'); $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
$item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? ''); $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
@ -1062,6 +1164,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'base', 'base',
$obj_id, $obj_id,
$requested_category, $requested_category,
$quantity,
$note, $note,
$error_message $error_message
)) { )) {
@ -1079,6 +1182,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$character_id = (int) ($_POST['character_id'] ?? 0); $character_id = (int) ($_POST['character_id'] ?? 0);
$itemcustom_id = (int) ($_POST['custom_item_id'] ?? 0); $itemcustom_id = (int) ($_POST['custom_item_id'] ?? 0);
$requested_category = sccharacters_clean_text($_POST['item_slot'] ?? ''); $requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
$quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
$note = sccharacters_clean_text($_POST['item_note'] ?? ''); $note = sccharacters_clean_text($_POST['item_note'] ?? '');
$item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'custom'); $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'custom');
$item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? ''); $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
@ -1093,6 +1197,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'custom', 'custom',
$itemcustom_id, $itemcustom_id,
$requested_category, $requested_category,
$quantity,
$note, $note,
$error_message $error_message
)) { )) {
@ -1105,6 +1210,40 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, true, $item_page_context, $item_per_page_context)); header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, true, $item_page_context, $item_per_page_context));
exit; exit;
} }
if ($action === 'update_character_item') {
$character_item_id = (int) ($_POST['character_item_id'] ?? 0);
$character_id = (int) ($_POST['character_id'] ?? 0);
$requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
$quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
$note = sccharacters_clean_text($_POST['item_note'] ?? '');
$item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
$item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
$item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
$item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
$item_panel_context = (string) ($_POST['item_panel_context'] ?? '') === '1';
$error_message = null;
if (!sccharacters_update_character_item(
$db,
$current_owner_auth_id,
$character_id,
$character_item_id,
$requested_category,
$quantity,
$note,
$error_message
)) {
auth_flash_set('error', $error_message ?? 'Impossible de mettre à jour cet objet.');
header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
exit;
}
auth_flash_set('success', 'Objet mis à jour.');
header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
exit;
}
if ($action === 'move_character_category') { if ($action === 'move_character_category') {
$character_id = (int) ($_POST['character_id'] ?? 0); $character_id = (int) ($_POST['character_id'] ?? 0);
$category_key = sccharacters_clean_text($_POST['category_key'] ?? ''); $category_key = sccharacters_clean_text($_POST['category_key'] ?? '');
@ -2082,11 +2221,93 @@ if ($selected_character) {
margin-top: auto; margin-top: auto;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0.6rem; gap: 0.75rem;
align-items: center; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
} }
.equipment-action-buttons {
display: grid;
grid-template-columns: repeat(2, auto);
align-items: start;
gap: 0.55rem;
justify-content: end;
}
.equipment-edit {
width: auto;
margin-top: 0;
}
.equipment-edit[open] {
grid-column: 1 / -1;
width: min(100%, 34rem);
justify-self: end;
}
.equipment-edit-summary,
.equipment-icon-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.45rem;
min-width: 2.45rem;
height: 2.45rem;
min-height: 2.45rem;
padding: 0;
cursor: pointer;
list-style: none;
line-height: 1;
}
.equipment-edit-summary::-webkit-details-marker {
display: none;
}
.equipment-edit-form {
margin-top: 0.85rem;
padding: 0.95rem;
border-radius: 14px;
border: 1px solid rgba(255,255,255,0.08);
background: rgba(255,255,255,0.04);
display: grid;
gap: 0.85rem;
width: min(100%, 34rem);
}
.equipment-edit-grid {
display: grid;
grid-template-columns: minmax(110px, 135px) minmax(0, 1fr);
gap: 0.75rem;
align-items: start;
}
.equipment-edit-grid textarea {
grid-column: 1 / -1;
min-height: 96px;
resize: vertical;
}
.item-attach-meta textarea {
grid-column: 1 / -1;
min-height: 72px;
resize: vertical;
}
.equipment-edit-form input,
.equipment-edit-form select,
.equipment-edit-form textarea,
.item-attach-meta input,
.item-attach-meta select,
.item-attach-meta textarea {
width: 100%;
}
.equipment-edit-form-actions {
display: flex;
justify-content: flex-end;
}
.equipment-reorder-form { .equipment-reorder-form {
display: none; display: none;
} }
@ -2219,13 +2440,13 @@ if ($selected_character) {
.search-result { .search-result {
padding: 0.95rem; padding: 0.95rem;
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) 310px; grid-template-columns: minmax(0, 1fr) 360px;
gap: 1rem; gap: 1rem;
align-items: start; align-items: start;
} }
body.show-item-preview .search-result { body.show-item-preview .search-result {
grid-template-columns: 96px minmax(0, 1fr) 310px; grid-template-columns: 96px minmax(0, 1fr) 360px;
} }
.search-result strong { display: block; margin-bottom: 0.25rem; } .search-result strong { display: block; margin-bottom: 0.25rem; }
@ -2305,27 +2526,35 @@ if ($selected_character) {
.item-attach-form { .item-attach-form {
display: grid; display: grid;
gap: 0.65rem; grid-template-columns: minmax(0, 1fr) auto;
gap: 0.75rem;
align-self: stretch;
align-items: stretch;
} }
.item-attach-meta { .item-attach-meta {
display: grid; display: grid;
grid-template-columns: minmax(0, 180px) minmax(0, 1fr); grid-template-columns: minmax(96px, 112px) minmax(0, 1fr);
gap: 0.55rem; gap: 0.55rem;
align-items: start;
} }
.item-attach-actions { .item-attach-actions {
display: flex; display: flex;
justify-content: flex-end; align-self: stretch;
} }
.item-add-button { .item-add-button {
min-width: 2.75rem; min-width: 3rem;
min-height: 2.75rem; min-height: 100%;
height: 100%;
padding: 0.4rem; padding: 0.4rem;
font-size: 1.55rem; font-size: 1.55rem;
line-height: 1; line-height: 1;
font-weight: 700; font-weight: 700;
display: inline-flex;
align-items: center;
justify-content: center;
} }
.search-results-summary { .search-results-summary {
@ -2415,6 +2644,7 @@ if ($selected_character) {
justify-content: flex-start; justify-content: flex-start;
} }
.item-attach-form,
.item-attach-meta, .item-attach-meta,
.search-controls-row { .search-controls-row {
grid-template-columns: 1fr; grid-template-columns: 1fr;
@ -2426,6 +2656,8 @@ if ($selected_character) {
.item-add-button { .item-add-button {
width: 100%; width: 100%;
min-height: 2.75rem;
height: auto;
} }
} }
@ -2803,6 +3035,8 @@ if ($selected_character) {
$item_type, $item_type,
$item_subtype $item_subtype
); );
$item_quantity = sccharacters_normalize_item_quantity($character_item_row['cl_sccharacteritem_quantity'] ?? null);
$item_title = $item_quantity !== null ? $item_quantity . 'x ' . $item_name : $item_name;
$item_note = trim((string) ($character_item_row['cl_sccharacteritem_note'] ?? '')); $item_note = trim((string) ($character_item_row['cl_sccharacteritem_note'] ?? ''));
$item_stats = []; $item_stats = [];
if ($is_custom) { if ($is_custom) {
@ -2818,7 +3052,7 @@ if ($selected_character) {
<div class="equip-content"> <div class="equip-content">
<div> <div>
<div class="equip-title-row"> <div class="equip-title-row">
<h3 class="equip-title"><?php echo htmlspecialchars($item_name, ENT_QUOTES, 'UTF-8'); ?></h3> <h3 class="equip-title"><?php echo htmlspecialchars($item_title, ENT_QUOTES, 'UTF-8'); ?></h3>
<span class="drag-handle" title="Glisser pour changer lordre" aria-hidden="true">⋮⋮</span> <span class="drag-handle" title="Glisser pour changer lordre" aria-hidden="true">⋮⋮</span>
</div> </div>
<div class="equip-meta" style="margin-top:0.45rem;"> <div class="equip-meta" style="margin-top:0.45rem;">
@ -2850,18 +3084,48 @@ if ($selected_character) {
<div class="equipment-actions"> <div class="equipment-actions">
<span class="drag-hint muted">Glisser-déposer pour réordonner dans cette catégorie</span> <span class="drag-hint muted">Glisser-déposer pour réordonner dans cette catégorie</span>
<form method="post" style="display:inline-flex;"> <div class="equipment-action-buttons">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>"> <details class="equipment-edit">
<input type="hidden" name="action" value="delete_character_item"> <summary class="btn btn-secondary btn-small equipment-edit-summary" title="Modifier lobjet" aria-label="Modifier lobjet"><span aria-hidden="true"></span></summary>
<input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>"> <form method="post" class="equipment-edit-form">
<input type="hidden" name="character_item_id" value="<?php echo (int) $character_item_row['cl_sccharacteritem_id']; ?>"> <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="item_source_context" value="<?php echo htmlspecialchars($item_source, ENT_QUOTES, 'UTF-8'); ?>"> <input type="hidden" name="action" value="update_character_item">
<input type="hidden" name="item_search_context" value="<?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?>"> <input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
<input type="hidden" name="item_page_context" value="<?php echo (int) $item_page; ?>"> <input type="hidden" name="character_item_id" value="<?php echo (int) $character_item_row['cl_sccharacteritem_id']; ?>">
<input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>"> <input type="hidden" name="item_source_context" value="<?php echo htmlspecialchars($item_source, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="item_panel_context" value="<?php echo ($item_search !== '' || $item_panel_open) ? '1' : '0'; ?>"> <input type="hidden" name="item_search_context" value="<?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?>">
<button type="submit" class="btn btn-danger btn-small" onclick="return confirm('Retirer cet objet du personnage ?');">Retirer</button> <input type="hidden" name="item_page_context" value="<?php echo (int) $item_page; ?>">
</form> <input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>">
<input type="hidden" name="item_panel_context" value="<?php echo ($item_search !== '' || $item_panel_open) ? '1' : '0'; ?>">
<div class="equipment-edit-grid">
<input type="number" name="item_quantity" min="1" step="1" inputmode="numeric" placeholder="Quantité" value="<?php echo $item_quantity !== null ? (int) $item_quantity : ''; ?>" aria-label="Quantité de l'objet">
<select name="item_slot" aria-label="Catégorie de l'objet">
<?php foreach ($item_category_options as $category_value => $category_label): ?>
<option value="<?php echo htmlspecialchars($category_value, ENT_QUOTES, 'UTF-8'); ?>" <?php echo $item_category === $category_value ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($category_label, ENT_QUOTES, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
<textarea name="item_note" class="item-note-field" rows="4" placeholder="Note optionnelle"><?php echo htmlspecialchars($item_note, ENT_QUOTES, 'UTF-8'); ?></textarea>
</div>
<div class="equipment-edit-form-actions">
<button type="submit" class="btn btn-primary btn-small">Enregistrer</button>
</div>
</form>
</details>
<form method="post" style="display:inline-flex;">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" value="delete_character_item">
<input type="hidden" name="character_id" value="<?php echo (int) $selected_character['cl_sccharacter_id']; ?>">
<input type="hidden" name="character_item_id" value="<?php echo (int) $character_item_row['cl_sccharacteritem_id']; ?>">
<input type="hidden" name="item_source_context" value="<?php echo htmlspecialchars($item_source, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="item_search_context" value="<?php echo htmlspecialchars($item_search, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="item_page_context" value="<?php echo (int) $item_page; ?>">
<input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>">
<input type="hidden" name="item_panel_context" value="<?php echo ($item_search !== '' || $item_panel_open) ? '1' : '0'; ?>">
<button type="submit" class="btn btn-danger btn-small equipment-icon-button" title="Retirer lobjet" aria-label="Retirer lobjet" onclick="return confirm('Retirer cet objet du personnage ?');"><span aria-hidden="true">🗑</span></button>
</form>
</div>
</div> </div>
</div> </div>
</article> </article>
@ -3008,6 +3272,7 @@ if ($selected_character) {
<input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>"> <input type="hidden" name="item_per_page_context" value="<?php echo (int) $item_per_page; ?>">
<div class="item-attach-meta"> <div class="item-attach-meta">
<input type="number" name="item_quantity" min="1" step="1" inputmode="numeric" placeholder="Quantité" aria-label="Quantité de l'objet">
<select name="item_slot" aria-label="Catégorie de l'objet"> <select name="item_slot" aria-label="Catégorie de l'objet">
<?php foreach ($item_category_options as $category_value => $category_label): ?> <?php foreach ($item_category_options as $category_value => $category_label): ?>
<option value="<?php echo htmlspecialchars($category_value, ENT_QUOTES, 'UTF-8'); ?>" <?php echo $recommended_category === $category_value ? 'selected' : ''; ?>> <option value="<?php echo htmlspecialchars($category_value, ENT_QUOTES, 'UTF-8'); ?>" <?php echo $recommended_category === $category_value ? 'selected' : ''; ?>>
@ -3015,7 +3280,7 @@ if ($selected_character) {
</option> </option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
<input type="text" name="item_note" placeholder="Note optionnelle"> <textarea name="item_note" class="item-note-field" rows="2" placeholder="Note optionnelle"></textarea>
</div> </div>
<div class="item-attach-actions"> <div class="item-attach-actions">