1<?php
2
3if (!defined('ACP_ROOT')) {
4 http_response_code(403);
5 die('Direct access denied.');
6}
7
8$repoConfig = plugin_repository_config();
9$catalogue = plugin_repository_list(isset($_GET['refresh']));
10$remote = $catalogue['plugins'];
11$repoError = (string)($catalogue['error'] ?? '');
12$installed = znote_plugins(true);
13?>
14
15<div class="acp-toolbar">
16 <div>
17 <a class="acp-btn acp-btn--ghost acp-btn--sm" href="<?= h(acp_url('plugins')) ?>">
18 <i class="fa fa-arrow-left"></i> <?= t('acp.plgbr.back') ?>
19 </a>
20 </div>
21 <div class="acp-actions is-tight">
22 <span class="is-muted"><?= t('acp.plgbr.available', ['n' => count($remote)]) ?></span>
23 <a class="acp-btn acp-btn--ghost acp-btn--sm" href="<?= h(acp_url('plugins', ['tab' => 'browse', 'refresh' => 1])) ?>">
24 <i class="fa fa-refresh"></i> <?= t('acp.plgbr.refresh') ?>
25 </a>
26 </div>
27</div>
28
29<?php if (!$repoConfig['enabled']): ?>
30
31 <section class="acp-card">
32 <div class="acp-card-body">
33 <?php acp_empty(t('acp.plgbr.repo_off'), 'fa-plug'); ?>
34 <p class="is-muted" style="text-align:center;">
35 <?= t('acp.plgbr.repo_off_hint', ['code' => '<code>$config[\'plugin_repository\'][\'enabled\'] = true;</code>']) ?>
36 </p>
37 </div>
38 </section>
39
40<?php elseif ($repoError !== ''): ?>
41
42 <div class="acp-actions is-tight" style="margin-bottom:12px;">
43 <form class="acp-inline-form" method="post">
44 <?= acp_csrf_field() ?>
45 <input type="hidden" name="clear_plugin_repository_cache" value="1">
46 <button class="acp-btn acp-btn--red acp-btn--sm" type="submit">
47 <i class="fa fa-trash"></i> <?= t('acp.plgbr.delete_cache') ?>
48 </button>
49 </form>
50 </div>
51
52 <div class="acp-flash acp-flash--error">
53 <i class="fa fa-exclamation-triangle"></i>
54 <span>
55 <strong><?= t('acp.plgbr.catalogue_error') ?></strong><br>
56 <?= h($repoError) ?><br>
57 <span class="is-muted"><?= t('acp.plgbr.catalogue_url') ?> <code><?= h($repoConfig['index']) ?></code></span>
58 </span>
59 </div>
60
61<?php elseif (!$remote): ?>
62
63 <section class="acp-card">
64 <div class="acp-card-body">
65 <?php acp_empty(t('acp.plgbr.catalogue_empty'), 'fa-inbox'); ?>
66 </div>
67 </section>
68
69<?php else: ?>
70
71 <div class="acp-flash acp-flash--info">
72 <i class="fa fa-info-circle"></i>
73 <span>
74 <?= t('acp.plgbr.warning', [
75 'hosts' => '<code>' . h(implode('</code>, <code>', $repoConfig['allowed_hosts'])) . '</code>',
76 'configphp' => '<code>config.php</code>',
77 ]) ?>
78 </span>
79 </div>
80
81 <div class="acp-media">
82 <?php foreach ($remote as $key => $item):
83 $isInstalled = isset($installed[$key]);
84 $localVer = $isInstalled ? (string)$installed[$key]['version'] : '';
85 $isUpdate = ($isInstalled && $item['version'] !== '' && $localVer !== '' && version_compare($item['version'], $localVer, '>'));
86 ?>
87 <article class="acp-media-item<?= $isInstalled && !$isUpdate ? ' is-dimmed' : '' ?>">
88
89 <?php if ($item['screenshot'] !== ''): ?>
90 <img src="<?= h($item['screenshot']) ?>" alt="<?= h($item['name']) ?>" loading="lazy" referrerpolicy="no-referrer">
91 <?php else: ?>
92 <div style="display:grid;place-items:center;height:170px;background:var(--acp-panel-2);color:var(--acp-fg-muted);">
93 <span><i class="fa fa-plug"></i> <?= t('acp.plgbr.no_screenshot') ?></span>
94 </div>
95 <?php endif; ?>
96
97 <div class="acp-media-body">
98 <h3>
99 <?= h($item['name']) ?>
100 <?php if ($isUpdate): ?>
101 <span class="acp-pill acp-pill--amber"><?= t('acp.plgbr.update_available') ?></span>
102 <?php elseif ($isInstalled): ?>
103 <span class="acp-pill acp-pill--grey"><?= t('acp.plgbr.installed_pill') ?></span>
104 <?php endif; ?>
105 </h3>
106
107 <p><?= h($item['description']) ?></p>
108
109 <?php if ($isUpdate && (string)($item['changelog'] ?? '') !== ''): ?>
110 <div style="margin:10px 0;padding:10px 12px;border:1px solid var(--acp-border);border-left:3px solid var(--acp-amber);border-radius:8px;background:var(--acp-panel-2);font-size:12px;">
111 <strong style="display:block;margin-bottom:5px;">
112 <i class="fa fa-list-ul"></i>
113 <?= t('acp.plgbr.whats_new', ['version' => h($item['version'])]) ?>
114 </strong>
115 <div class="is-muted" style="white-space:pre-line;line-height:1.45;"><?= h($item['changelog']) ?></div>
116 </div>
117 <?php endif; ?>
118
119 <p class="is-muted" style="font-size:12px;">
120 <code>plugins/<?= h($key) ?>/</code>
121 <?php if ($item['author'] !== ''): ?>· <?= t('acp.plgbr.by_author', ['author' => h($item['author'])]) ?><?php endif; ?>
122 <?php if ($item['version'] !== ''): ?>
123 · v<?= h($item['version']) ?>
124 <?php if ($isUpdate): ?>
125 <span class="acp-pill acp-pill--amber"><?= t('acp.plgbr.you_have', ['version' => h($localVer)]) ?></span>
126 <?php endif; ?>
127 <?php endif; ?>
128 </p>
129
130 <?php if (!$item['installable']): ?>
131 <p style="font-size:12px;color:var(--acp-red);"><?= t('acp.plgbr.not_installable') ?></p>
132 <?php endif; ?>
133 </div>
134
135 <div class="acp-media-foot">
136 <?php if (!$item['installable']): ?>
137
138 <?php if ($item['url'] !== ''): ?>
139 <a class="acp-btn acp-btn--ghost acp-btn--sm" href="<?= h($item['url']) ?>" target="_blank" rel="noopener">
140 <i class="fa fa-external-link"></i> <?= t('acp.plgbr.open_page') ?>
141 </a>
142 <?php endif; ?>
143
144 <?php elseif ($isInstalled && !$isUpdate): ?>
145
146 <span class="acp-btn acp-btn--ghost acp-btn--sm is-disabled">
147 <i class="fa fa-check"></i> <?= t('acp.plgbr.installed_badge') ?>
148 </span>
149 <form class="acp-inline-form" method="post"
150 data-confirm="<?= h(t('acp.plgbr.confirm_reinstall', ['name' => $item['name'], 'key' => $key])) ?>">
151 <?= acp_csrf_field() ?>
152 <input type="hidden" name="repo_install" value="<?= h($key) ?>">
153 <input type="hidden" name="overwrite" value="1">
154 <button class="acp-btn acp-btn--ghost acp-btn--sm" type="submit">
155 <i class="fa fa-refresh"></i> <?= t('acp.plgbr.reinstall') ?>
156 </button>
157 </form>
158
159 <?php else: ?>
160
161 <form class="acp-inline-form" method="post"
162 data-confirm="<?= $isInstalled
163 ? h(t('acp.plgbr.confirm_update', ['name' => $item['name'], 'version' => $item['version'], 'key' => $key]))
164 : h(t('acp.plgbr.confirm_install', ['name' => $item['name']])) ?>">
165 <?= acp_csrf_field() ?>
166 <input type="hidden" name="repo_install" value="<?= h($key) ?>">
167 <?php if ($isInstalled): ?><input type="hidden" name="overwrite" value="1"><?php endif; ?>
168 <button class="acp-btn acp-btn--sm" type="submit">
169 <i class="fa fa-<?= $isInstalled ? 'arrow-up' : 'download' ?>"></i>
170 <?= $isInstalled ? t('acp.plgbr.update_btn') : t('acp.plgbr.install_btn') ?>
171 </button>
172 </form>
173
174 <?php endif; ?>
175
176 <?php if ($item['url'] !== '' && $item['installable']): ?>
177 <a class="acp-btn acp-btn--ghost acp-btn--sm" href="<?= h($item['url']) ?>" target="_blank" rel="noopener">
178 <i class="fa fa-external-link"></i> <?= t('acp.plgbr.details') ?>
179 </a>
180 <?php endif; ?>
181 </div>
182 </article>
183 <?php endforeach; ?>
184 </div>
185
186<?php endif; ?>
187