first commit
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="404"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<div class="card" style="text-align: center; padding: 2rem;">
|
||||
<div style="font-size: 4rem; color: var(--text-muted); margin-bottom: 1rem;">404</div>
|
||||
<h2 style="margin-bottom: 1rem; color: var(--text-main);">{'Sorry, nothing to see here.'|t}</h2>
|
||||
{if="!empty($error_message)"}
|
||||
<p class="text-muted">{$error_message}</p>
|
||||
{/if}
|
||||
<a href="{$base_path}/" class="btn btn-primary" style="margin-top: 1rem;">{'Home'|t}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="addlink"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body onload="document.addform.post.focus();">
|
||||
{include="page.header"}
|
||||
<div id="headerform" class="page-add container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<form method="GET" action="{$base_path}/admin/shaare" name="addform" class="form-add">
|
||||
<div class="card">
|
||||
<div class="card-header">{"Shaare a new link"|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="post">{'URL or leave empty to post a note'|t}</label>
|
||||
<input type="text" name="post" id="post" class="form-control autofocus" placeholder="https://...">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary">{'Add link'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<div style="text-align: right; margin-bottom: 1rem;">
|
||||
<button type="button" class="btn btn-secondary button-batch-addform"><i class="mdi mdi-playlist-plus" aria-hidden="true"></i> {'BULK CREATION'|t}</button>
|
||||
</div>
|
||||
|
||||
<form class="card batch-addform hidden" method="POST" action="{$base_path}/admin/shaare-batch" name="batch-addform">
|
||||
<div class="card-header">{"Shaare multiple new links"|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="urls">{'Add one URL per line to create multiple bookmarks.'|t}</label>
|
||||
<textarea name="urls" id="urls" rows="5" class="form-control" placeholder="https://site1.com https://site2.com"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="tags">{'Tags'|t}</label>
|
||||
<input type="text" name="tags" id="tags" class="form-control lf_input" data-list="{loop="$tags"}{$key}, {/loop}" data-multiple data-autofirst autocomplete="off" placeholder="tags, separated, by, commas">
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="private" value="0">
|
||||
<div class="form-group checkbox-wrapper">
|
||||
<input type="checkbox" name="private" {if="$default_private_links"} checked="checked"{/if} id="lf_private" style="width: auto;"/>
|
||||
<label for="lf_private" style="margin: 0;">{'Private'|t}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer">
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
<button type="submit" class="btn btn-primary">{'Add links'|t}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="changepassword"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div class="container page-changepassword">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<form method="POST" action="#" name="changepasswordform" id="changepasswordform">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Change password'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="oldpassword">{'Current password'|t}</label>
|
||||
<input type="password" name="oldpassword" id="oldpassword" class="form-control autofocus">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="setpassword">{'New password'|t}</label>
|
||||
<input type="password" name="setpassword" id="setpassword" class="form-control">
|
||||
</div>
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" name="Save" class="btn btn-primary">{'Change'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="changetag"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div class="container page-changetag">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<form method="POST" action="" name="changetag" id="changetag">
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{"Manage tags"|t}</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted" style="margin-bottom: 1.5rem;">All modifications are case sensitive.</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="fromtag">Modify this tag…</label>
|
||||
<input type="text" name="fromtag" id="fromtag" value="{$fromtag}" class="form-control autofocus"
|
||||
autocomplete="off" data-multiple data-minChars="1"
|
||||
data-list="{loop="$tags"}{$key}, {/loop}" placeholder="Old tag"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="totag">…into this tag</label>
|
||||
<input type="text" name="totag" id="totag" class="form-control" placeholder="New tag">
|
||||
</div>
|
||||
<p class="text-muted" style="font-size: 0.9rem;">
|
||||
{'You can also edit tags in the'|t} <a href="{$base_path}/tags/list?sort=usage">{'tag list'|t}</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" id="button-delete" name="deletetag" class="btn btn-danger" value="Delete tag">{'Delete tag'|t}</button>
|
||||
<button type="submit" name="renametag" class="btn btn-primary" value="Rename tag">{'Rename tag'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<form method="POST" action="{$base_path}/admin/tags/change-separator" name="changeseparator" id="changeseparator">
|
||||
<div class="card">
|
||||
<div class="card-header">{"Change tags separator"|t}</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted" style="margin-bottom: 1rem;">
|
||||
{'Your current tag separator is'|t} <code>{$tags_separator}</code>{if="!empty($tags_separator_desc)"} ({$tags_separator_desc}){/if}.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="separator">{'New separator'|t}</label>
|
||||
<input type="text" name="separator" id="separator" class="form-control" autocomplete="off"/>
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
</div>
|
||||
<p class="text-warning" style="font-size: 0.9rem; margin-top: 1rem;">
|
||||
<i class="mdi mdi-alert"></i> {'Note that hashtags won\'t fully work with a non-whitespace separator.'|t}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" name="saveseparator" class="btn btn-primary">{'Save'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,216 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="configure"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div class="container page-configure">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<form method="POST" action="#" name="configform" id="configform">
|
||||
<input type="hidden" name="token" value="{$token}"/>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{'Configuration'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="title">Shaarli {'title'|t}</label>
|
||||
<input type="text" name="title" id="title" class="form-control" value="{$title}" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="titleLink">{'Home link'|t}</label>
|
||||
<input type="text" name="titleLink" id="titleLink" class="form-control" value="{$titleLink}">
|
||||
<div class="sublabel">{'Default value'|t}: {$base_path}/</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="theme">{'Theme'|t}</label>
|
||||
<select name="theme" id="theme" class="form-control">
|
||||
{loop="$theme_available"}
|
||||
<option value="{$value}" {if="$value === $theme"}selected{/if}>
|
||||
{$value|ucfirst}
|
||||
</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="formatter">{'Description formatter'|t}</label>
|
||||
<select name="formatter" id="formatter" class="form-control">
|
||||
{loop="$formatter_available"}
|
||||
<option value="{$value}" {if="$value === $formatter"}selected="selected"{/if}>
|
||||
{$value|ucfirst}
|
||||
</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="language">{'Language'|t}</label>
|
||||
<select name="language" id="language" class="form-control">
|
||||
{loop="$languages"}
|
||||
<option value="{$key}" {if="$key === $language"}selected{/if}>
|
||||
{$value|ucfirst}
|
||||
</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">{'Timezone'|t}</label>
|
||||
<div class="row">
|
||||
<div class="col-sm-6" id="timezone-continent">
|
||||
<select name="continent" id="continent" class="form-control">
|
||||
{loop="$continents"}
|
||||
{if="$key !== 'selected'"}
|
||||
<option value="{$value}" {if="$continents.selected === $value"}selected{/if}>
|
||||
{$value}
|
||||
</option>
|
||||
{/if}
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-6" id="timezone-city">
|
||||
<select name="city" id="city" class="form-control">
|
||||
{loop="$cities"}
|
||||
{if="$key !== 'selected'"}
|
||||
<option value="{$value.city}" {if="$cities.selected === $value.city"}selected{/if} data-continent="{$value.continent}">
|
||||
{$value.city}
|
||||
</option>
|
||||
{/if}
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{'Parameters'|t}</div>
|
||||
<div class="card-body">
|
||||
<!-- Session Protection -->
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'Disable session cookie hijacking protection'|t}</div>
|
||||
<div class="sublabel">{'Check this if you get disconnected or if your IP address changes often'|t}</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="disablesessionprotection" id="disablesessionprotection" {if="$session_protection_disabled"}checked{/if}/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Private Links -->
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'Private links by default'|t}</div>
|
||||
<div class="sublabel">{'All new links are private by default'|t}</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="privateLinkByDefault" id="privateLinkByDefault" {if="$private_links_default"}checked{/if}/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- RSS Permalinks -->
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'RSS direct links'|t}</div>
|
||||
<div class="sublabel">Enabling it will show a permalink in the description.</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="enableRssPermalinks" id="enableRssPermalinks" {if="$enable_rss_permalinks"}checked{/if}/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Hide Public Links -->
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'Hide public links'|t}</div>
|
||||
<div class="sublabel">{'Do not show any links if the user is not logged in'|t}</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="hidePublicLinks" id="hidePublicLinks" {if="$hide_public_links"}checked{/if}/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Retrieve Description -->
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'Automatically retrieve description'|t}</div>
|
||||
<div class="sublabel">{'Shaarli will try to retrieve the description from meta HTML headers'|t}</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="retrieveDescription" id="retrieveDescription" {if="$retrieve_description"}checked{/if}/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Update Check -->
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'Check updates'|t}</div>
|
||||
<div class="sublabel">{'Notify me when a new release is ready'|t}</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="updateCheck" id="updateCheck" {if="$enable_update_check"}checked{/if}/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- API -->
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'Enable REST API'|t}</div>
|
||||
<div class="sublabel">{'Allow third party software to use Shaarli'|t}</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="enableApi" id="enableApi" {if="$api_enabled"}checked{/if}/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="apiSecret">{'API secret'|t}</label>
|
||||
<input type="text" name="apiSecret" id="apiSecret" class="form-control" value="{$api_secret}" placeholder="Type a random string..." />
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="enableThumbnails">{'Enable thumbnails'|t}</label>
|
||||
<select name="enableThumbnails" id="enableThumbnails" class="form-control">
|
||||
<option value="all" {if="$thumbnails_mode=='all'"}selected{/if}>{'All'|t}</option>
|
||||
<option value="common" {if="$thumbnails_mode=='common'"}selected{/if}>{'Only common media hosts'|t}</option>
|
||||
<option value="none" {if="$thumbnails_mode=='none'"}selected{/if}>{'None'|t}</option>
|
||||
</select>
|
||||
<div class="sublabel">
|
||||
{if="! $gd_enabled"}
|
||||
{'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t}
|
||||
{elseif="$thumbnails_enabled"}
|
||||
<a href="{$base_path}/admin/thumbnails">{'Synchronize thumbnails'|t}</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" name="Save" class="btn btn-primary">{'Save'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,118 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="daily"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body class="dark-toolbar">
|
||||
{include="page.header"}
|
||||
|
||||
<div class="subheader is-dark" style="margin-bottom: 1.5rem;">
|
||||
<div class="container text-center">
|
||||
<div class="btn-group" role="group">
|
||||
<a class="btn {if="array_key_exists('day', $_GET) || (!array_key_exists('week', $_GET) && !array_key_exists('month', $_GET))"}btn-primary{else}btn-secondary{/if}" href="{$base_path}/daily?day" title="{'Daily'|t}">{'Daily'|t}</a>
|
||||
<a class="btn {if="array_key_exists('week', $_GET)"}btn-primary{else}btn-secondary{/if}" href="{$base_path}/daily?week" title="{'Weekly'|t}">{'Weekly'|t}</a>
|
||||
<a class="btn {if="array_key_exists('month', $_GET)"}btn-primary{else}btn-secondary{/if}" href="{$base_path}/daily?month" title="{'Monthly'|t}">{'Monthly'|t}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="daily">
|
||||
<div id="plugin_zone_start_picwall" class="plugin_zone">
|
||||
{loop="$plugin_start_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
|
||||
<div class="daily-header">
|
||||
<h1>{$localizedType} Shaarli</h1>
|
||||
<p class="daily-header-subtitle">{function="t('All links of one :type in a single page.', '', 1, 'shaarli', [':type' => t($type)])"}</p>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<a {if="$previousday"}href="{$base_path}/daily?{$type}={$previousday}"{else}href="#"{/if} class="btn btn-secondary" {if="!$previousday"}disabled{/if}>
|
||||
<i class="mdi mdi-arrow-left"></i> {function="t('Previous :type', '', 1, 'shaarli', [':type' => t($type)], true)"}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-6 text-right">
|
||||
<a {if="$nextday"}href="{$base_path}/daily?{$type}day={$nextday}"{else}href="#"{/if} class="btn btn-secondary" {if="!$nextday"}disabled{/if}>
|
||||
{function="t('Next :type', '', 1, 'shaarli', [':type' => t($type)], true)"} <i class="mdi mdi-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="darker">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="daily-title">{$dayDesc}</h2>
|
||||
|
||||
<div id="plugin_zone_about_daily" class="plugin_zone">
|
||||
{loop="$daily_about_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
|
||||
{if="$linksToDisplay"}
|
||||
<div class="daily-grid clearfix" data-columns>
|
||||
{loop="$linksToDisplay"}
|
||||
{$link=$value}
|
||||
<div class="daily-item">
|
||||
<div class="daily-card">
|
||||
<a href="{$link.real_url}" class="daily-item-header ripple ripple-primary">
|
||||
{$link.title}
|
||||
</a>
|
||||
|
||||
{if="$thumbnails_enabled && !empty($link.thumbnail)"}
|
||||
<div class="daily-item-image" style="background-image: url({$root_path}/{$link.thumbnail}#)"></div>
|
||||
{/if}
|
||||
|
||||
{if="$link.formatedDescription"}
|
||||
<div class="daily-item-body">
|
||||
{$link.formatedDescription}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="daily-item-footer clearfix">
|
||||
{if="!$hide_timestamps || $is_logged_in"}
|
||||
<a href="{$base_path}/shaare/{$value.shorturl}" class="daily-item-footer-subtitle" title="{'Permalink'|t}">
|
||||
{if="$type === 'week'"}
|
||||
{function="strftime('%a %e %b, %H:%M', $link.timestamp)"}
|
||||
{else}
|
||||
{if="$type === 'month'"}
|
||||
{function="strftime('%a %e %b %Y, %H:%M', $link.timestamp)"}
|
||||
{else}
|
||||
{function="strftime('%H:%M', $link.timestamp)"}
|
||||
{/if}
|
||||
{/if}
|
||||
</a>
|
||||
{/if}
|
||||
{if="$link.tags"}
|
||||
<div class="daily-item-tags">
|
||||
{$tags=implode(', ', $link['taglist'])}
|
||||
{$tags}
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
{loop="$link.link_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/loop}
|
||||
</div>
|
||||
{else}
|
||||
<div>No articles on this day.</div>
|
||||
{/if}
|
||||
|
||||
<div id="plugin_zone_end_picwall" class="plugin_zone">
|
||||
{loop="$plugin_end_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>{$localizedType} - {$title}</title>
|
||||
<link>{$index_url}</link>
|
||||
<description>{function="t('All links of one :type in a single page.', '', 1, 'shaarli', [':type' => t($type)])"}</description>
|
||||
<language>{$language}</language>
|
||||
<copyright>{$index_url}</copyright>
|
||||
<generator>Shaarli</generator>
|
||||
|
||||
{loop="$days"}
|
||||
<item>
|
||||
<title>{$value.date_human} - {$title}</title>
|
||||
<guid>{$value.absolute_url}</guid>
|
||||
<link>{$value.absolute_url}</link>
|
||||
<pubDate>{$value.date_rss}</pubDate>
|
||||
<description><![CDATA[
|
||||
{loop="$value.links"}
|
||||
<h3><a href="{$value.url}">{$value.title}</a></h3>
|
||||
<small>
|
||||
{if="!$hide_timestamps"}{$value.created|format_date} — {/if}
|
||||
<a href="{$index_url}shaare/{$value.shorturl}">{'Permalink'|t}</a>
|
||||
{if="$value.tags"} — {$value.tags}{/if}
|
||||
<br>
|
||||
{$value.url}
|
||||
</small><br>
|
||||
{if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
|
||||
{if="$value.description"}{$value.description}{/if}
|
||||
<br><hr>
|
||||
{/loop}
|
||||
]]></description>
|
||||
</item>
|
||||
{/loop}
|
||||
</channel>
|
||||
</rss><!-- Cached version of {$page_url} -->
|
||||
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="editlinkbatch"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body class="page-edit-link-batch">
|
||||
{include="page.header"}
|
||||
|
||||
<div id="progress-overlay" class="fullscreen hidden">
|
||||
<div class="content-fullscreen">
|
||||
<div class="container">
|
||||
<div class="mbl row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="is-inverted">
|
||||
<div class="progress-counter">
|
||||
<span class="progress-current">0</span> / <span class="progress-total"></span>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-actual"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center" style="margin: 1.5rem 0;">
|
||||
<button type="submit" name="save_edit_batch" class="btn btn-primary">{'Save all'|t}</button>
|
||||
</div>
|
||||
|
||||
{loop="$links"}
|
||||
{$index=$key}
|
||||
{include="editlink"}
|
||||
{/loop}
|
||||
|
||||
<div class="text-center" style="margin: 1.5rem 0;">
|
||||
<button type="submit" name="save_edit_batch" class="btn btn-primary">{'Save all'|t}</button>
|
||||
</div>
|
||||
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,97 @@
|
||||
{if="empty($batch_mode)"}
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="editlink"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body {if="!empty($_GET['source']) && $_GET['source']=='bookmarklet'"}class="from-bookmarklet"{/if}>
|
||||
{include="page.header"}
|
||||
{else}
|
||||
{ignore}Lil hack: when included in a loop in batch mode, `$value` is assigned by RainTPL with template vars.{/ignore}
|
||||
{function="extract($value) ? '' : ''"}
|
||||
{/if}
|
||||
{$asyncLoadClass=$link_is_new && $async_metadata && empty($link.title) ? 'loading-wrapper' : ''}
|
||||
{if="!isset($index)"}
|
||||
{$index=""}
|
||||
{/if}
|
||||
<div id="editlinkform{$index}" class="editlinkform container page-edit">
|
||||
<div class="row editlinkform-row">
|
||||
<div class="col-md-6 col-md-offset-3 editlinkform-col">
|
||||
<form method="post" name="linkform" class="card" action="{$base_path}/admin/shaare">
|
||||
{if="isset($link.id)"}
|
||||
<input type="hidden" name="lf_id" value="{$link.id}">
|
||||
{/if}
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
<input type="hidden" name="source" value="{$source}">
|
||||
{if="$http_referer"}
|
||||
<input type="hidden" name="returnurl" value="{$http_referer}">
|
||||
{/if}
|
||||
|
||||
<div class="card-header">
|
||||
{if="!$link_is_new"}Edit Bookmark{else}New Bookmark{/if}
|
||||
{if="!$link_is_new"}<span class="card-subheader" style="font-size:0.85rem; color:var(--text-muted); font-weight:normal;"> - {'created on'|t} {$link.created|format_date}</span>{/if}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="lf_url{$index}">{'URL'|t}</label>
|
||||
<input type="text" class="form-control" name="lf_url" id="lf_url{$index}" value="{$link.url}" placeholder="https://...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="lf_title{$index}">{'Title'|t}</label>
|
||||
<div class="{$asyncLoadClass}">
|
||||
<input type="text" class="form-control" name="lf_title" id="lf_title{$index}" {if="empty($batch_mode) && $link.title==''"}class="autofocus form-control"{else}class="form-control"{/if} value="{$link.title}" placeholder="Page title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="lf_description{$index}">{'Description'|t}</label>
|
||||
<div class="{$asyncLoadClass}">
|
||||
<textarea class="form-control" name="lf_description" id="lf_description{$index}" {if="empty($batch_mode) && $link.description==''"}class="autofocus form-control"{/if} placeholder="Add a description..." rows="5">{$link.description}</textarea>
|
||||
</div>
|
||||
{if="$formatter==='markdown'"}
|
||||
<div class="sublabel">
|
||||
{'Description will be rendered with'|t} <a href="http://daringfireball.net/projects/markdown/syntax" target="_blank" rel="noopener">{'Markdown syntax'|t}</a>.
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="lf_tags{$index}">{'Tags'|t}</label>
|
||||
<div class="{$asyncLoadClass}">
|
||||
<input type="text" class="form-control" id="lf_tags{$index}" name="lf_tags" {if="empty($batch_mode)"}class="autofocus form-control"{/if} value="{$link.tags}"
|
||||
data-list="{loop="$tags"}{$key}, {/loop}" data-multiple autocomplete="off" placeholder="tags, separated, by, commas" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if="isset($edit_link_plugin)"}
|
||||
{loop="$edit_link_plugin"}
|
||||
<div class="form-group">
|
||||
{$value}
|
||||
</div>
|
||||
{/loop}
|
||||
{/if}
|
||||
|
||||
<div class="form-group checkbox-wrapper">
|
||||
<input type="checkbox" {if="$link.private === true"}checked="checked"{/if} name="lf_private" id="lf_private{$index}" style="width:auto;"/>
|
||||
<label for="lf_private{$index}" style="margin:0;">{'Private bookmark'|t}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
{if="!empty($batch_mode)"}
|
||||
<button type="button" name="cancel-batch-link" class="btn btn-secondary">{'Cancel'|t}</button>
|
||||
{/if}
|
||||
{if="!$link_is_new"}
|
||||
<a href="{$base_path}/admin/shaare/delete?id={$link.id}&token={$token}"
|
||||
onclick="return confirm('Delete this bookmark?');"
|
||||
class="btn btn-danger">{'Delete'|t}</a>
|
||||
{/if}
|
||||
<button type="submit" name="save_edit" class="btn btn-primary">{'Save'|t}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{if="empty($batch_mode)"}
|
||||
{include="page.footer"}
|
||||
{/if}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="error"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
<div id="pageError" class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header" style="background-color: var(--danger); color: white;">
|
||||
<i class="mdi mdi-alert-circle"></i> {'Error'|t}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h2 style="color: var(--text-main); margin-bottom: 1rem;">{$message}</h2>
|
||||
{if="!empty($text)"}
|
||||
<p class="text-muted">{$text}</p>
|
||||
{/if}
|
||||
{if="!empty($stacktrace)"}
|
||||
<div style="margin-top: 1.5rem;">
|
||||
<strong>Stack Trace:</strong>
|
||||
<pre style="background: var(--bg-body); padding: 1rem; border-radius: 0.375rem; border: 1px solid var(--border); overflow-x: auto; margin-top: 0.5rem;">{$stacktrace}</pre>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a href="{$base_path}/" class="btn btn-primary">{'Home'|t}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE NETSCAPE-Bookmark-file-1>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
|
||||
<!-- This is an automatically generated file.
|
||||
It will be read and overwritten.
|
||||
Do Not Edit! -->{ignore}The RainTPL loop is formatted to avoid generating extra newlines{/ignore}
|
||||
<TITLE>{$pagetitle}</TITLE>
|
||||
<H1>Shaarli export of {$selection} bookmarks on {$date}</H1>
|
||||
<DL><p>{loop="links"}
|
||||
<DT><A HREF="{$value.url}" ADD_DATE="{$value.timestamp}" PRIVATE="{$value.private}" TAGS="{$value.taglist}">{$value.title}</A>{if="$value.description"}{$eol}<DD>{$value.description}{/if}{/loop}
|
||||
</DL><p>
|
||||
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="export"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div id="toolsdiv" class="container page-export">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<form method="post" action="{$base_path}/admin/export">
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{"Export Database"|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="filter-toggle-row">
|
||||
<div>
|
||||
<div class="filter-toggle-label">{'Prepend note permalinks with this Shaarli instance\'s URL'|t}</div>
|
||||
<div class="sublabel">{'Useful to import bookmarks in a web browser'|t}</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="prepend_note_url" id="prepend_note_url"/>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<hr style="margin: 1.5rem 0; border-top: 1px solid var(--border);">
|
||||
|
||||
<h3 style="font-size: 1.1rem; font-weight: 600; color: var(--text-main); margin-bottom: 1rem;">Selection</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="radio-group">
|
||||
<div class="form-group checkbox-wrapper" style="margin-bottom: 0.5rem;">
|
||||
<input name="selection" type="radio" value="all" id="selection-all" checked style="width: auto;" />
|
||||
<label for="selection-all" style="margin: 0;">
|
||||
<strong>Export all</strong> <span class="text-muted">- Export all links</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group checkbox-wrapper" style="margin-bottom: 0.5rem;">
|
||||
<input name="selection" type="radio" value="public" id="selection-public" style="width: auto;" />
|
||||
<label for="selection-public" style="margin: 0;">
|
||||
<strong>Export public</strong> <span class="text-muted">- Export public links only</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group checkbox-wrapper">
|
||||
<input name="selection" type="radio" value="private" id="selection-private" style="width: auto;" />
|
||||
<label for="selection-private" style="margin: 0;">
|
||||
<strong>Export private</strong> <span class="text-muted">- Export private links only</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary">{'Export'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>{$pagetitle}</title>
|
||||
<subtitle>Shaared links</subtitle>
|
||||
{if="$show_dates"}
|
||||
<updated>{$last_update}</updated>
|
||||
{/if}
|
||||
<link rel="self" href="{$self_link}#" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="{$index_url}open-search#"
|
||||
title="Shaarli search - {$shaarlititle}" />
|
||||
{loop="$plugins_feed_header"}
|
||||
{$value}
|
||||
{/loop}
|
||||
<author>
|
||||
<name>{$pagetitle}</name>
|
||||
<uri>{$index_url}</uri>
|
||||
</author>
|
||||
<id>{$index_url}</id>
|
||||
<generator>Shaarli</generator>
|
||||
{loop="$links"}
|
||||
<entry>
|
||||
<title>{$value.title}</title>
|
||||
{if="$usepermalinks"}
|
||||
<link href="{$value.guid}#" />
|
||||
{else}
|
||||
<link href="{$value.url}#" />
|
||||
{/if}
|
||||
<id>{$value.guid}</id>
|
||||
{if="$show_dates"}
|
||||
<published>{$value.pub_iso_date}</published>
|
||||
<updated>{$value.up_iso_date}</updated>
|
||||
{/if}
|
||||
<content type="html" xml:lang="{$language}"><![CDATA[{$value.description}]]></content>
|
||||
{loop="$value.taglist"}
|
||||
<category scheme="{$index_url}?searchtags=" term="{$value|strtolower}" label="{$value}" />
|
||||
{/loop}
|
||||
{loop="$value.feed_plugins"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</entry>
|
||||
{/loop}
|
||||
</feed>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{$pagetitle}</title>
|
||||
<link>{$index_url}</link>
|
||||
<description>Shaared links</description>
|
||||
<language>{$language}</language>
|
||||
<copyright>{$index_url}</copyright>
|
||||
<generator>Shaarli</generator>
|
||||
<atom:link rel="self" href="{$self_link}" />
|
||||
<atom:link rel="search" type="application/opensearchdescription+xml" href="{$index_url}open-search#"
|
||||
title="Shaarli search - {$shaarlititle}" />
|
||||
{loop="$plugins_feed_header"}
|
||||
{$value}
|
||||
{/loop}
|
||||
{loop="$links"}
|
||||
<item>
|
||||
<title>{$value.title}</title>
|
||||
<guid isPermaLink="{if="$usepermalinks"}true{else}false{/if}">{$value.guid}</guid>
|
||||
{if="$usepermalinks"}
|
||||
<link>{$value.guid}</link>
|
||||
{else}
|
||||
<link>{$value.url}</link>
|
||||
{/if}
|
||||
{if="$show_dates"}
|
||||
<pubDate>{$value.pub_iso_date}</pubDate>
|
||||
<atom:modified>{$value.up_iso_date}</atom:modified>
|
||||
{/if}
|
||||
<description><![CDATA[{$value.description}]]></description>
|
||||
{loop="$value.taglist"}
|
||||
<category domain="{$index_url}?searchtags=">{$value}</category>
|
||||
{/loop}
|
||||
{loop="$value.feed_plugins"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</item>
|
||||
{/loop}
|
||||
</channel>
|
||||
</rss>
|
||||
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="import"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div id="uploaddiv" class="container page-import">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<form method="post" action="{$base_path}/admin/import" enctype="multipart/form-data" name="uploadform" id="uploadform">
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
<input type="hidden" name="MAX_FILE_SIZE" value="{$maxfilesize}">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{"Import Database"|t}</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted" style="margin-bottom: 1.5rem;">
|
||||
Import Netscape HTML bookmarks (as exported from Firefox/Chrome/Opera/Delicious/Diigo...).
|
||||
</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="filetoupload">File to upload</label>
|
||||
<input type="file" id="filetoupload" name="filetoupload" class="form-control" style="height: auto; padding: 0.5rem;"/>
|
||||
<div class="sublabel">{'Maximum size allowed:'|t} <strong>{$maxfilesizeHuman}</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group checkbox-wrapper">
|
||||
<input type="checkbox" name="overwrite" id="overwrite" style="width: auto;">
|
||||
<label for="overwrite" style="margin: 0;">{'Overwrite existing bookmarks'|t}</label>
|
||||
</div>
|
||||
|
||||
<hr style="margin: 1.5rem 0; border-top: 1px solid var(--border);">
|
||||
|
||||
<h3 style="font-size: 1.1rem; font-weight: 600; color: var(--text-main); margin-bottom: 1rem;">Privacy Settings</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="radio-group">
|
||||
<div class="form-group checkbox-wrapper" style="margin-bottom: 0.5rem;">
|
||||
<input name="privacy" type="radio" value="default" id="privacy-default" checked style="width: auto;" />
|
||||
<label for="privacy-default" style="margin: 0;">
|
||||
<strong>Default</strong> <span class="text-muted">- {'Use values from the imported file, default to public'|t}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group checkbox-wrapper" style="margin-bottom: 0.5rem;">
|
||||
<input name="privacy" type="radio" value="private" id="privacy-private" style="width: auto;" />
|
||||
<label for="privacy-private" style="margin: 0;">
|
||||
<strong>Private</strong> <span class="text-muted">- {'Import all bookmarks as private'|t}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group checkbox-wrapper">
|
||||
<input name="privacy" type="radio" value="public" id="privacy-public" style="width: auto;" />
|
||||
<label for="privacy-public" style="margin: 0;">
|
||||
<strong>Public</strong> <span class="text-muted">- {'Import all bookmarks as public'|t}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="default-tags">{'Add default tags'|t}</label>
|
||||
<input type="text" name="default_tags" id="default-tags" class="form-control" placeholder="Separate tags with comma...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer">
|
||||
<button type="submit" name="import_file" class="btn btn-primary">{'Import'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,41 @@
|
||||
<title>{$pagetitle}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="referrer" content="same-origin">
|
||||
<link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$searchcrits}#" title="RSS Feed" />
|
||||
<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#"
|
||||
title="Shaarli search - {$shaarlititle}" />
|
||||
|
||||
<!-- Professional Theme CSS -->
|
||||
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/style.css#" />
|
||||
|
||||
<!-- Icons (Material Design Icons) -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/MaterialDesign-Webfont/7.2.96/css/materialdesignicons.min.css">
|
||||
|
||||
<!-- Theme Color -->
|
||||
<meta name="theme-color" content="#2563eb">
|
||||
|
||||
<!-- Plugins CSS -->
|
||||
{loop="$plugins_includes.css_files"}
|
||||
<link type="text/css" rel="stylesheet" href="{$root_path}/{$value}#" />
|
||||
{/loop}
|
||||
|
||||
{if="is_file('data/user.css')"}
|
||||
<link type="text/css" rel="stylesheet" href="{$root_path}/data/user.css#" />
|
||||
{/if}
|
||||
|
||||
<script>
|
||||
var shaarli = {
|
||||
basePath: '{$base_path}',
|
||||
rootPath: '{$root_path}',
|
||||
assetPath: '{$asset_path}',
|
||||
isAuth: {if="$is_logged_in"}true{else}false{/if},
|
||||
pageName: '{$pageName}'
|
||||
};
|
||||
</script>
|
||||
<script src="{$asset_path}/js/script.js#" defer></script>
|
||||
|
||||
{if="file_exists('tpl/shaarli-pro/extra.html')"}
|
||||
{include="extra"}
|
||||
{/if}
|
||||
@@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="install"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
<div id="install" class="page-install">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<form method="post" action="{$base_path}/install" name="installform" id="installform">
|
||||
<div class="card">
|
||||
<div class="card-header">Welcome to your Shaarli</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted" style="margin-bottom: 1.5rem;">{'It looks like it\'s the first time you run Shaarli. Please configure it.'|t}</p>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="setlogin">{'Username'|t}</label>
|
||||
<input type="text" name="setlogin" id="setlogin" class="form-control autofocus"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="setpassword">{'Password'|t}</label>
|
||||
<input type="password" id="setpassword" name="setpassword" class="form-control"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="continent">{'Timezone'|t}</label>
|
||||
<div class="row">
|
||||
<div class="col-sm-6" id="timezone-continent">
|
||||
<select name="continent" id="continent" class="form-control">
|
||||
{loop="$continents"}
|
||||
{if="$key !== 'selected'"}
|
||||
<option value="{$value}" {if="$continents.selected === $value"}selected{/if}>
|
||||
{$value}
|
||||
</option>
|
||||
{/if}
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-6" id="timezone-city">
|
||||
<select name="city" id="city" class="form-control">
|
||||
{loop="$cities"}
|
||||
{if="$key !== 'selected'"}
|
||||
<option value="{$value.city}" {if="$cities.selected === $value.city"}selected{/if} data-continent="{$value.continent}">
|
||||
{$value.city}
|
||||
</option>
|
||||
{/if}
|
||||
{/loop}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="title">{'Shaarli title'|t}</label>
|
||||
<input type="text" name="title" id="title" class="form-control" placeholder="{'My links'|t}"/>
|
||||
</div>
|
||||
<div class="form-group checkbox-wrapper">
|
||||
<input type="checkbox" name="updateCheck" id="updateCheck" checked="checked" style="width: auto;">
|
||||
<label for="updateCheck" style="margin: 0;">{'Notify me when a new release is ready'|t}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox-wrapper">
|
||||
<input type="checkbox" name="enableApi" id="enableApi" style="width: auto;">
|
||||
<label for="enableApi" style="margin: 0;">{'Enable REST API'|t}</label>
|
||||
</div>
|
||||
<div class="sublabel" style="margin-left: 1.5rem;">{'Allow third party software to use Shaarli such as mobile application'|t}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" name="Save" class="btn btn-primary">{'Install'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include="server.requirements"}
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,456 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// ===== Theme Toggle =====
|
||||
const themeCheckbox = document.getElementById('theme-toggle-checkbox');
|
||||
const themeIconLight = document.getElementById('theme-icon-light');
|
||||
const themeLabelSpan = document.querySelector('.theme-toggle-label span');
|
||||
|
||||
function updateTheme(theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem('theme', theme);
|
||||
|
||||
if (themeCheckbox) {
|
||||
themeCheckbox.checked = theme === 'dark';
|
||||
}
|
||||
if (themeIconLight) {
|
||||
themeIconLight.className = theme === 'dark' ? 'mdi mdi-weather-night' : 'mdi mdi-weather-sunny';
|
||||
}
|
||||
if (themeLabelSpan) {
|
||||
themeLabelSpan.textContent = theme === 'dark' ? 'Dark Mode' : 'Light Mode';
|
||||
}
|
||||
}
|
||||
|
||||
// Init Theme
|
||||
const savedTheme = localStorage.getItem('theme') ||
|
||||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
updateTheme(savedTheme);
|
||||
|
||||
if (themeCheckbox) {
|
||||
themeCheckbox.addEventListener('change', () => {
|
||||
const next = themeCheckbox.checked ? 'dark' : 'light';
|
||||
updateTheme(next);
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Mobile Sidebar Toggle =====
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
||||
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
|
||||
|
||||
function toggleSidebar() {
|
||||
sidebar?.classList.toggle('show');
|
||||
sidebarOverlay?.classList.toggle('show');
|
||||
}
|
||||
|
||||
mobileMenuBtn?.addEventListener('click', toggleSidebar);
|
||||
sidebarOverlay?.addEventListener('click', toggleSidebar);
|
||||
|
||||
// ===== Search Overlay =====
|
||||
const searchOverlay = document.getElementById('search-overlay');
|
||||
const searchToggleBtn = document.getElementById('search-toggle-btn');
|
||||
const searchModalInput = document.getElementById('search-modal-input');
|
||||
|
||||
function openSearch() {
|
||||
searchOverlay?.classList.add('show');
|
||||
setTimeout(() => searchModalInput?.focus(), 100);
|
||||
}
|
||||
|
||||
function closeSearch() {
|
||||
searchOverlay?.classList.remove('show');
|
||||
}
|
||||
|
||||
searchToggleBtn?.addEventListener('click', openSearch);
|
||||
|
||||
// Close search on overlay click
|
||||
searchOverlay?.addEventListener('click', (e) => {
|
||||
if (e.target === searchOverlay) {
|
||||
closeSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard shortcut: S to open search, ESC to close
|
||||
document.addEventListener('keydown', (e) => {
|
||||
// Don't trigger if typing in an input
|
||||
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
|
||||
if (e.key === 'Escape') {
|
||||
closeSearch();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.key === 's' || e.key === 'S') {
|
||||
e.preventDefault();
|
||||
openSearch();
|
||||
}
|
||||
if (e.key === 'Escape') {
|
||||
closeSearch();
|
||||
closeFilterPanel();
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Filter Panel =====
|
||||
const filterToggleBtn = document.getElementById('filter-toggle-btn');
|
||||
const filterPanel = document.getElementById('filter-panel');
|
||||
const filterCloseBtn = document.getElementById('filter-close-btn');
|
||||
const filterPrivate = document.getElementById('filter-private');
|
||||
const filterPublic = document.getElementById('filter-public');
|
||||
const filterUntagged = document.getElementById('filter-untagged');
|
||||
|
||||
function toggleFilterPanel() {
|
||||
filterPanel?.classList.toggle('show');
|
||||
}
|
||||
|
||||
function closeFilterPanel() {
|
||||
filterPanel?.classList.remove('show');
|
||||
}
|
||||
|
||||
filterToggleBtn?.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
toggleFilterPanel();
|
||||
});
|
||||
|
||||
filterCloseBtn?.addEventListener('click', closeFilterPanel);
|
||||
|
||||
// Close filter when clicking outside
|
||||
document.addEventListener('click', (e) => {
|
||||
if (filterPanel?.classList.contains('show')) {
|
||||
if (!filterPanel.contains(e.target) && e.target !== filterToggleBtn) {
|
||||
closeFilterPanel();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle filter toggle switches - using data-url like the example
|
||||
document.querySelectorAll('.toggle-switch input[type="checkbox"]').forEach(checkbox => {
|
||||
checkbox.addEventListener('change', (e) => {
|
||||
const label = e.target.closest('label');
|
||||
if (label && label.dataset.url) {
|
||||
window.location.href = label.dataset.url;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle links per page options
|
||||
|
||||
|
||||
// Handle custom value form submission
|
||||
const filterInput = document.querySelector('.filter-input');
|
||||
if (filterInput) {
|
||||
filterInput.closest('form')?.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const value = filterInput.value;
|
||||
if (value && value > 0) {
|
||||
window.location.href = shaarli.basePath + '/?nb=' + value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ===== View Toggle (Grid/List/Compact) =====
|
||||
const linksList = document.getElementById('links-list');
|
||||
const viewGridBtn = document.getElementById('view-grid-btn');
|
||||
const viewListBtn = document.getElementById('view-list-btn');
|
||||
const viewCompactBtn = document.getElementById('view-compact-btn');
|
||||
|
||||
function setView(view) {
|
||||
if (!linksList) return;
|
||||
|
||||
// Remove all view classes
|
||||
linksList.classList.remove('view-grid', 'view-list', 'view-compact');
|
||||
|
||||
// Remove active state from all buttons
|
||||
viewGridBtn?.classList.remove('active');
|
||||
viewListBtn?.classList.remove('active');
|
||||
viewCompactBtn?.classList.remove('active');
|
||||
|
||||
// Apply selected view
|
||||
if (view === 'list') {
|
||||
linksList.classList.add('view-list');
|
||||
viewListBtn?.classList.add('active');
|
||||
} else if (view === 'compact') {
|
||||
linksList.classList.add('view-compact');
|
||||
viewCompactBtn?.classList.add('active');
|
||||
} else {
|
||||
// Default to grid
|
||||
linksList.classList.add('view-grid');
|
||||
viewGridBtn?.classList.add('active');
|
||||
}
|
||||
|
||||
localStorage.setItem('linksView', view);
|
||||
}
|
||||
|
||||
// Init view from localStorage
|
||||
const savedView = localStorage.getItem('linksView') || 'grid';
|
||||
setView(savedView);
|
||||
|
||||
viewGridBtn?.addEventListener('click', () => setView('grid'));
|
||||
viewListBtn?.addEventListener('click', () => setView('list'));
|
||||
viewCompactBtn?.addEventListener('click', () => setView('compact'));
|
||||
|
||||
// ===== Multi-Select Mode =====
|
||||
const selectModeBtn = document.getElementById('select-mode-btn');
|
||||
const bulkActionsBar = document.getElementById('bulk-actions-bar');
|
||||
const bulkCount = document.getElementById('bulk-count');
|
||||
const bulkSelectAll = document.getElementById('bulk-select-all');
|
||||
const bulkCancel = document.getElementById('bulk-cancel');
|
||||
const bulkDelete = document.getElementById('bulk-delete');
|
||||
const bulkPublic = document.getElementById('bulk-public');
|
||||
const bulkPrivate = document.getElementById('bulk-private');
|
||||
|
||||
let selectionMode = false;
|
||||
let selectedIds = new Set();
|
||||
|
||||
function updateBulkUI() {
|
||||
if (bulkCount) {
|
||||
bulkCount.textContent = selectedIds.size;
|
||||
}
|
||||
|
||||
// Update link cards visual state
|
||||
document.querySelectorAll('.link-outer').forEach(card => {
|
||||
const id = card.dataset.id;
|
||||
if (selectedIds.has(id)) {
|
||||
card.classList.add('selected');
|
||||
} else {
|
||||
card.classList.remove('selected');
|
||||
}
|
||||
});
|
||||
|
||||
// Update checkboxes
|
||||
document.querySelectorAll('.link-checkbox').forEach(cb => {
|
||||
cb.checked = selectedIds.has(cb.dataset.id);
|
||||
});
|
||||
}
|
||||
|
||||
function enterSelectionMode() {
|
||||
selectionMode = true;
|
||||
document.body.classList.add('selection-mode');
|
||||
bulkActionsBar?.classList.add('show');
|
||||
selectModeBtn?.classList.add('active');
|
||||
}
|
||||
|
||||
function exitSelectionMode() {
|
||||
selectionMode = false;
|
||||
selectedIds.clear();
|
||||
document.body.classList.remove('selection-mode');
|
||||
bulkActionsBar?.classList.remove('show');
|
||||
selectModeBtn?.classList.remove('active');
|
||||
updateBulkUI();
|
||||
}
|
||||
|
||||
function toggleSelection(id) {
|
||||
if (selectedIds.has(id)) {
|
||||
selectedIds.delete(id);
|
||||
} else {
|
||||
selectedIds.add(id);
|
||||
}
|
||||
|
||||
if (selectedIds.size > 0 && !selectionMode) {
|
||||
enterSelectionMode();
|
||||
} else if (selectedIds.size === 0 && selectionMode) {
|
||||
exitSelectionMode();
|
||||
}
|
||||
|
||||
updateBulkUI();
|
||||
}
|
||||
|
||||
selectModeBtn?.addEventListener('click', () => {
|
||||
if (selectionMode) {
|
||||
exitSelectionMode();
|
||||
} else {
|
||||
enterSelectionMode();
|
||||
}
|
||||
});
|
||||
|
||||
bulkCancel?.addEventListener('click', exitSelectionMode);
|
||||
|
||||
bulkSelectAll?.addEventListener('click', () => {
|
||||
document.querySelectorAll('.link-outer').forEach(card => {
|
||||
if (card.dataset.id) {
|
||||
selectedIds.add(card.dataset.id);
|
||||
}
|
||||
});
|
||||
updateBulkUI();
|
||||
});
|
||||
|
||||
// Handle checkbox clicks
|
||||
document.addEventListener('change', (e) => {
|
||||
if (e.target.classList.contains('link-checkbox')) {
|
||||
toggleSelection(e.target.dataset.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle card clicks in selection mode
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!selectionMode) return;
|
||||
|
||||
const card = e.target.closest('.link-outer');
|
||||
if (card && card.dataset.id) {
|
||||
// Don't toggle if clicking on actions or links
|
||||
if (e.target.closest('.link-actions') ||
|
||||
e.target.closest('.link-hover-actions') ||
|
||||
e.target.tagName === 'A') {
|
||||
return;
|
||||
}
|
||||
toggleSelection(card.dataset.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Bulk actions
|
||||
bulkDelete?.addEventListener('click', () => {
|
||||
if (selectedIds.size === 0) return;
|
||||
if (!confirm(`Delete ${selectedIds.size} bookmark(s)?`)) return;
|
||||
|
||||
// Submit form with selected IDs
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = shaarli.basePath + '/admin/shaare/delete';
|
||||
|
||||
selectedIds.forEach(id => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'id[]';
|
||||
input.value = id;
|
||||
form.appendChild(input);
|
||||
});
|
||||
|
||||
const tokenInput = document.createElement('input');
|
||||
tokenInput.type = 'hidden';
|
||||
tokenInput.name = 'token';
|
||||
tokenInput.value = document.querySelector('input[name="token"]')?.value || '';
|
||||
form.appendChild(tokenInput);
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
});
|
||||
|
||||
bulkPublic?.addEventListener('click', () => {
|
||||
if (selectedIds.size === 0) return;
|
||||
bulkVisibilityChange('public');
|
||||
});
|
||||
|
||||
bulkPrivate?.addEventListener('click', () => {
|
||||
if (selectedIds.size === 0) return;
|
||||
bulkVisibilityChange('private');
|
||||
});
|
||||
|
||||
function bulkVisibilityChange(visibility) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = shaarli.basePath + '/admin/shaare/visibility';
|
||||
|
||||
selectedIds.forEach(id => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'id[]';
|
||||
input.value = id;
|
||||
form.appendChild(input);
|
||||
});
|
||||
|
||||
const visInput = document.createElement('input');
|
||||
visInput.type = 'hidden';
|
||||
visInput.name = 'visibility';
|
||||
visInput.value = visibility;
|
||||
form.appendChild(visInput);
|
||||
|
||||
const tokenInput = document.createElement('input');
|
||||
tokenInput.type = 'hidden';
|
||||
tokenInput.name = 'token';
|
||||
tokenInput.value = document.querySelector('input[name="token"]')?.value || '';
|
||||
form.appendChild(tokenInput);
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
|
||||
// ===== Search Type Toggle =====
|
||||
const searchTagsBtn = document.getElementById('search-tags-btn');
|
||||
const searchAllBtn = document.getElementById('search-all-btn');
|
||||
const searchForm = document.getElementById('search-form');
|
||||
|
||||
searchTagsBtn?.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
searchModalInput.name = 'searchtags';
|
||||
searchAllBtn?.classList.remove('active');
|
||||
searchTagsBtn?.classList.add('active');
|
||||
searchForm?.submit();
|
||||
});
|
||||
|
||||
searchAllBtn?.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
searchModalInput.name = 'searchterm';
|
||||
searchTagsBtn?.classList.remove('active');
|
||||
searchAllBtn?.classList.add('active');
|
||||
searchForm?.submit();
|
||||
});
|
||||
|
||||
// ===== Thumbnail Update =====
|
||||
const thumbnailsPage = document.querySelector('.page-thumbnails');
|
||||
if (thumbnailsPage) {
|
||||
const thumbnailPlaceholder = document.querySelector('.thumbnail-placeholder');
|
||||
const thumbnailTitle = document.querySelector('.thumbnail-link-title');
|
||||
const progressCurrent = document.querySelector('.progress-current');
|
||||
const progressBarActual = document.querySelector('.progress-actual');
|
||||
const idsInput = document.querySelector('input[name="ids"]');
|
||||
|
||||
if (idsInput && idsInput.value) {
|
||||
const thumbnailsIdList = idsInput.value.split(',');
|
||||
const total = thumbnailsIdList.length;
|
||||
let i = 0;
|
||||
|
||||
const updateThumbnail = function (id) {
|
||||
console.log('Updating thumbnail #' + i + ' with id ' + id);
|
||||
|
||||
fetch(shaarli.basePath + '/admin/shaare/' + id + '/update-thumbnail', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
i++;
|
||||
|
||||
if (thumbnailTitle) {
|
||||
thumbnailTitle.textContent = data.title || 'Processing...';
|
||||
}
|
||||
|
||||
if (thumbnailPlaceholder) {
|
||||
if (data.thumbnail) {
|
||||
thumbnailPlaceholder.innerHTML = '<img title="Current thumbnail" src="' + data.thumbnail + '" style="max-width: 100%; height: auto;"/>';
|
||||
} else {
|
||||
thumbnailPlaceholder.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (progressCurrent) {
|
||||
progressCurrent.textContent = i;
|
||||
}
|
||||
|
||||
if (progressBarActual) {
|
||||
progressBarActual.style.width = ((i * 100) / total) + '%';
|
||||
}
|
||||
|
||||
if (i < total) {
|
||||
updateThumbnail(thumbnailsIdList[i]);
|
||||
} else {
|
||||
if (thumbnailTitle) {
|
||||
thumbnailTitle.textContent = 'Thumbnail update done!';
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to update thumbnail:', error);
|
||||
if (thumbnailTitle) {
|
||||
thumbnailTitle.textContent = 'Error updating thumbnail #' + i;
|
||||
}
|
||||
// Continue with next thumbnail even if one fails
|
||||
i++;
|
||||
if (i < total) {
|
||||
updateThumbnail(thumbnailsIdList[i]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Start the update process
|
||||
updateThumbnail(thumbnailsIdList[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="linklist"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div id="linklist">
|
||||
{loop="$plugin_start_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
<div class="content-toolbar">
|
||||
<div class="toolbar-left">{include="linklist.paging"}</div>
|
||||
<div class="toolbar-right">
|
||||
<div class="view-toggle">
|
||||
<button class="view-toggle-btn active" id="view-grid-btn" title="Grid View"><i class="mdi mdi-view-grid"></i></button>
|
||||
<button class="view-toggle-btn" id="view-list-btn" title="List View"><i class="mdi mdi-view-list"></i></button>
|
||||
<button class="view-toggle-btn" id="view-compact-btn" title="Compact View"><i class="mdi mdi-view-headline"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{if="count($links)==0"}
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon"><i class="mdi mdi-bookmark-off-outline"></i></div>
|
||||
<h2 class="empty-state-title">No bookmarks found</h2>
|
||||
<p class="empty-state-text">{if="!empty($search_term)"}No results for: <strong>{$search_term}</strong>{else}Start adding bookmarks to see them here.{/if}</p>
|
||||
</div>
|
||||
{else}
|
||||
<div class="links-list view-grid" id="links-list">
|
||||
{loop="$links"}
|
||||
<div id="{$value.id}" class="link-outer{if="isset($value.sticky) && $value.sticky"} is-sticky{/if}{if="$value.class"} {$value.class}{/if}{if="$value.private"} private{else} public{/if}" data-id="{$value.id}">
|
||||
{if="$is_logged_in"}<div class="link-select-checkbox"><input type="checkbox" class="link-checkbox" data-id="{$value.id}"></div>{/if}
|
||||
{if="$value.thumbnail !== false"}<div class="link-thumbnail"><img src="{$root_path}/{$value.thumbnail}#" loading="lazy" alt="" style="width:100%; height:100%; object-fit:cover;"></div>{/if}
|
||||
<div class="link-visibility-badge">{if="$value.private"}<i class="mdi mdi-lock" title="Private"></i>{else}<i class="mdi mdi-lock-open-variant" title="Public"></i>{/if}</div>
|
||||
{if="$is_logged_in"}
|
||||
<div class="link-hover-actions">
|
||||
<a href="{$base_path}/admin/shaare/{$value.id}" class="link-hover-btn" title="Edit"><i class="mdi mdi-pencil"></i></a>
|
||||
<a href="{$value.real_url}" target="_blank" rel="noopener" class="link-hover-btn" title="Open"><i class="mdi mdi-open-in-new"></i></a>
|
||||
<a href="{$base_path}/admin/shaare/delete?id={$value.id}&token={$token}" class="link-hover-btn" title="Delete" onclick="return confirm('Delete this bookmark?');"><i class="mdi mdi-delete"></i></a>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="link-content">
|
||||
<div class="link-header">
|
||||
<a href="{$value.real_url}" class="link-title"{if="strpos($value.url, $value.shorturl) !== false"} title="Note"{/if}>{if="isset($value.sticky) && $value.sticky"}<i class="mdi mdi-pin" style="color:var(--primary);"></i>{/if}{$value.title_html}</a>
|
||||
<span class="link-url">{$value.url}</span>
|
||||
<div class="link-meta">
|
||||
<span class="link-date">{function="strftime('%c', $value.timestamp)"}</span>
|
||||
<a href="{$base_path}/shaare/{$value.shorturl}" class="link-permalink" title="Permalink"><i class="mdi mdi-link-variant"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
{if="$value.description"}<div class="link-description">{$value.description}</div>{/if}
|
||||
<div class="link-footer">
|
||||
<div class="link-tag-list">{loop="$value.taglist"}<span class="link-tag"><a href="{$base_path}/add-tag/{$key|urlencode}">{$value}</a></span>{/loop}</div>
|
||||
<div class="link-actions">
|
||||
{if="$is_logged_in"}
|
||||
<a href="{$base_path}/admin/shaare/{$value.id}" title="Edit"><i class="mdi mdi-pencil"></i></a>
|
||||
<a href="{$base_path}/admin/shaare/{$value.id}/pin?token={$token}" title="Pin/Unpin"><i class="mdi mdi-pin"></i></a>
|
||||
<a href="{$base_path}/admin/shaare/delete?id={$value.id}&token={$token}" title="Delete" onclick="return confirm('Delete this bookmark?');"><i class="mdi mdi-delete"></i></a>
|
||||
{/if}
|
||||
<a href="{$value.real_url}" target="_blank" rel="noopener" title="Open Link"><i class="mdi mdi-open-in-new"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/loop}
|
||||
</div>
|
||||
{include="linklist.paging"}
|
||||
{/if}
|
||||
{loop="$plugin_end_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
{if="$page_max > 1"}
|
||||
{if="$is_logged_in"}
|
||||
{$total="$linkcount"}
|
||||
{else}
|
||||
{if="empty($privateLinkcount)"}
|
||||
{$total="$linkcount"}
|
||||
{else}
|
||||
{$total=$linkcount - $privateLinkcount}
|
||||
{/if}
|
||||
{/if}
|
||||
{$from=($page_current - 1) * $links_per_page + 1}
|
||||
{$to=min($total, ($page_current - 1) * $links_per_page + $links_per_page)}
|
||||
<div class="paging">
|
||||
<div class="paging-links">
|
||||
{if="$next_page_url"}<a href="{$next_page_url}" class="paging-newer" title="Newer"><i class="mdi mdi-chevron-left"></i></a>{/if}
|
||||
<div class="paging-current">page <strong>{$page_current}</strong> / {$page_max}</div>
|
||||
{if="$previous_page_url"}<a href="{$previous_page_url}" class="paging-older" title="Older"><i class="mdi mdi-chevron-right"></i></a>{/if}
|
||||
</div>
|
||||
{loop="$action_plugin"}
|
||||
<div class="paging-plugin">
|
||||
<a {loop="$value.attr"}{$key}="{$value}" {/loop}>{$value.html}</a>
|
||||
</div>
|
||||
{/loop}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
|
||||
<head>
|
||||
{$pageName="linklist"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
<div id="linklist">
|
||||
{loop="$plugin_start_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
|
||||
<!-- Toolbar with View Toggle -->
|
||||
<div class="content-toolbar">
|
||||
<div class="toolbar-left">
|
||||
{include="linklist.paging"}
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<div class="view-toggle">
|
||||
<button class="view-toggle-btn active" id="view-grid-btn" title="Grid View">
|
||||
<i class="mdi mdi-view-grid"></i>
|
||||
</button>
|
||||
<button class="view-toggle-btn" id="view-list-btn" title="List View">
|
||||
<i class="mdi mdi-view-list"></i>
|
||||
</button>
|
||||
<button class="view-toggle-btn" id="view-compact-btn" title="Compact View">
|
||||
<i class="mdi mdi-view-headline"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if="count($links)==0"}
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">
|
||||
<i class="mdi mdi-bookmark-off-outline"></i>
|
||||
</div>
|
||||
<h2 class="empty-state-title">No bookmarks found</h2>
|
||||
<p class="empty-state-text">
|
||||
{if="!empty($search_term)"}
|
||||
No results for: <strong>{$search_term}</strong>
|
||||
{else}
|
||||
Start adding bookmarks to see them here.
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
{else}
|
||||
|
||||
<div class="links-list view-grid" id="links-list">
|
||||
{loop="$links"}
|
||||
<div id="{$value.id}" class="link-outer{if="isset($value.sticky) && $value.sticky"} is-sticky{/if}{if="$value.class"} {$value.class}{/if}{if="$value.private"} private{else} public{/if}" data-id="{$value.id}">
|
||||
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="loginform"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
<div id="headerform" class="page-login container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<form method="post" name="loginform">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Login'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="login">{'Username'|t}</label>
|
||||
<input type="text" name="login" id="login" class="form-control {if="empty($username)"}autofocus{/if}" tabindex="1" {if="!empty($username)"}value="{$username}"{/if}>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password">{'Password'|t}</label>
|
||||
<input type="password" name="password" id="password" class="form-control {if="!empty($username)"}autofocus{/if}" tabindex="2" >
|
||||
</div>
|
||||
<div class="form-group checkbox-wrapper">
|
||||
<input type="checkbox" name="longlastingsession" id="longlastingsession" tabindex="3" style="width: auto;"
|
||||
{if="$remember_user_default"}checked="checked"{/if}>
|
||||
<label for="longlastingsession" style="margin: 0;">{'Remember me'|t}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary" tabindex="4">{'Login'|t}</button>
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
{if="$returnurl"}<input type="hidden" name="returnurl" value="{$returnurl}">{/if}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||
<ShortName>Shaarli search - {$pagetitle}</ShortName>
|
||||
<Description>Shaarli search - {$pagetitle}</Description>
|
||||
<Url type="text/html" template="{$serverurl}?searchterm={searchTerms}" />
|
||||
<Url type="application/atom+xml" template="{$serverurl}feed/atom?searchterm={searchTerms}"/>
|
||||
<Url type="application/rss+xml" template="{$serverurl}feed/rss?searchterm={searchTerms}"/>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<Developer>Shaarli Community - https://github.com/shaarli/Shaarli/</Developer>
|
||||
<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAHRklE
|
||||
QVRIx5WWaWxU5xWG3++7986dfYYZb+MN2xiMDRiDFePUiQsNoiwpUNpAmhInJVEqpa0oQUlbJVKq
|
||||
olaiqpLKUtOKhAJRm1BKRVWctuykpFjAgPcFx/uMl5mxPTOeuXPv3O3rjyiV0lIpfX+dc36c55xf
|
||||
70vwP9TZ2fFpSQCwT5u6unX4f0QeNLx27RoMQwfRveTd11T23M+8S9w+Z3NRma1W4Hk6/nEimFpM
|
||||
Xnun9Xpmz1MPY+feOhBi/fwAAOjq7iJEqmQqCZf5i7NvyNZ/bJPYgAjCiJc2Zmhyw68SM/T1+NlK
|
||||
uf61BPoH+tHU1PT5ACMjI8RXvACvpZ5NT0+fmrG+2TKqtDLV0BgA2AUfXS3+UtfDX2ixCf73E+oA
|
||||
rat92CTkv9fRBwEkSaLDt/JZR/v0Q7qjb8dQ5hjSqmYSOCkzBbogL+ij2RN8bik9wK88Al9tH4tG
|
||||
ow88lvb19yEyPwfGGLq6OungYD9fUlosrqwoQVVVUeOU8qE/mU0ZTq6KNvreNort+5hugkayQUgY
|
||||
qQld/u6qnVRhkciscOdOkNy5E0RnZ+e/AbwsZxAaHyORZA+prW01CTlnGppOqAcwUnCmlDAkAyin
|
||||
Dapb2t7lNeRijpwvTGlJROXugoKS+upz/S19Kj9lJjxXGY1VU49tGevt7WOCSMHTeAXclePsQts9
|
||||
Jq9oLR7rPVkHxpUYkK2c07ZDiieRNcAx3ZlNphcnsxbiMuEsXFSTZpabp+VVS17UNSV/8n7+gN75
|
||||
+C1DM6VEjkgatiz/5IOCAheiUdeyr+198keKZXLzTKYjMDk/ZzGJhkV9AiPSdWaYIAY4U7TYNJMR
|
||||
pugMqgHcXTiJqDK8ycMv2+TPWyWtKFw3KEdtJxNz8u8+/PNYIqeUgY/Oz+Z7q5X3gtqvG7qip8yM
|
||||
HqdZg5kGgwGACoQQQkEMQ2DMIFnGE04xCRQTZFaexUT6jEEImJ2njjxx9fr13hfqfULTQ4apHept
|
||||
lxf4mrqS3Tek0w1toTc1K6WcXfAwnyWH8kSkIueEhdhNrzUAv16fSCUzNwR3vr/G2lKWojMqbxF4
|
||||
FWlLPDvBR+RBNpTsNqfkV7htuUe/UVq456qdzzvFh2KjdSH0I6ODs1ps9NHcw2jMfRYcEQyOCiox
|
||||
aWR0fOQWVLFNUuOnrXJxfIPnpXLRKzocLpsJanhUU/bfjJ4gfwm/ys3JGX1cuS3UBvauLa/MBe9z
|
||||
5c/xGRdSKpiVmhhN98JK/w4DGgg4uLh8u1NfPhWbmzszeH3G1rxv3dL7+qXyGaXHJi46s4QQophp
|
||||
TKSDkHWGlAqmGCbAGAUA3sY5LlRZv3w44Dhnm0iFzbnsGfJR5E+EEsppTBVXuBptL5b8YQMlwnO+
|
||||
Z2wtea4cl8Rc3KXJ4zShRm0CFaCaGhSDwGSMlbtLhSr7FnVhKhscC4+AO3L0x5PSFBdfE9i40SE6
|
||||
xLSWRCIbJ6phIqEysqvk+2aJ0vhB1NK353zyaL3GS76NgRbVYykkt2OXuaQqMwuxkk0FT+OJpS+z
|
||||
piXPRP1KzRvz4dRvO68PaWCMEQAIDcbqFiLJtyaSA/Ef3NnMGttgvHS7mUUWw7cTMemtY/cPsw3n
|
||||
oe2+4mGXpt7VGWPJ6zOn1V2Xfaz5AxgvBzexodmeGWmCbWWTDOGpSZIIqeAe2/IYvnXgWbomUj2T
|
||||
lNlwUP7bV64lzuRIeoodqDxi1OKRs/e0i08dH/6JPWtk6KKaZd3xj2jAXkY3BvZGK1xrhZvRNktP
|
||||
fNA0ubQrxyxV4jHpSkWoXJPKYqBetxeRpgsMWwE5b/bxaYxUDSWmzCLbStqQuy02LY4/cWLsqH8i
|
||||
HYNbyEeJczkJSzH2855DwsXp932F9hXEKQSQ1UHa568iRAa3uFyeNVolMBmeIrzT4cTXm37KMuvA
|
||||
xb8XXTqiDELRgKg8h/dGWwP9iSDaIzcYJSCbA/uNR3N2sNahV/hbsSA70vEdW66tCOOpj8FRkIgU
|
||||
Q5ybLUopiTzeTpFWUoTXdR3knwQMzLANOyQX50fWhDktLeAX3UcIA2EEQHPgi6TBsrWzaLGm7emC
|
||||
H7bY+GPlV6YumiEpDhslxGBgROApz+yyhROzduIEzwngDh48iD3jO0nBRAUUXtHcoq+ZWbI5EWWa
|
||||
WTieFjoKsaVoN92T88J4vlz+asXqpb+hEcdotbdueZ47vyiqhpA2UoRQwpoLtpNHxR0382jR8RzT
|
||||
k8xYMyCMMfR33Uc8rxdrA9tpuHPyS7pPOTRPZ1arepa4rUsybiWnnU9a39ZXxdur+XoGAGMdoXLi
|
||||
M789axnfNxDr8omiDcvF1f3OhPf18efjF/nfz6PGvv6zlrlwWwYBgcBZbKH4WKHODLHEURDxbHDF
|
||||
QWGePftHUlZWjsy8guYnH2EgwORfZ5cuavEqgGhLnL6+sycvRP1Fbux/fheIn3wCCN4N/qdPMwA4
|
||||
2fYOeoe7kc6kcfCbh8n+r7YwAOjs6QCl9DNx5t7dew+MOf8CcuqqoLxlhwgAAAAASUVORK5CYII=
|
||||
</Image>
|
||||
</OpenSearchDescription>
|
||||
@@ -0,0 +1,38 @@
|
||||
<footer class="footer-main" style="margin-top: 3rem; padding: 2rem 0; border-top: 1px solid var(--border); text-align: center; color: var(--text-secondary); font-size: 0.9rem;">
|
||||
<p>
|
||||
Powered by <a href="https://github.com/shaarli/Shaarli" target="_blank" rel="noopener" style="color:var(--text-main);">Shaarli</a>.
|
||||
{if="$is_logged_in"}
|
||||
<span class="footer-divider">|</span> <a href="{$base_path}/admin/tools" style="color:var(--text-main);">Administration</a>
|
||||
{/if}
|
||||
</p>
|
||||
<div class="footer-feeds" style="margin-top: 0.5rem;">
|
||||
<a href="{$base_path}/feed/rss" title="RSS Feed"><i class="mdi mdi-rss"></i> RSS</a>
|
||||
<span style="margin: 0 0.5rem;">•</span>
|
||||
<a href="{$base_path}/feed/atom" title="Atom Feed">Atom</a>
|
||||
<span style="margin: 0 0.5rem;">•</span>
|
||||
<a href="{$base_path}/daily" title="Daily">Daily</a>
|
||||
</div>
|
||||
|
||||
{loop="$plugins_footer.text"}
|
||||
<div class="plugin-footer-text">{$value}</div>
|
||||
{/loop}
|
||||
|
||||
{loop="$plugins_footer.js"}
|
||||
<script src="{$root_path}/{$value}"></script>
|
||||
{/loop}
|
||||
</footer>
|
||||
</div><!-- /.content-container -->
|
||||
|
||||
<!-- Bulk Actions Bar (for multi-select) -->
|
||||
<div class="bulk-actions-bar" id="bulk-actions-bar">
|
||||
<div class="bulk-info">
|
||||
<span id="bulk-count">0</span> links selected - <a class="bulk-select-all" id="bulk-select-all">select all</a>
|
||||
</div>
|
||||
<div class="bulk-buttons">
|
||||
<button class="bulk-btn bulk-btn-cancel" id="bulk-cancel">CANCEL</button>
|
||||
<button class="bulk-btn bulk-btn-delete" id="bulk-delete">DELETE</button>
|
||||
<button class="bulk-btn bulk-btn-public" id="bulk-public">SET PUBLIC</button>
|
||||
<button class="bulk-btn bulk-btn-private" id="bulk-private">SET PRIVATE</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.main-content -->
|
||||
@@ -0,0 +1,253 @@
|
||||
<!--
|
||||
{$isCalledFromBookmarklet=isset($_GET['source']) && $_GET['source'] == 'bookmarklet'}
|
||||
-->
|
||||
{if="$isCalledFromBookmarklet"}
|
||||
{ignore} When called as a popup from bookmarklet, do not display menu. {/ignore}
|
||||
{else}
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<div class="sidebar-logo">
|
||||
<i class="mdi mdi-bookmark-multiple"></i>
|
||||
</div>
|
||||
<a href="{$titleLink}" class="sidebar-brand">{$shaarlititle}</a>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-title">Navigation</div>
|
||||
<a href="{$base_path}/" class="sidebar-link{if=" $pageName=='linklist'"} active{/if}">
|
||||
<i class="mdi mdi-bookmark-multiple-outline"></i>
|
||||
<span>All Bookmarks</span>
|
||||
</a>
|
||||
<a href="{$base_path}/tags/cloud" class="sidebar-link{if=" $pageName=='tagcloud'"} active{/if}">
|
||||
<i class="mdi mdi-tag-multiple-outline"></i>
|
||||
<span>Tag Cloud</span>
|
||||
</a>
|
||||
<a href="{$base_path}/picture-wall?{function=" ltrim($searchcrits, '&' )"}" class="sidebar-link{if="
|
||||
$pageName=='picwall'"} active{/if}">
|
||||
<i class="mdi mdi-image-multiple-outline"></i>
|
||||
<span>Picture Wall</span>
|
||||
</a>
|
||||
<a href="{$base_path}/daily" class="sidebar-link{if=" $pageName=='daily'"} active{/if}">
|
||||
<i class="mdi mdi-calendar-today"></i>
|
||||
<span>Daily</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{if="$is_logged_in"}
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-title">Admin</div>
|
||||
<a href="{$base_path}/admin/tools" class="sidebar-link">
|
||||
<i class="mdi mdi-tools"></i>
|
||||
<span>Tools</span>
|
||||
</a>
|
||||
<a href="{$base_path}/admin/configure" class="sidebar-link">
|
||||
<i class="mdi mdi-cog-outline"></i>
|
||||
<span>Settings</span>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
{if="$is_logged_in"}
|
||||
<a href="{$base_path}/admin/add-shaare" class="sidebar-add-btn">
|
||||
<i class="mdi mdi-plus"></i>
|
||||
<span>New Bookmark</span>
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
<div class="theme-toggle-wrapper">
|
||||
<span class="theme-toggle-label">
|
||||
<i class="mdi mdi-weather-sunny" id="theme-icon-light"></i>
|
||||
<span>Light Mode</span>
|
||||
</span>
|
||||
<label class="theme-switch">
|
||||
<input type="checkbox" id="theme-toggle-checkbox">
|
||||
<span class="theme-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Sidebar Overlay for Mobile -->
|
||||
<div class="sidebar-overlay" id="sidebar-overlay"></div>
|
||||
|
||||
<!-- Main Content Wrapper -->
|
||||
<div class="main-content">
|
||||
<!-- Top Header Bar -->
|
||||
<header class="header-main">
|
||||
<div class="header-inner">
|
||||
<div class="header-left">
|
||||
<button class="mobile-menu-btn" id="mobile-menu-btn" title="Toggle Menu">
|
||||
<i class="mdi mdi-menu"></i>
|
||||
</button>
|
||||
<a href="{$titleLink}" class="header-brand">{$shaarlititle}</a>
|
||||
</div>
|
||||
|
||||
<!-- Main Navigation -->
|
||||
<nav class="header-nav">
|
||||
<a href="{$base_path}/" class="header-nav-link{if=" $pageName=='linklist'"} active{/if}">
|
||||
<i class="mdi mdi-home-outline"></i>
|
||||
<span>HOME</span>
|
||||
</a>
|
||||
<a href="{$base_path}/tags/cloud" class="header-nav-link{if=" $pageName=='tagcloud'"} active{/if}">
|
||||
<i class="mdi mdi-tag-multiple"></i>
|
||||
<span>TAG CLOUD</span>
|
||||
</a>
|
||||
<a href="{$base_path}/picture-wall?{function=" ltrim($searchcrits, '&' )"}" class="header-nav-link{if="
|
||||
$pageName=='picwall'"} active{/if}">
|
||||
<i class="mdi mdi-image-multiple"></i>
|
||||
<span>PICTURE WALL</span>
|
||||
</a>
|
||||
<a href="{$base_path}/daily" class="header-nav-link{if=" $pageName=='daily'"} active{/if}">
|
||||
<i class="mdi mdi-calendar"></i>
|
||||
<span>DAILY</span>
|
||||
</a>
|
||||
<button class="header-nav-link" id="search-toggle-btn" title="Search (Press S)">
|
||||
<i class="mdi mdi-magnify"></i>
|
||||
<span>SEARCH</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- Header Actions -->
|
||||
<div class="header-actions">
|
||||
<!-- Filter Button -->
|
||||
<div class="filter-dropdown" id="filter-dropdown">
|
||||
<button class="header-action-btn" id="filter-toggle-btn" title="Filters">
|
||||
<i class="mdi mdi-filter-variant"></i>
|
||||
</button>
|
||||
|
||||
<!-- Filter Panel -->
|
||||
<div class="filter-panel" id="filter-panel">
|
||||
<div class="filter-header">
|
||||
<span class="filter-title">Filters</span>
|
||||
<button class="filter-close" id="filter-close-btn">
|
||||
<i class="mdi mdi-close"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="filter-body">
|
||||
<div class="filter-section">
|
||||
<div class="filter-section-title">Links Per Page</div>
|
||||
<a href="{$base_path}/?nb=20" class="filter-option">20 links</a>
|
||||
<a href="{$base_path}/?nb=50" class="filter-option">50 links</a>
|
||||
<a href="{$base_path}/?nb=100" class="filter-option">100 links</a>
|
||||
</div>
|
||||
<div class="filter-section">
|
||||
<div class="filter-section-title">Custom value</div>
|
||||
<form method="GET" action="{$base_path}/">
|
||||
<input type="number" name="nb" class="filter-input" placeholder="20" min="1"
|
||||
max="500">
|
||||
</form>
|
||||
</div>
|
||||
{if="$is_logged_in"}
|
||||
<div class="filter-section">
|
||||
<div class="filter-section-title">Filters</div>
|
||||
<div class="filter-toggle-row">
|
||||
<span class="filter-toggle-label">Only private links</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="filter-private">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="filter-toggle-row">
|
||||
<span class="filter-toggle-label">Only public links</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="filter-public">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="filter-toggle-row">
|
||||
<span class="filter-toggle-label">Untagged links</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="filter-untagged">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if="$is_logged_in"}
|
||||
<!-- Multi-select Toggle -->
|
||||
<button class="header-action-btn" id="select-mode-btn" title="Multi-select">
|
||||
<i class="mdi mdi-checkbox-multiple-marked-outline"></i>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<!-- RSS Feed -->
|
||||
<a href="{$base_path}/feed/rss" class="header-action-btn" title="RSS Feed">
|
||||
<i class="mdi mdi-rss"></i>
|
||||
</a>
|
||||
|
||||
<!-- Plugins Support -->
|
||||
{if="isset($plugins_header.buttons_toolbar)"}
|
||||
{loop="$plugins_header.buttons_toolbar"}
|
||||
{$value.html}
|
||||
{/loop}
|
||||
{/if}
|
||||
|
||||
{if="$is_logged_in"}
|
||||
<a href="{$base_path}/admin/tools" class="header-action-btn" title="Tools">
|
||||
<i class="mdi mdi-cog-outline"></i>
|
||||
</a>
|
||||
<a href="{$base_path}/admin/logout" class="header-action-btn" title="Logout">
|
||||
<i class="mdi mdi-logout-variant"></i>
|
||||
</a>
|
||||
{else}
|
||||
<a href="{$base_path}/login" class="header-action-btn" title="Login">
|
||||
<i class="mdi mdi-login-variant"></i>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Search Overlay -->
|
||||
<div class="search-overlay" id="search-overlay">
|
||||
<div class="search-modal">
|
||||
<form method="GET" action="{$base_path}/" id="search-form">
|
||||
<div class="search-modal-header">
|
||||
<i class="mdi mdi-magnify search-modal-icon"></i>
|
||||
<input type="text" name="searchterm" class="search-modal-input" id="search-modal-input"
|
||||
placeholder="Search..." autocomplete="off" value="{if="
|
||||
isset($search_term)"}{$search_term}{/if}">
|
||||
<div class="search-modal-actions">
|
||||
<button type="submit" name="searchtags" class="search-type-btn" id="search-tags-btn">
|
||||
<i class="mdi mdi-tag"></i> tags
|
||||
</button>
|
||||
<button type="submit" class="search-type-btn active" id="search-all-btn">
|
||||
<i class="mdi mdi-magnify"></i> search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="search-hint">
|
||||
Press <kbd class="search-kbd">ESC</kbd> to close or <kbd class="search-kbd">Enter</kbd> to search
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Container -->
|
||||
<div class="content-container">
|
||||
<!-- Feedback Messages -->
|
||||
{if="!empty($plugin_errors) && $is_logged_in"}
|
||||
{loop="plugin_errors"}
|
||||
<div class="alert alert-danger">{$value}</div>
|
||||
{/loop}
|
||||
{/if}
|
||||
{if="!empty($global_errors)"}
|
||||
{loop="global_errors"}
|
||||
<div class="alert alert-danger">{$value}</div>
|
||||
{/loop}
|
||||
{/if}
|
||||
{if="!empty($global_successes)"}
|
||||
{loop="global_successes"}
|
||||
<div class="alert alert-success">{$value}</div>
|
||||
{/loop}
|
||||
{/if}
|
||||
{/if}
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="custom"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
You body goes here...
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="picwall"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
<div class="container content-container">
|
||||
{if="count($linksToDisplay) === 0 && $is_logged_in"}
|
||||
<div class="alert alert-warning text-center">
|
||||
{'There is no cached thumbnail.'|t}
|
||||
<a href="{$base_path}/admin/thumbnails">{'Try to synchronize them.'|t}</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div id="plugin_zone_start_picwall" class="plugin_zone">
|
||||
{loop="$plugin_start_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
|
||||
<div class="picwall-container">
|
||||
{loop="$linksToDisplay"}
|
||||
<div class="picwall-pictureframe">
|
||||
<img src="{$root_path}/{$value.thumbnail}#"
|
||||
loading="lazy"
|
||||
alt="{$value.title}"
|
||||
style="width: 100%; height: 100%; object-fit: cover;" />
|
||||
|
||||
<div class="picwall-overlay" style="position: absolute; bottom: 0; left: 0; right: 0; background: rgba(0,0,0,0.7); padding: 0.5rem; transform: translateY(100%); transition: transform 0.2s ease;">
|
||||
<a class="picwall-link" href="{$value.real_url}" style="color: white; font-size: 0.9rem; text-decoration: none; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
||||
{$value.title}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{loop="$value.picwall_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
{/loop}
|
||||
</div>
|
||||
|
||||
<div id="plugin_zone_end_picwall" class="plugin_zone">
|
||||
{loop="$plugin_end_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.picwall-pictureframe:hover .picwall-overlay {
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,125 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="pluginsadmin"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div id="pluginadmindiv" class="page-pluginadmin container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<noscript>
|
||||
<p>{'You need to enable Javascript to change plugin loading order.'|t}</p>
|
||||
</noscript>
|
||||
|
||||
<h1>{'Plugin administration'|t}</h1>
|
||||
<p>Drag and drop your plugin to change the order in which they'll be called. Uncheck enabled plugin to disable them and vice-versa.</p>
|
||||
|
||||
<form action="{$base_path}/admin/plugins" method="post">
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{'Enabled Plugins'|t}</div>
|
||||
{if="count($enabledPlugins)==0"}
|
||||
<div class="card-body">
|
||||
<p class="text-center text-muted">{'No plugin enabled.'|t}</p>
|
||||
</div>
|
||||
{else}
|
||||
<ul id="list-plugin-enabled" class="list-group list-sortable list-checkable" style="margin:0; padding:0; list-style:none;">
|
||||
{loop="$enabledPlugins"}
|
||||
<li class="list-group-item list-item-sortable" data-line="{$key}" data-order="{$counter}">
|
||||
<div class="checkbox-wrapper">
|
||||
<input type="checkbox" name="{$key}" id="checkbox-{$key}" checked style="width:auto;">
|
||||
</div>
|
||||
<input type="hidden" name="order_{$key}" value="{$counter}">
|
||||
<div class="list-group-item-content">
|
||||
<label for="checkbox-{$key}" class="list-group-item-label" style="cursor:pointer; margin:0;">{function="str_replace('_', ' ', $key)"}</label>
|
||||
<div class="list-group-item-sublabel">{$value.description}</div>
|
||||
</div>
|
||||
<div class="list-sortable-handle mdi mdi-drag"></div>
|
||||
</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{'Disabled Plugins'|t}</div>
|
||||
{if="count($disabledPlugins)==0"}
|
||||
<div class="card-body">
|
||||
<p class="text-center text-muted">{'No plugin disabled.'|t}</p>
|
||||
</div>
|
||||
{else}
|
||||
<ul class="list-group list-sortable list-checkable" style="margin:0; padding:0; list-style:none;">
|
||||
{loop="$disabledPlugins"}
|
||||
<li class="list-group-item list-item-sortable" data-line="{$key}" data-order="{$counter}">
|
||||
<div class="checkbox-wrapper">
|
||||
<input type="checkbox" id="checkbox-{$key}" name="{$key}" style="width:auto;">
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<label for="checkbox-{$key}" class="list-group-item-label" style="cursor:pointer; margin:0;">{function="str_replace('_', ' ', $key)"}</label>
|
||||
<div class="list-group-item-sublabel">{$value.description}</div>
|
||||
</div>
|
||||
</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="card" style="background:transparent; border:none; box-shadow:none; margin-top:-1rem;">
|
||||
<div class="card-body" style="padding:0; display:flex; justify-content:space-between; align-items:center;">
|
||||
<p class="text-muted" style="margin:0; font-size:0.9rem;">
|
||||
{"More plugins available"|t}
|
||||
<a href="{$root_path}/doc/html/Community-&-Related-software/#third-party-plugins" target="_blank" rel="noopener">{"in the documentation"|t}</a>.
|
||||
</p>
|
||||
<button type="submit" class="btn btn-primary">{'Save plugins'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form action="{$base_path}/admin/plugins" method="post" style="margin-top:2rem;">
|
||||
<input type="hidden" name="token" value="{$token}">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Plugin Parameters'|t}</div>
|
||||
<div class="card-body">
|
||||
{if="count($enabledPlugins)==0"}
|
||||
<p class="text-center text-muted">{'No plugin enabled.'|t}</p>
|
||||
{else}
|
||||
{$count=0}
|
||||
{loop="$enabledPlugins"}
|
||||
{if="count($value.parameters) > 0"}
|
||||
{if="$count>0"}
|
||||
<hr style="margin: 1.5rem 0; border-top: 1px solid var(--border);">
|
||||
{/if}
|
||||
{$count=$count+1}
|
||||
<h3 style="font-size:1.1rem; margin:0 0 1rem 0; color:var(--primary);">{function="str_replace('_', ' ', $key)"}</h3>
|
||||
{loop="$value.parameters"}
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-4">
|
||||
<label class="form-label" for="{$key}" {if="isset($value.desc)"}title="{$value.desc}"{/if}>{function="str_replace('_', ' ', $key)"}</label>
|
||||
{if="isset($value.desc)"}<div class="sublabel">{$value.desc}</div>{/if}
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" name="{$key}" value="{$value.value}" id="{$key}" {if="isset($value.desc)"}placeholder="{$value.desc}"{/if}>
|
||||
</div>
|
||||
</div>
|
||||
{/loop}
|
||||
{/if}
|
||||
{/loop}
|
||||
{if="$count==0"}
|
||||
<p class="text-center text-muted">{'No parameter available.'|t}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" name="parameters_form" class="btn btn-primary">{'Save parameters'|t}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,115 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="server"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
<div id="toolsdiv" class="page-server container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<h1>{'Server administration'|t}</h1>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{'General'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="key-value-list">
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">{'Index URL'|t}</div>
|
||||
<div class="key-value-data"><a href="{$index_url}" title="{$pagetitle}">{$index_url}</a></div>
|
||||
</div>
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">{'Base path'|t}</div>
|
||||
<div class="key-value-data">{$base_path}</div>
|
||||
</div>
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">{'Client IP'|t}</div>
|
||||
<div class="key-value-data">{$client_ip}</div>
|
||||
</div>
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">{'Trusted reverse proxies'|t}</div>
|
||||
<div class="key-value-data">
|
||||
{if="count($trusted_proxies) > 0"}
|
||||
<ul style="margin: 0; padding: 0; list-style: none;">
|
||||
{loop="$trusted_proxies"}
|
||||
<li>{$value}</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
{else}
|
||||
{'N/A'|t}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include="server.requirements"}
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Version'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="key-value-list">
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">{'Current version'|t}</div>
|
||||
<div class="key-value-data">{$current_version}</div>
|
||||
</div>
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">{'Latest release'|t}</div>
|
||||
<div class="key-value-data"><a href="{$release_url}" title="{'Visit releases page on Github'|t}" target="_blank" rel="noopener">{$latest_version}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Thumbnails'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="key-value-list">
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">{'Thumbnails status'|t}</div>
|
||||
<div class="key-value-data">
|
||||
{if="$thumbnails_mode==='all'"}
|
||||
<span class="text-success">{'All'|t}</span>
|
||||
{elseif="$thumbnails_mode==='common'"}
|
||||
<span class="text-success">{'Only common media hosts'|t}</span>
|
||||
{else}
|
||||
<span class="text-muted">{'None'|t}</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{if="$thumbnails_mode!=='none'"}
|
||||
<div class="card-footer">
|
||||
<a href="{$base_path}/admin/thumbnails" title="{'Synchronize all link thumbnails'|t}" class="btn btn-primary">{'Synchronize thumbnails'|t}</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Cache'|t}</div>
|
||||
<div class="card-footer">
|
||||
<a href="{$base_path}/admin/clear-cache?type=main" class="btn btn-secondary">{'Clear main cache'|t}</a>
|
||||
<a href="{$base_path}/admin/clear-cache?type=thumbnails" class="btn btn-secondary">{'Clear thumbnails cache'|t}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,70 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Permissions'|t}</div>
|
||||
<div class="card-body">
|
||||
{if="count($permissions) > 0"}
|
||||
<p><i class="mdi mdi-close text-error"></i> {'There are permissions that need to be fixed.'|t}</p>
|
||||
<ul style="padding-left: 1.5rem;">
|
||||
{loop="$permissions"}
|
||||
<li>{$value}</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
{else}
|
||||
<p class="text-success" style="margin: 0;"><i class="mdi mdi-check"></i> {'All read/write permissions are properly set.'|t}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
<div class="card">
|
||||
<div class="card-header">PHP</div>
|
||||
<div class="card-body">
|
||||
<p style="margin-bottom: 1.5rem;">
|
||||
<strong>{'Running PHP'|t} {$php_version}</strong>
|
||||
{if="$php_has_reached_eol"}
|
||||
<span class="text-warning"><i class="mdi mdi-circle"></i> {'End of life: '|t} {$php_eol}</span>
|
||||
{else}
|
||||
<span class="text-success"><i class="mdi mdi-circle"></i></span>
|
||||
{/if}
|
||||
</p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{'Extension'|t}</th>
|
||||
<th>{'Usage'|t}</th>
|
||||
<th>{'Status'|t}</th>
|
||||
<th class="text-center">{'Loaded'|t}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{loop="$php_extensions"}
|
||||
<tr>
|
||||
<td><strong>{$value.name}</strong></td>
|
||||
<td>{$value.desc}</td>
|
||||
<td>{$value.required ? t('Required') : t('Optional')}</td>
|
||||
<td class="text-center">
|
||||
{if="$value.loaded"}
|
||||
<i class="mdi mdi-check-circle text-success" title="{'Loaded'|t}"></i>
|
||||
{else}
|
||||
{if="$value.required"}
|
||||
<i class="mdi mdi-close-circle text-error" title="{'Not loaded'|t}"></i>
|
||||
{else}
|
||||
<i class="mdi mdi-alert-circle text-warning" title="{'Not loaded'|t}"></i>
|
||||
{/if}
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/loop}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="tag.cloud"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
{include="tag.sort"}
|
||||
|
||||
<div class="container page-tag-cloud">
|
||||
<div id="plugin_zone_start_tagcloud" class="plugin_zone">
|
||||
{loop="$plugin_start_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{'Tag Cloud'|t}</div>
|
||||
<div class="card-body">
|
||||
<div id="cloudtag" class="tag-cloud">
|
||||
{loop="$tags"}
|
||||
<a href="{$base_path}/?searchtags={$tags_url.$key1}{$tags_separator|urlencode}{$search_tags_url}" style="font-size:{$value.size}em;" class="cloud-tag">{$key}</a>
|
||||
<span class="count-badge">{$value.count}</span>
|
||||
{loop="$value.tag_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="plugin_zone_end_tagcloud" class="plugin_zone">
|
||||
{loop="$plugin_end_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tag-cloud {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
gap: 0.5rem 0.25rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.cloud-tag {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.cloud-tag:hover {
|
||||
color: var(--primary-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.count-badge {
|
||||
font-size: 0.7em;
|
||||
color: var(--text-muted);
|
||||
vertical-align: super;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="tag.list"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
|
||||
{include="tag.sort"}
|
||||
|
||||
<div class="container">
|
||||
{$countTags=count($tags)}
|
||||
|
||||
<div id="plugin_zone_start_tagcloud" class="plugin_zone">
|
||||
{loop="$plugin_start_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
|
||||
<div id="taglist" class="card">
|
||||
<div class="card-header">
|
||||
<div class="pull-right" style="font-size: 0.9rem;">
|
||||
<a href="{$base_path}/?searchtags={$search_tags|urlencode}" title="{'List all links with those tags'|t}">{$countTags} {'tags'|t}</a>
|
||||
</div>
|
||||
{'Tag list'|t}
|
||||
</div>
|
||||
<div class="card-body" style="padding-bottom: 0;">
|
||||
<form class="card-search" method="get">
|
||||
<input type="hidden" name="do" value="taglist">
|
||||
<div class="form-group">
|
||||
<input type="search" name="searchtags" class="form-control" placeholder="{'Filter by tag'|t}..."
|
||||
{if="!empty($search_tags)"}
|
||||
value="{$search_tags}"
|
||||
{/if}
|
||||
autocomplete="off" data-multiple data-autofirst data-minChars="1"
|
||||
data-list="{loop="$tags"}{$key}, {/loop}"
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
{loop="tags"}
|
||||
<div class="list-group-item">
|
||||
<div class="list-group-item-content" style="display: flex; align-items: center; justify-content: space-between;">
|
||||
<div style="flex: 1;">
|
||||
<a href="{$base_path}/?searchtags={$key|urlencode} {$search_tags|urlencode}" class="tag-link" style="font-weight: 500; font-size: 1rem;">{$key}</a>
|
||||
{loop="$value.tag_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
<div style="margin-right: 1rem;">
|
||||
<span class="badge" style="background: var(--border-light); padding: 0.25rem 0.5rem; border-radius: 999px; font-size: 0.8rem;">{$value}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item-action">
|
||||
<a href="{$base_path}/add-tag/{$key|urlencode}" title="{'Add tag'|t} {$key} {'to the filters'|t}" class="btn btn-secondary btn-sm" style="padding: 0.25rem 0.5rem;">
|
||||
<i class="mdi mdi-magnify-plus-outline"></i>
|
||||
</a>
|
||||
{if="$is_logged_in"}
|
||||
<a href="{$base_path}/admin/tags?fromtag={$key|urlencode}" title="{'Rename tag'|t} {$key}" data-tag="{$key}" class="rename-tag btn btn-secondary btn-sm" style="padding: 0.25rem 0.5rem;">
|
||||
<i class="mdi mdi-pencil"></i>
|
||||
</a>
|
||||
<a href="#" class="delete-tag btn btn-danger btn-sm" data-tag="{$key}" title="{'Delete tag'|t} {$key}" style="padding: 0.25rem 0.5rem;">
|
||||
<i class="mdi mdi-delete"></i>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="plugin_zone_end_tagcloud" class="plugin_zone">
|
||||
{loop="$plugin_end_zone"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if="$is_logged_in"}
|
||||
<input type="hidden" name="taglist" value="{loop="$tags"}{$key} {/loop}">
|
||||
{/if}
|
||||
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="subheader" style="margin-bottom: 1.5rem;">
|
||||
<div class="container text-center">
|
||||
<div class="btn-group" role="group" aria-label="Tag View">
|
||||
<a class="btn {if="$pageName === 'tag.cloud'"}btn-primary{else}btn-secondary{/if}" href="{$base_path}/tags/cloud" title="{'Cloud'|t}">{'Cloud'|t}</a>
|
||||
<a class="btn {if="$pageName === 'tag.list' && $_GET['sort'] === 'usage'"}btn-primary{else}btn-secondary{/if}" href="{$base_path}/tags/list?sort=usage" title="{'Most used'|t}">{'Most used'|t}</a>
|
||||
<a class="btn {if="$pageName === 'tag.list' && $_GET['sort'] === 'alpha'"}btn-primary{else}btn-secondary{/if}" href="{$base_path}/tags/list?sort=alpha" title="{'Alphabetical'|t}">{'Alphabetical'|t}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
$theme_info = array(
|
||||
'name' => 'Professional',
|
||||
'version' => '1.0.0',
|
||||
'author' => 'Antigravity',
|
||||
'description' => 'A professional, modern theme with specific light and dark modes.',
|
||||
'copyright' => '2026'
|
||||
);
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
<head>
|
||||
{$pageName="thumbnails"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div class="page-thumbnails container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Thumbnails update'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="thumbnail-placeholder" style="width: {$thumbnails_width}px; height: {$thumbnails_height}px;">
|
||||
|
||||
</div>
|
||||
<div class="thumbnail-link-title">
|
||||
Loading...
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-actual"></div>
|
||||
</div>
|
||||
<div class="progress-counter">
|
||||
<span class="progress-current">0</span> / <span class="progress-total">{$ids|count}</span>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="ids" value="{function="implode(',', $ids)"}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,193 @@
|
||||
<!DOCTYPE html>
|
||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||
|
||||
<head>
|
||||
{$pageName="tools"}
|
||||
{include="includes"}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{include="page.header"}
|
||||
<div id="toolsdiv" class="page-tools container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Settings'|t}</div>
|
||||
<div class="list-group">
|
||||
<a class="list-group-item list-group-item-action ripple" href="{$base_path}/admin/configure">
|
||||
<div class="list-sortable-handle" style="cursor: pointer; padding: 0; margin-right: 1rem;">
|
||||
<i class="mdi mdi-cog" style="font-size: 1.5rem; color: var(--primary);"></i>
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<div class="list-group-item-label">{'Configure your Shaarli'|t}</div>
|
||||
<div class="list-group-item-sublabel">{'Change Title, timezone...'|t}</div>
|
||||
</div>
|
||||
<i class="mdi mdi-chevron-right" style="color: var(--text-muted);"></i>
|
||||
</a>
|
||||
{if="!$openshaarli"}
|
||||
<a class="list-group-item list-group-item-action ripple" href="{$base_path}/admin/password">
|
||||
<div class="list-sortable-handle" style="cursor: pointer; padding: 0; margin-right: 1rem;">
|
||||
<i class="mdi mdi-lock" style="font-size: 1.5rem; color: var(--primary);"></i>
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<div class="list-group-item-label">{'Change password'|t}</div>
|
||||
<div class="list-group-item-sublabel">{'Change your password'|t}</div>
|
||||
</div>
|
||||
<i class="mdi mdi-chevron-right" style="color: var(--text-muted);"></i>
|
||||
</a>
|
||||
{/if}
|
||||
<a class="list-group-item list-group-item-action ripple" href="{$base_path}/admin/plugins">
|
||||
<div class="list-sortable-handle" style="cursor: pointer; padding: 0; margin-right: 1rem;">
|
||||
<i class="mdi mdi-puzzle" style="font-size: 1.5rem; color: var(--primary);"></i>
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<div class="list-group-item-label">{'Plugin administration'|t}</div>
|
||||
<div class="list-group-item-sublabel">{'Enable, disable and configure plugins'|t}</div>
|
||||
</div>
|
||||
<i class="mdi mdi-chevron-right" style="color: var(--text-muted);"></i>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action ripple" href="{$base_path}/admin/server">
|
||||
<div class="list-sortable-handle" style="cursor: pointer; padding: 0; margin-right: 1rem;">
|
||||
<i class="mdi mdi-server" style="font-size: 1.5rem; color: var(--primary);"></i>
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<div class="list-group-item-label">{'Server administration'|t}</div>
|
||||
<div class="list-group-item-sublabel">{'Check instance\'s server configuration'|t}</div>
|
||||
</div>
|
||||
<i class="mdi mdi-chevron-right" style="color: var(--text-muted);"></i>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action ripple" href="{$base_path}/admin/tags">
|
||||
<div class="list-sortable-handle" style="cursor: pointer; padding: 0; margin-right: 1rem;">
|
||||
<i class="mdi mdi-tag-multiple" style="font-size: 1.5rem; color: var(--primary);"></i>
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<div class="list-group-item-label">{'Manage Tags'|t}</div>
|
||||
<div class="list-group-item-sublabel">{'Rename or delete a tag in all links'|t}</div>
|
||||
</div>
|
||||
<i class="mdi mdi-chevron-right" style="color: var(--text-muted);"></i>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action ripple" href="{$base_path}/admin/import">
|
||||
<div class="list-sortable-handle" style="cursor: pointer; padding: 0; margin-right: 1rem;">
|
||||
<i class="mdi mdi-file-import" style="font-size: 1.5rem; color: var(--primary);"></i>
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<div class="list-group-item-label">{'Import'|t}</div>
|
||||
<div class="list-group-item-sublabel">{'Import Netscape html bookmarks'|t}</div>
|
||||
</div>
|
||||
<i class="mdi mdi-chevron-right" style="color: var(--text-muted);"></i>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action ripple" href="{$base_path}/admin/export">
|
||||
<div class="list-sortable-handle" style="cursor: pointer; padding: 0; margin-right: 1rem;">
|
||||
<i class="mdi mdi-file-export" style="font-size: 1.5rem; color: var(--primary);"></i>
|
||||
</div>
|
||||
<div class="list-group-item-content">
|
||||
<div class="list-group-item-label">{'Export'|t}</div>
|
||||
<div class="list-group-item-sublabel">{'Export Netscape html bookmarks'|t}</div>
|
||||
</div>
|
||||
<i class="mdi mdi-chevron-right" style="color: var(--text-muted);"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if="!empty($linkcount)"}
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">{'Statistics'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="key-value-list">
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">Total Links</div>
|
||||
<div class="key-value-data">{$linkcount}</div>
|
||||
</div>
|
||||
<div class="key-value-item">
|
||||
<div class="key-value-label">Private Links</div>
|
||||
<div class="key-value-data">{$privateLinkcount}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if="isset($tools_plugin)"}
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">Plugin settings</div>
|
||||
<div class="card-body">
|
||||
{loop="$tools_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">Bookmarklet</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted" style="margin-bottom: 1.5rem;">
|
||||
Drag these buttons to your bookmarks bar to quickly add links from any page.
|
||||
</p>
|
||||
<div class="row" style="display: flex; gap: 1rem; justify-content: center;">
|
||||
<div class="col-xs-6 text-center">
|
||||
<a class="btn btn-primary" href="javascript:(function(){var%20url%20=%20location.href;var%20title%20=%20document.title%20||%20url;var%20desc=document.getSelection().toString();if(desc.length>4000){desc=desc.substr(0,4000)+'...';alert('{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}');}window.open('{$pageabsaddr}admin/shaare?post='%20+%20encodeURIComponent(url)+'&title='%20+%20encodeURIComponent(title)+'&description='%20+%20encodeURIComponent(desc)+'&source=bookmarklet','_blank','menubar=no,height=800,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1');})();">
|
||||
<i class="mdi mdi-bookmark-plus"></i> {'Shaare link'|t}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-6 text-center">
|
||||
<a class="btn btn-secondary" href="javascript:(function(){var desc=document.getSelection().toString();if(desc.length>4000){desc=desc.substr(0,4000)+'...';alert('{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}');}window.open('{$pageabsaddr}?private=1&post='+'&description='%20+%20encodeURIComponent(desc)+'&source=bookmarklet','_blank','menubar=no,height=800,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1');})();">
|
||||
<i class="mdi mdi-note-plus"></i> {'Add Note'|t}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="card">
|
||||
<div class="card-header">{'3rd party'|t}</div>
|
||||
<div class="card-body">
|
||||
<div class="list-group" style="flex-direction: row; flex-wrap: wrap; gap: 1rem; justify-content: center;">
|
||||
<a href="https://addons.mozilla.org/fr/firefox/addon/shaarli/" target="_blank" class="btn btn-secondary">
|
||||
<i class="mdi mdi-firefox" style="font-size: 1.2rem;"></i> Firefox
|
||||
</a>
|
||||
<a href="https://chromewebstore.google.com/detail/add-to-shaarli/jhfblapoehcfajokolimghdfmeeakbee" target="_blank" class="btn btn-secondary">
|
||||
<i class="mdi mdi-google-chrome" style="font-size: 1.2rem;"></i> Chrome
|
||||
</a>
|
||||
<a href="https://f-droid.org/fr/packages/com.dimtion.shaarlier/" target="_blank" class="btn btn-secondary">
|
||||
<i class="mdi mdi-android" style="font-size: 1.2rem;"></i> Shaarlier
|
||||
</a>
|
||||
<a href="https://stakali.toneiv.eu/" target="_blank" class="btn btn-secondary">
|
||||
<i class="mdi mdi-android" style="font-size: 1.2rem;"></i> Stakali
|
||||
</a>
|
||||
<a href="https://github.com/lockcp/ShaarliOS" target="_blank" class="btn btn-secondary">
|
||||
<i class="mdi mdi-apple-ios" style="font-size: 1.2rem;"></i> iOS
|
||||
</a>
|
||||
</div>
|
||||
<p class="text-center text-muted" style="margin-top: 1.5rem;">
|
||||
Other <a href="https://shaarli.readthedocs.io/en/master/Community-and-related-software.html" target="_blank">{'Community and related software'|t}</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{loop="$tools_plugin"}
|
||||
{$value}
|
||||
{/loop}
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user