1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-04-21 07:22:20 +02:00

Merge branch 'main' into dev-v2

# Conflicts:
#	app/Helper/Sharing.php
#	app/Http/Controllers/App/SystemSettingsController.php
#	app/Http/Controllers/FetchController.php
#	app/Http/Controllers/Guest/TagController.php
#	app/Http/Controllers/Models/ListController.php
#	app/Http/Controllers/Models/NoteController.php
#	app/Http/Controllers/Setup/RequirementsController.php
#	app/Providers/FortifyServiceProvider.php
#	composer.json
#	composer.lock
#	docker-compose.yml
#	resources/views/admin/system-settings/partials/general-settings.blade.php
#	resources/views/app/settings/partials/user/app-settings/privacy.blade.php
#	resources/views/app/settings/system.blade.php
#	resources/views/models/links/show.blade.php
#	resources/views/models/notes/partials/single.blade.php
#	resources/views/partials/header.blade.php
This commit is contained in:
Kovah 2024-02-06 09:16:07 +01:00
commit 274eca2ff0
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
110 changed files with 1877 additions and 976 deletions

49
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,49 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
target-branch: "dev"
schedule:
interval: "weekly"
groups:
npm-major:
update-types:
- "major"
npm-minor:
update-types:
- "minor"
- "patch"
- package-ecosystem: "composer"
directory: "/"
target-branch: "dev"
schedule:
interval: "weekly"
groups:
composer-major:
update-types:
- "major"
composer-minor:
update-types:
- "minor"
- "patch"
- package-ecosystem: "docker"
directory: "/"
target-branch: "dev"
schedule:
interval: "weekly"
groups:
docker:
patterns:
- '*'
- package-ecosystem: "github-actions"
directory: "/"
target-branch: "dev"
schedule:
interval: "weekly"
groups:
actions:
patterns:
- '*'

View File

@ -15,10 +15,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Use Node.js 18.x
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: 18
node-version: 20
- name: Build all assets
run: |
@ -28,7 +28,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.0
php-version: 8.1
coverage: pcov
extensions: mbstring

View File

@ -18,10 +18,10 @@ jobs:
git config --global url."https://github.com/".insteadOf
ssh://git@github.com/
- name: Use Node.js 18.x
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: 18
node-version: 20
- name: Try to build the assets
run: |
@ -59,7 +59,7 @@ jobs:
- uses: shivammathur/setup-php@v2
with:
php-version: 8.0
php-version: 8.1
extensions: mbstring
- id: composer-cache
@ -114,7 +114,7 @@ jobs:
- uses: actions/upload-artifact@v3
with:
name: linkace-package-docker-simple
name: linkace-docker-simple
path: linkace-package-docker-simple.zip
- name: Rename files
@ -126,6 +126,6 @@ jobs:
- uses: actions/upload-artifact@v3
with:
name: linkace-package-docker-advanced
name: linkace-docker-advanced
path: linkace-package-docker-advanced.zip

View File

@ -12,10 +12,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Use Node.js 18 LTS
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
- name: Try to build the assets
run: |
@ -42,7 +42,7 @@ jobs:
strategy:
matrix:
operating-system: [ ubuntu-latest ]
php-versions: [ '8.0', '8.1', '8.2' ]
php-versions: [ '8.1', '8.2', '8.3' ]
steps:
- uses: actions/checkout@v2

View File

@ -43,6 +43,7 @@ It provides a long-term archive to store links to websites, media files or anyth
* Automated backups of saved sites via the [Internet Archive](https://web.archive.org/).
* Organize bookmarks with the help of lists and tags.
* A full REST API offers access to all features of LinkAce from other apps and services.
* LinkAce is also [available on Zapier](https://zapier.com/apps/linkace/integrations) and integrates with over 2500+ applications.
* LinkAce ships with a light and dark theme, that can be toggled or changes automatically.
* A bookmarklet to quickly save links from any browser.
* Links can be private or public, so friends or internet strangers may see your collection.
@ -52,8 +53,6 @@ It provides a long-term archive to store links to websites, media files or anyth
* Import and export of bookmarks from HTML.
* Support for complete database and application backups to any AWS S3 storage.
More features are already planned. Take a look at the [project board](https://github.com/Kovah/LinkAce/projects/3) for more information.
More screenshots of the app and further details about the features can be found on the [LinkAce Website](https://www.linkace.org/).

View File

@ -12,7 +12,7 @@ class ImportCommand extends Command
use AsksForUser;
protected $signature = 'links:import
{filepath : Bookmarks file to import}
{filepath : Bookmarks file to import, use absolute paths if stored outside of LinkAce}
{--skip-meta-generation : Whether the automatic generation of titles should be skipped.}
{--skip-check : Whether the links checking should be skipped afterwards}';
@ -31,7 +31,8 @@ class ImportCommand extends Command
$this->askForUser();
$this->info('Reading file "' . $this->argument('filepath') . '"...');
$data = File::get(storage_path($this->argument('filepath')));
$filepath = $this->argument('filepath');
$data = File::get(str_starts_with($filepath, '/') ? $filepath : storage_path($filepath));
if (empty($data)) {
$this->warn('The provided file is empty or could not be read!');

View File

@ -6,7 +6,7 @@ use App\Models\Link;
class Sharing
{
public static string $linkClasses = 'share-link btn btn-sm btn-light';
public static string $linkClasses = 'share-link btn btn-light';
public static array $placeholders = [
'#URL#',

View File

@ -38,15 +38,28 @@ class DashboardController extends Controller
->where('status', '>', 1)
->count();
$totalLinks = Link::byUser()
->count();
$totalLists = LinkList::byUser()
->count();
$totalNotes = Note::byUser()
->count();
$totalTags = Tag::byUser()
->count();
$stats = [
'total_links' => Link::count(),
'total_lists' => LinkList::count(),
'total_tags' => Tag::count(),
'total_notes' => Note::count(),
'total_links' => $totalLinks,
'total_lists' => $totalLists,
'total_tags' => $totalTags,
'total_notes' => $totalNotes,
'total_broken_links' => $brokenLinks,
];
return view('dashboard', [
'pageTitle' => trans('linkace.dashboard'),
'recent_links' => $recentLinks,
'recent_tags' => $recentTags,
'recent_lists' => $recentLists,

View File

@ -16,7 +16,9 @@ class ExportController extends Controller
{
public function getExport(): View
{
return view('app.export.export');
return view('app.export.export', [
'pageTitle' => trans('export.export'),
]);
}
/**

View File

@ -13,7 +13,9 @@ class ImportController extends Controller
{
public function getImport(): View
{
return view('app.import.import');
return view('app.import.import', [
'pageTitle' => trans('import.import'),
]);
}
/**

View File

@ -13,7 +13,9 @@ class SearchController extends Controller
public function getSearch(): View
{
return view('app.search.search')
return view('app.search.search', [
'pageTitle' => trans('search.search'),
])
->with('results', collect([]))
->with('order_by_options', $this->orderByOptions)
->with('query_settings', [
@ -36,7 +38,9 @@ class SearchController extends Controller
$search = $this->buildDatabaseQuery($request);
$results = $search->paginate(getPaginationLimit());
return view('app.search.search')
return view('app.search.search', [
'pageTitle' => trans('search.results_for') . ' ' . $this->searchQuery,
])
->with('results', $results)
->with('order_by_options', $this->orderByOptions)
->with('query_settings', [

View File

@ -23,6 +23,7 @@ class TrashController extends Controller
$notes = Note::onlyTrashed()->byUser()->get();
return view('app.trash.index', [
'pageTitle' => trans('trash.trash'),
'links' => $links,
'lists' => $lists,
'tags' => $tags,

View File

@ -20,6 +20,7 @@ class UserSettingsController extends Controller
public function getUserSettings(): View
{
return view('app.settings.user', [
'pageTitle' => trans('settings.user_settings'),
'user' => auth()->user(),
'bookmarklet_code' => bookmarkletUrl(),
]);

View File

@ -9,12 +9,14 @@ use App\Models\Tag;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Http;
use Masterminds\HTML5;
class FetchController extends Controller
{
public function getTags(Request $request): JsonResponse
{
$query = $request->input('query');
$query = $request->input('query', false);
if (!$query) {
return response()->json([]);
@ -87,9 +89,9 @@ class FetchController extends Controller
* implementation.
*
* @param Request $request
* @return Response
* @return JsonResponse
*/
public function htmlForUrl(Request $request): Response
public function htmlKeywordsFromUrl(Request $request)
{
$request->validate([
'url' => ['url'],
@ -100,9 +102,20 @@ class FetchController extends Controller
$response = $newRequest->get($url);
if ($response->successful()) {
return response($response->body());
$html5 = new HTML5();
$dom = $html5->loadHTML($response->body());
$keywords = [];
/** @var \DOMElement $metaTag */
foreach ($dom->getElementsByTagName('meta') as $metaTag) {
if (strtolower($metaTag->getAttribute('name')) === 'keywords') {
$keywords = explode(',', $metaTag->getAttributeNode('content')?->value);
$keywords = array_map(fn($keyword) => trim(e($keyword)), $keywords);
array_push($keywords, ...$keywords);
}
}
return response()->json(['keywords' => $keywords]);
}
return response(null);
return response()->json(['keywords' => null]);
}
}

View File

@ -32,6 +32,7 @@ class LinkController extends Controller
}
return view('guest.links.index', [
'pageTitle' => trans('link.links'),
'links' => $links->paginate(getPaginationLimit()),
'route' => $request->getBaseUrl(),
'orderBy' => $this->orderBy,

View File

@ -29,6 +29,7 @@ class ListController extends Controller
->paginate(getPaginationLimit());
return view('guest.lists.index', [
'pageTitle' => trans('list.lists'),
'lists' => $lists,
'orderBy' => $this->orderBy,
'orderDir' => $this->orderDir,
@ -49,6 +50,7 @@ class ListController extends Controller
->paginate(getPaginationLimit());
return view('guest.lists.show', [
'pageTitle' => trans('list.list') . ': ' . $list->name,
'list' => $list,
'listLinks' => $links,
'route' => $request->getBaseUrl(),

View File

@ -30,6 +30,7 @@ class TagController extends Controller
->paginate(getPaginationLimit());
return view('guest.tags.index', [
'pageTitle' => trans('tag.tags'),
'tags' => $tags,
'route' => $request->getBaseUrl(),
'orderBy' => $this->orderBy,
@ -51,6 +52,7 @@ class TagController extends Controller
->paginate(getPaginationLimit());
return view('guest.tags.show', [
'pageTitle' => trans('tag.tag') . ': ' . $tag->name,
'tag' => $tag,
'tagLinks' => $links,
'route' => $request->getBaseUrl(),

View File

@ -44,6 +44,7 @@ class LinkController extends Controller
}
return view('models.links.index', [
'pageTitle' => trans('link.links'),
'links' => $links->paginate(getPaginationLimit()),
'route' => $request->getBaseUrl(),
'orderBy' => $this->orderBy,
@ -57,6 +58,7 @@ class LinkController extends Controller
session()->forget('bookmarklet.create');
return view('models.links.create', [
'pageTitle' => trans('link.add'),
'existing_link' => null,
]);
}
@ -104,6 +106,7 @@ class LinkController extends Controller
},
]);
return view('models.links.show', [
'pageTitle' => trans('link.link') . ': ' . $link->shortTitle(),
'link' => $link,
'history' => $link->audits()->latest()->get(),
]);
@ -112,6 +115,7 @@ class LinkController extends Controller
public function edit(Link $link): View
{
return view('models.links.edit', [
'pageTitle' => trans('link.edit') . ': ' . $link->shortTitle(),
'link' => $link,
'existing_link' => null,
]);

View File

@ -43,6 +43,7 @@ class ListController extends Controller
$lists = $lists->paginate(getPaginationLimit());
return view('models.lists.index', [
'pageTitle' => trans('list.lists'),
'lists' => $lists,
'route' => $request->getBaseUrl(),
'orderBy' => $this->orderBy,
@ -52,7 +53,9 @@ class ListController extends Controller
public function create(): View
{
return view('models.lists.create');
return view('models.lists.create', [
'pageTitle' => trans('list.add'),
]);
}
public function store(ListStoreRequest $request): RedirectResponse
@ -82,6 +85,7 @@ class ListController extends Controller
->paginate(getPaginationLimit());
return view('models.lists.show', [
'pageTitle' => trans('list.list') . ': ' . $list->name,
'list' => $list,
'history' => $list->audits()->latest()->get(),
'listLinks' => $links,
@ -93,7 +97,10 @@ class ListController extends Controller
public function edit(LinkList $list): View
{
return view('models.lists.edit', ['list' => $list]);
return view('models.lists.edit', [
'pageTitle' => trans('list.edit') . ': ' . $list->name,
'list' => $list,
]);
}
public function update(ListUpdateRequest $request, LinkList $list): RedirectResponse

View File

@ -33,7 +33,10 @@ class NoteController extends Controller
public function edit(Note $note): View
{
return view('models.notes.edit', ['note' => $note]);
return view('models.notes.edit', [
'pageTitle' => trans('note.edit'),
'note' => $note,
]);
}
public function update(NoteUpdateRequest $request, Note $note): RedirectResponse

View File

@ -46,6 +46,7 @@ class TagController extends Controller
$tags = $tags->paginate(getPaginationLimit());
return view('models.tags.index', [
'pageTitle' => trans('tag.tags'),
'tags' => $tags,
'route' => $request->getBaseUrl(),
'orderBy' => $this->orderBy,
@ -56,7 +57,9 @@ class TagController extends Controller
public function create(): View
{
return view('models.tags.create');
return view('models.tags.create', [
'pageTitle' => trans('tag.add'),
]);
}
public function store(TagStoreRequest $request): RedirectResponse
@ -85,6 +88,7 @@ class TagController extends Controller
->paginate(getPaginationLimit());
return view('models.tags.show', [
'pageTitle' => trans('tag.tag') . ': ' . $tag->name,
'tag' => $tag,
'history' => $tag->audits()->latest()->get(),
'tagLinks' => $links,
@ -96,7 +100,10 @@ class TagController extends Controller
public function edit(Tag $tag): View
{
return view('models.tags.edit', ['tag' => $tag]);
return view('models.tags.edit', [
'pageTitle' => trans('tag.edit') . ': ' . $tag->name,
'tag' => $tag,
]);
}
public function update(TagUpdateRequest $request, Tag $tag): RedirectResponse

View File

@ -19,7 +19,9 @@ class AccountController extends Controller
public function index(): View
{
return view('setup.account');
return view('setup.account', [
'pageTitle' => trans('setup.account_setup'),
]);
}
protected function register(Request $request): RedirectResponse

View File

@ -20,7 +20,9 @@ class DatabaseController extends Controller
public function index(): View
{
return view('setup.database');
return view('setup.database', [
'pageTitle' => trans('setup.database_configure'),
]);
}
public function configure(SetupDatabaseRequest $request): RedirectResponse

View File

@ -10,7 +10,9 @@ class MetaController extends Controller
{
public function welcome(): View
{
return view('setup.welcome');
return view('setup.welcome', [
'pageTitle' => trans('setup.setup'),
]);
}
public function complete(SystemSettings $settings): View
@ -18,6 +20,8 @@ class MetaController extends Controller
$settings->setup_completed = true;
$settings->save();
return view('setup.complete');
return view('setup.complete', [
'pageTitle' => trans('setup.complete'),
]);
}
}

View File

@ -13,6 +13,7 @@ class RequirementsController extends Controller
[$success, $results] = $this->checkRequirements();
return view('setup.requirements', [
'pageTitle' => trans('setup.setup_requirements'),
'success' => $success,
'results' => $results,
]);
@ -21,7 +22,7 @@ class RequirementsController extends Controller
protected function checkRequirements(): array
{
$results = [
'php_version' => PHP_VERSION_ID >= 80002,
'php_version' => PHP_VERSION_ID >= 80110,
'extension_bcmath' => extension_loaded('bcmath'),
'extension_ctype' => extension_loaded('ctype'),
'extension_json' => extension_loaded('json'),

View File

@ -33,14 +33,14 @@ class FortifyServiceProvider extends ServiceProvider
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
Fortify::loginView(fn() => view('auth.login'));
Fortify::loginView(fn() => view('auth.login', ['pageTitle' => trans('linkace.login')]));
Fortify::requestPasswordResetLinkView(fn() => view('auth.passwords.email'));
Fortify::requestPasswordResetLinkView(fn() => view('auth.passwords.email', ['pageTitle' => trans('linkace.login')]));
Fortify::resetPasswordView(fn() => view('auth.passwords.reset'));
Fortify::resetPasswordView(fn() => view('auth.passwords.reset', ['pageTitle' => trans('linkace.login')]));
Fortify::confirmPasswordView(fn() => view('auth.confirm-password'));
Fortify::confirmPasswordView(fn() => view('auth.confirm-password', ['pageTitle' => trans('linkace.login')]));
Fortify::twoFactorChallengeView(fn() => view('auth.two-factor-challenge'));
Fortify::twoFactorChallengeView(fn() => view('auth.two-factor-challenge', ['pageTitle' => trans('linkace.login')]));
}
}

View File

@ -98,6 +98,7 @@ return [
'no_NO' => 'Norsk',
'pl_PL' => 'Polski',
'ro_RO' => 'Română',
'ru_RU' => 'Русский',
'vi_VN' => 'Tiếng Việt',
'zh_CN' => '简体中文',
],

View File

@ -4,9 +4,9 @@ services:
# --- MariaDB
db:
image: mariadb:10.7
image: mariadb:11.2
restart: unless-stopped
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
command: mariadbd --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
environment:
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
- MYSQL_USER=${DB_USERNAME}

View File

@ -4,9 +4,9 @@ services:
# --- MariaDB
db:
image: mariadb:10.7
image: mariadb:11.2
restart: unless-stopped
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
command: mariadbd --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
environment:
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
- MYSQL_USER=${DB_USERNAME}
@ -29,7 +29,7 @@ services:
# --- nginx
nginx:
image: bitnami/nginx:1.21
image: bitnami/nginx:1.24
restart: unless-stopped
ports:
- "0.0.0.0:80:8080"
@ -45,7 +45,7 @@ services:
# --- Redis
redis:
image: bitnami/redis:6.2
image: bitnami/redis:7.2
restart: unless-stopped
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}

View File

@ -5,9 +5,8 @@ services:
# --- MariaDB
db:
container_name: "linkace-db"
image: mariadb:10.6
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
image: mariadb:11.2
command: mariadbd --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
environment:
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
- MYSQL_USER=${DB_USERNAME}
@ -19,8 +18,7 @@ services:
- linkace-db:/var/lib/mysql
pg-db:
container_name: "linkace-pg-db"
image: postgres:13
image: postgres:14
environment:
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_USER=${DB_USERNAME}
@ -32,7 +30,6 @@ services:
# --- PHP
php:
container_name: "linkace-php"
build:
context: .
dockerfile: ./resources/docker/dockerfiles/development.Dockerfile
@ -44,8 +41,7 @@ services:
# --- nginx
nginx:
container_name: "linkace-nginx"
image: bitnami/nginx:1.19
image: bitnami/nginx:1.25
ports:
- "80:8080"
depends_on:
@ -56,8 +52,7 @@ services:
# --- Redis
redis:
container_name: "linkace-redis"
image: bitnami/redis:6.0
image: bitnami/redis:7.2
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
ports:

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'Extensió PHP: JSON',
'requirements.extension_mbstring' => 'Extensió PHP: Mbstring',
'requirements.extension_openssl' => 'Extensió PHP: OpenSSL',
'requirements.extension_pdo_mysql' => 'Extensió PHP: PDO',
'requirements.extension_pdo_mysql' => 'Extensió PHP: PDO MySQL',
'requirements.extension_tokenizer' => 'Extensió PHP: Tokenizer',
'requirements.extension_xml' => 'Extensió PHP: XML',
'requirements.env_writable' => 'L\'arxiu .env està present i té permisos d\'escriptura',

View File

@ -11,6 +11,7 @@ return [
'logout' => 'Abmelden',
'remember_me' => 'Angemeldet bleiben',
'go_to_dashboard' => 'Zur Übersicht gehen',
'dashboard' => 'Übersicht',
'system_logs' => 'System Logs',
'reset_password' => 'Passwort zurücksetzen',

View File

@ -25,6 +25,7 @@ return [
'order_by.random' => 'Zufällig',
'no_results' => 'Keine Ergebnisse gefunden.',
'results_for' => 'Ergebnisse für',
'validation_query_missing' => 'Es muss entweder eine Suchanfrage eingeben oder eine Liste oder ein Tag ausgewählt werden, oder die Suche nach kaputten Links muss aktiviert sein.',
];

View File

@ -11,6 +11,7 @@ return [
'intro.step2' => 'Richten Sie eine Datenbank ein und prüfen Sie, ob die Verbindung erfolgreich ist.',
'intro.step3' => 'Erstellen Sie Ihr Benutzerkonto.',
'setup_requirements' => 'Setup-Anforderungen',
'check_requirements' => 'Anforderungen prüfen',
'requirements.php_version' => 'PHP-Version >= 7.4.0',
'requirements.extension_bcmath' => 'PHP Extension: BCMath',
@ -18,7 +19,7 @@ return [
'requirements.extension_json' => 'PHP Extension: JSON',
'requirements.extension_mbstring' => 'PHP Extension: Mbstring',
'requirements.extension_openssl' => 'PHP Extension: OpenSSL',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO MySQL',
'requirements.extension_tokenizer' => 'PHP Extension: Tokenizer',
'requirements.extension_xml' => 'PHP Extension: XML',
'requirements.env_writable' => '.env Datei ist vorhanden und beschreibbar',

View File

@ -11,6 +11,7 @@ return [
'logout' => 'Logout',
'remember_me' => 'Remember me',
'go_to_dashboard' => 'Go to the Dashboard',
'dashboard' => 'Dashboard',
'system_logs' => 'System Logs',
'reset_password' => 'Reset Password',

View File

@ -25,6 +25,7 @@ return [
'order_by.random' => 'Random',
'no_results' => 'No results found.',
'results_for' => 'Search results for',
'validation_query_missing' => 'You must either enter a search query, or select a list, a tag or enable searching for broken links.',
];

View File

@ -11,6 +11,7 @@ return [
'intro.step2' => 'Setup up a database and check if the connection is successful.',
'intro.step3' => 'Create your user account.',
'setup_requirements' => 'Setup Requirements',
'check_requirements' => 'Check Requirements',
'requirements.php_version' => 'PHP version >= 7.4.0',
'requirements.extension_bcmath' => 'PHP Extension: BCMath',
@ -18,7 +19,7 @@ return [
'requirements.extension_json' => 'PHP Extension: JSON',
'requirements.extension_mbstring' => 'PHP Extension: Mbstring',
'requirements.extension_openssl' => 'PHP Extension: OpenSSL',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO MySQL',
'requirements.extension_tokenizer' => 'PHP Extension: Tokenizer',
'requirements.extension_xml' => 'PHP Extension: XML',
'requirements.env_writable' => '.env file is present and writable',

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'Extensión PHP: JSON',
'requirements.extension_mbstring' => 'Extensión PHP: Mbstring',
'requirements.extension_openssl' => 'Extensión PHP: OpenSSL',
'requirements.extension_pdo_mysql' => 'Extensión PHP: PDO',
'requirements.extension_pdo_mysql' => 'Extensión PHP: PDO MySQL',
'requirements.extension_tokenizer' => 'Extensión PHP: Tokenizer',
'requirements.extension_xml' => 'Extensión PHP: XML',
'requirements.env_writable' => 'El archivo .env está presente y tiene permisos de escritura',

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'Module PHP : JSON',
'requirements.extension_mbstring' => 'Module PHP : Mbstring',
'requirements.extension_openssl' => 'Module PHP : OpenSSL',
'requirements.extension_pdo_mysql' => 'Module PHP : PDO',
'requirements.extension_pdo_mysql' => 'Module PHP : PDO MySQL',
'requirements.extension_tokenizer' => 'Module PHP : Tokenizer',
'requirements.extension_xml' => 'Module PHP : XML',
'requirements.env_writable' => 'Le fichier .env est présent et accessible en écriture',

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'PHP-bővítmény: JSON',
'requirements.extension_mbstring' => 'PHP-bővítmény: Mbstring',
'requirements.extension_openssl' => 'PHP-bővítmény: OpenSSL',
'requirements.extension_pdo_mysql' => 'PHP-bővítmény: PDO',
'requirements.extension_pdo_mysql' => 'PHP-bővítmény: PDO MySQL',
'requirements.extension_tokenizer' => 'PHP-bővítmény: Tokenizer',
'requirements.extension_xml' => 'PHP-bővítmény: XML',
'requirements.env_writable' => '.env-fájl jelen van és írható',

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'Estensione PHP: JSON',
'requirements.extension_mbstring' => 'Estensione PHP: Mbstring',
'requirements.extension_openssl' => 'Estensione PHP: OpenSSL',
'requirements.extension_pdo_mysql' => 'Estensione PHP: PDO',
'requirements.extension_pdo_mysql' => 'Estensione PHP: PDO MySQL',
'requirements.extension_tokenizer' => 'Estensione PHP: Tokenizer',
'requirements.extension_xml' => 'Estensione PHP: XML',
'requirements.env_writable' => 'Il file .env esiste ed è modificabile',

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'PHP utvidelse: JSON',
'requirements.extension_mbstring' => 'PHP utvidelse: Mbstring',
'requirements.extension_openssl' => 'PHP utvidelse: OpenSSL',
'requirements.extension_pdo_mysql' => 'PHP utvidelse: PDO',
'requirements.extension_pdo_mysql' => 'PHP utvidelse: PDO MySQL',
'requirements.extension_tokenizer' => 'PHP utvidelse: Tokenizer',
'requirements.extension_xml' => 'PHP utvidelse: XML',
'requirements.env_writable' => '.env filen finnes og er skrivbar',

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'Rozszerzenie PHP: JSON',
'requirements.extension_mbstring' => 'Rozszerzenie PHP: Mbstring',
'requirements.extension_openssl' => 'Rozszerzenie PHP: OpenSSL',
'requirements.extension_pdo_mysql' => 'Rozszerzenie PHP: PDO',
'requirements.extension_pdo_mysql' => 'Rozszerzenie PHP: PDO MySQL',
'requirements.extension_tokenizer' => 'Rozszerzenie PHP: Tokenizer',
'requirements.extension_xml' => 'Rozszerzenie PHP: XML',
'requirements.env_writable' => 'Plik .env jest obecny i zapisywalny',

View File

@ -14,6 +14,6 @@ return [
*/
'previous' => '« Anterior',
'next' => 'Următoarea »',
'next' => 'Următorul »',
];

View File

@ -14,17 +14,18 @@ return [
'empty_lists' => 'fără liste',
'order_by' => 'Ordonare după',
'order_by.title:asc' => 'Titlul A-Z',
'order_by.title:desc' => 'Titlul Z-A',
'order_by.title:asc' => 'Titlu A-Z',
'order_by.title:desc' => 'Titlu Z-A',
'order_by.url:asc' => 'URL A-Z',
'order_by.url:desc' => 'URL Z-A',
'order_by.created_at:asc' => 'Cele mai vechi',
'order_by.created_at:desc' => 'Cele mai noi',
'order_by.number_links:asc' => 'Link-uri cel mai puțin',
'order_by.number_links:desc' => 'Cele mai multe link-uri',
'order_by.number_links:asc' => 'Cele mai puține linkuri',
'order_by.number_links:desc' => 'Cele mai multe linkuri',
'order_by.random' => 'Aleatoriu',
'no_results' => 'Niciun rezultat găsit.',
'results_for' => 'Rezultate pentru',
'validation_query_missing' => 'Trebuie fie să introduci o interogare de căutare, fie să selectezi o listă, o etichetă sau să activezi căutarea pentru legături nefuncționale.',
];

View File

@ -11,6 +11,7 @@ return [
'intro.step2' => 'Configurează o bază de date și verifică dacă se realizează conexiunea la aceasta.',
'intro.step3' => 'Creează-ți contul de utilizator.',
'setup_requirements' => 'Cerințe de configurare',
'check_requirements' => 'Verificare cerințe',
'requirements.php_version' => 'Versiune PHP >= 7.4.0',
'requirements.extension_bcmath' => 'Extensie PHP: BCMath',
@ -18,7 +19,7 @@ return [
'requirements.extension_json' => 'Extensie PHP: JSON',
'requirements.extension_mbstring' => 'Extensie PHP: Mbstring',
'requirements.extension_openssl' => 'Extensie PHP: OpenSSL',
'requirements.extension_pdo_mysql' => 'Extensie PHP: PDO',
'requirements.extension_pdo_mysql' => 'Extensie PHP: PDO MySQL',
'requirements.extension_tokenizer' => 'Extensie PHP: Tokenizer',
'requirements.extension_xml' => 'Extensie PHP: XML',
'requirements.env_writable' => 'Fișierul .env există și este inscripționabil',

27
lang/ru_RU/auth.php Normal file
View File

@ -0,0 +1,27 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'Учетные данные не совпадают с нашими записями.',
'throttle' => 'Слишком много попыток входа. Пожалуйста, повторите попытку через :seconds секунд.',
'confirm_title' => 'Требуется подтверждение',
'confirm' => 'Пожалуйста, подтвердите это действие, используя свой текущий пароль.',
'confirm_action' => 'Подтвердить действие',
'two_factor' => 'Двухфакторная аутентификация',
'two_factor_check' => 'Пожалуйста, введите одноразовый пароль, предоставленный вашим приложением для двухфакторной аутентификации.',
'two_factor_with_recovery' => 'Аутентификация с помощью кода восстановления',
];

10
lang/ru_RU/export.php Normal file
View File

@ -0,0 +1,10 @@
<?php
return [
'export' => 'Экспорт',
'start_export_html' => 'Экспорт в HTML',
'start_export_csv' => 'Экспорт в CSV',
'export_help' => 'Запуск экспорта сохранит все существующие закладки в обычный файл, совместимый с закладками, или CSV-файл, если хотите.',
'export_csv_error' => 'При попытке сгенерировать CSV-файл произошла ошибка. Пожалуйста, проверьте файл журнала для получения более подробной информации.',
];

14
lang/ru_RU/import.php Normal file
View File

@ -0,0 +1,14 @@
<?php
return [
'import' => 'Импорт',
'start_import' => 'Импортировать',
'import_running' => 'Выполняется импорт...',
'import_file' => 'Файл для импорта',
'import_help' => 'Вы можете импортировать ваши существующие закладки браузера. Обычно закладки экспортируются в файл .html вашим браузером. Выберите файл здесь и запустите импорт.<br>В зависимости от количества закладок, этот процесс может занять некоторое время.',
'import_networkerror' => 'Что-то пошло не так при попытке импортировать закладки. Пожалуйста, проверьте консоль вашего браузера для получения подробной информации или посмотрите журнал приложения.',
'import_error' => 'Что-то пошло не так при попытке импортировать закладки. Пожалуйста, ознакомьтесь с журналом событий.',
'import_empty' => 'Не удалось импортировать закладки. Загруженный файл поврежден или пуст.',
'import_successfully' => ':imported ссылок импортировано успешно, :skipped пропущено.',
];

69
lang/ru_RU/link.php Normal file
View File

@ -0,0 +1,69 @@
<?php
return [
'link' => 'Ссылка',
'links' => 'Ссылки',
'all_links' => 'Все ссылки',
'recent_links' => 'Недавние ссылки',
'no_links' => 'Нет ссылок',
'add' => 'Добавить ссылку',
'add_quick' => 'Быстро добавить ссылку',
'show' => 'Показать ссылку',
'details' => 'Детали ссылки',
'edit' => 'Изменить ссылку',
'update' => 'Обновить ссылку',
'delete' => 'Удалить ссылку',
'private' => 'Приватная ссылка',
'history' => 'История',
'history_added' => 'Добавлено <code>:newvalue</code> в :fieldname.',
'history_changed' => 'Изменено :fieldname с <code>:oldvalue</code> на <code>:newvalue</code>',
'history_removed' => 'Удалено <code>:oldvalue</code> из :fieldname.',
'history_deleted' => 'Ссылка была удалена',
'history_restored' => 'Ссылка была восстановлена',
'history_created' => 'Ссылка была создана',
'url' => 'URL',
'title' => 'Название',
'description' => 'Описание',
'revtags' => 'Теги',
'revlists' => 'Списки',
'is_private' => 'Частный статус',
'status' => 'Статус',
'stati' => [
'1' => 'Работает',
'2' => 'Перемещено',
'3' => 'Недоступно',
],
'author' => 'от :user',
'external_link' => 'Внешняя ссылка',
'wayback' => 'Архив ссылок @ Wayback Machine',
'check_disable' => 'Отключить проверку',
'check_disabled' => 'Проверка отключена',
'check_enable' => 'Включить проверку',
'check_enabled' => 'Проверка включена',
'status_is_broken' => 'Ссылка помечена как неработающая',
'status_mark_working' => 'Пометить как рабочую',
'added_successfully' => 'Ссылка успешно добавлена.',
'added_connection_error' => 'Ссылка была добавлена, но при попытке доступа к URL-адресу произошла ошибка подключения. Подробности можно найти в журналах.',
'added_request_error' => 'Ссылка была добавлена, но при попытке запросить URL-адрес произошла ошибка, например, неверный сертификат. Подробности можно найти в журналах.',
'updated_successfully' => 'Ссылка успешно обновлена.',
'deleted_successfully' => 'Ссылка успешно удалена.',
'deletion_error' => 'Ссылка не может быть удалена.',
'duplicates_found' => 'LinkAce нашел возможные дубликаты отправленного URL-адреса:',
'existing_found' => 'Ссылка с этим URL-адресом уже существует.',
'notifications.linkcheck.errors' => 'LinkAce нашёл ошибки при проверке ваших ссылок.',
'notifications.linkcheck.errors.moved' => '⚠ Следующие ссылки перенесены в новое местоположение:',
'notifications.linkcheck.errors.broken' => '🚫 Следующие ссылки больше недоступны или возвращают ошибку:',
'happy_bookmarking' => 'Приятного сохранения ссылок',
];

31
lang/ru_RU/list.php Normal file
View File

@ -0,0 +1,31 @@
<?php
return [
'list' => 'Список',
'lists' => 'Списки',
'all_lists' => 'Все списки',
'recent_lists' => 'Недавние списки',
'add' => 'Добавить список',
'show' => 'Показать список',
'edit' => 'Изменить список',
'update' => 'Обновить список',
'delete' => 'Удалить список',
'filter_lists' => 'Фильтровать списки...',
'private' => 'Закрытый список',
'name' => 'Имя списка',
'description' => 'Описание списка',
'author' => 'от :user',
'no_lists' => 'Нет списков',
'number_links' => ':number ссылка в этом списке|:number ссылок в этом списке',
'added_successfully' => 'Список успешно добавлен.',
'updated_successfully' => 'Список успешно обновлен.',
'deleted_successfully' => 'Список успешно удален.',
'deletion_error' => 'Список не может быть удален.',
];

20
lang/ru_RU/note.php Normal file
View File

@ -0,0 +1,20 @@
<?php
return [
'note' => 'Заметка',
'notes' => 'Заметки',
'add' => 'Добавить заметку',
'show' => 'Показать заметку',
'edit' => 'Изменить заметку',
'update' => 'Обновить заметку',
'delete' => 'Удалить заметку',
'private' => 'Личная заметка',
'note_content' => 'Содержание заметки',
'added_successfully' => 'Заметка успешно добавлена.',
'updated_successfully' => 'Заметка успешно обновлена.',
'deleted_successfully' => 'Заметка успешно удалена.',
'deletion_error' => 'Заметка не может быть удалена.',
];

19
lang/ru_RU/pagination.php Normal file
View File

@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Предыдущий',
'next' => 'Следующий &raquo;',
];

22
lang/ru_RU/passwords.php Normal file
View File

@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'password' => 'Пароли должны содержать не менее 6 символов и совпадать с подтверждением.',
'reset' => 'Ваш пароль был сброшен!',
'sent' => 'Если учетная запись с вашим адресом электронной почты существует, мы отправили ссылку для сброса пароля.',
'token' => 'Этот токен сброса пароля недействителен.',
'user' => "Мы не можем найти пользователя с таким e-mail адресом.",
];

View File

@ -0,0 +1,20 @@
<?php
return [
'username' => 'johndoe',
'email' => 'john.doe@example.com',
'password' => 'Пароль',
'password_confirmed' => 'Подтверждение пароля',
'link_url' => 'https://github.com/Kovah/LinkAce',
'link_title' => 'Заголовок сайта',
'list_select' => 'Выберите список',
'tags_select' => 'Выберите несколько тегов',
'list_name' => 'Фактическое название списка',
'tag_name' => 'Фактическое название метки',
'two_factor_otp' => 'Одноразовый пароль',
'two_factor_recovery_code' => 'Код восстановления',
];

106
lang/ru_RU/settings.php Normal file
View File

@ -0,0 +1,106 @@
<?php
return [
'settings' => 'Настройки',
'user_settings' => 'Настройки пользователя',
'account_settings' => 'Настройки аккаунта',
'app_settings' => 'Настройки приложения',
'system_settings' => 'Настройки системы',
'guest_settings' => 'Настройки для гостей',
'language' => 'Язык',
'timezone' => 'Часовой пояс',
'date_format' => 'Формат даты',
'time_format' => 'Формат времени',
'listitem_count' => 'Количество элементов в списках',
'links_new_tab' => 'Открывать внешние ссылки в новой вкладке',
'markdown_for_text' => 'Включить Markdown для описаний и заметок',
'privacy' => 'Конфиденциальность',
'links_private_default' => 'Закрытые ссылки по умолчанию',
'links_private_default_help' => 'Включение этого параметра сделает все новые ссылки закрытыми по умолчанию',
'notes_private_default' => 'Личные заметки по умолчанию',
'notes_private_default_help' => 'Включение этого параметра сделает все новые заметки закрытыми по умолчанию',
'tags_private_default' => 'Закрытые метки по умолчанию',
'tags_private_default_help' => 'Включение этого параметра сделает все новые метки закрытыми по умолчанию',
'lists_private_default' => 'Закрытые списки по умолчанию',
'lists_private_default_help' => 'Включение этого параметра сделает все новые списки закрытыми по умолчанию',
'archive_backups' => 'Резервные копии Wayback Machine',
'archive_backups_help' => 'Если включено, LinkAce сообщит <a href="https://archive.org/">Wayback машине</a> о необходимости сделать резервную копию ваших ссылок. Сервис Wayback Machine работает на базе некоммерческой организации Internet Archive. Пожалуйста, подумайте о <a href="https://archive.org/donate/">пожертвовании в пользу Internet Archive </a>.',
'archive_backups_enabled' => 'Включить резервное копирование',
'archive_backups_enabled_help' => 'При включении опции не закрытые ссылки будут сохраняться в Internet Archive.',
'archive_private_backups_enabled' => 'Включить резервное копирование для личных ссылок',
'archive_private_backups_enabled_help' => 'При включении опции личные ссылки также будут сохранены. Резервное копирование должно быть включено.',
'display_mode' => 'Отображать ссылки в виде',
'display_mode_list_detailed' => 'более детальный список',
'display_mode_list_simple' => 'менее детальный список',
'display_mode_cards' => 'менее детальные карточки',
'display_mode_cards_detailed' => 'более детальные карточки',
'sharing' => 'Обмен ссылками',
'sharing_help' => 'Включите все сервисы, которые вы хотите отображать для ссылок, чтобы легко поделиться ими одним щелчком.',
'sharing_toggle' => 'Все вкл./выкл.',
'darkmode' => 'Темный режим',
'darkmode_help' => 'Вы можете выбрать включение темного режима постоянно или автоматически в зависимости от настроек вашего устройства. (<small>Проверьте <a href="https://caniuse.com/#search=prefers-color-scheme">здесь</a>, поддерживает ли ваш браузер автоматическое определение</small>)',
'darkmode_disabled' => 'Отключен',
'darkmode_auto' => 'Автоматически',
'darkmode_permanent' => 'Постоянно',
'save_settings' => 'Сохранить настройки',
'settings_saved' => 'Настройки успешно обновлены!',
'bookmarklet' => 'Букмарклет',
'bookmarklet_button' => 'Перетащите ссылку в свои Закладки или щелкните правой кнопкой мыши и сохраните ссылку как закладку',
'bookmarklet_help' => 'Добавьте этот Букмарклет в свой браузер, чтобы быстро добавлять ссылки с посещаемых вами сайтов, не открывая LinkAce вручную.',
'change_password' => 'Изменить пароль',
'old_password' => 'Старый пароль',
'new_password' => 'Новый пароль',
'new_password2' => 'Повторите новый пароль',
'password_updated' => 'Пароль успешно изменён!',
'old_password_invalid' => 'Старый пароль недействителен!',
'two_factor_auth' => 'Двухфакторная аутентификация',
'two_factor_enable' => 'Включить двухфакторную аутентификацию',
'two_factor_disable' => 'Отключить двухфакторную аутентификацию',
'two_factor_setup_app' => 'Включена двухфакторная аутентификация. Пожалуйста, настройте свое устройство аутентификации прямо сейчас, отсканировав следующий QR-код.',
'two_factor_setup_url' => 'QR-код не работает? Вы также можете использовать этот URL напрямую.',
'two_factor_recovery_codes' => 'Храните эти коды восстановления в безопасном месте. Они могут быть использованы для восстановления доступа к вашей учетной записи, если ваше устройство двухфакторной аутентификации утеряно.',
'two_factor_recovery_codes_view' => 'Просмотр кодов восстановления',
'two_factor_regenerate_recovery_codes' => 'Генерировать новые коды восстановления',
'api_token' => 'Токен API',
'api_token_generate' => 'Сгенерировать токен',
'api_token_generate_confirm' => 'Вы действительно хотите сгенерировать новый токен?',
'api_token_help' => 'Ключ API может быть использован для доступа к LinkAce из других приложений или скриптов.',
'api_token_generate_info' => 'Внимание: Если у вас уже есть ключ API, генерация нового токена нарушит все существующие интеграции!',
'api_token_generate_failure' => 'Не удалось сгенерировать новый API токен. Пожалуйста, проверьте консоль браузера и журналы приложений для получения дополнительной информации.',
'sys_page_title' => 'Название страницы',
'sys_guest_access' => 'Гостевой доступ',
'sys_guest_access_help' => 'Если включено, гость будет иметь возможность видеть все ссылки, которые не являются приватными.',
'sys_custom_header_content' => 'Пользовательское содержимое заголовка',
'sys_custom_header_content_help' => 'Содержимое, введенное здесь, будет размещено перед тегом &lt;/head&gt; на всех сайтах LinkAce. Это полезно для размещения аналитики или скриптов настройки. Внимание: содержимое не экранируется и может повредить сайт!',
'cron_token' => 'Токен Cron',
'cron_token_generate' => 'Сгенерировать токен',
'cron_token_generate_confirm' => 'Вы действительно хотите сгенерировать новый токен?',
'cron_token_help' => 'Для запуска сервиса cron, который проверяет нерабочие ссылки или выполняет резервное копирование, требуется токен cron.',
'cron_token_url' => 'Укажите вашему cron следующий URL: <span class="cron-token-url">:route</span>',
'cron_token_generate_info' => 'Внимание: если у вас уже есть токен cron, создание нового нарушит существующую задачу cron!',
'cron_token_generate_failure' => 'Новый токен cron не может быть сгенерирован. Пожалуйста, проверьте консоль вашего браузера и логи приложения для получения дополнительной информации.',
'cron_token_auth_failure' => 'Предоставленный токен cron недействителен',
'cron_execute_successful' => 'Cron успешно выполнен',
'update_check' => 'Проверка обновления',
'update_check_running' => 'Проверка обновлений...',
'update_check_version_found' => 'Обновление найдено. Версия обновления #VERSION#.',
'update_check_success' => 'Обновлений не найдено.',
'update_check_failed' => 'Не удалось проверить обновления.',
'guest_settings_info' => 'Следующие настройки будут применяться к гостям, посещающим ваш сайт, если включен гостевой доступ.',
];

33
lang/ru_RU/sharing.php Normal file
View File

@ -0,0 +1,33 @@
<?php
return [
'sharetext' => 'Я нашел эту удивительную ссылку, посмотрите: #URL#',
'subject' => 'Посмотрите эту классную ссылку',
'share' => 'Поделиться ссылкой через :service',
'share_link' => 'Поделиться этой ссылкой',
'service' => [
'email' => 'Электронная почта',
'print' => 'Печать',
'facebook' => 'Facebook',
'twitter' => 'Twitter',
'reddit' => 'Reddit',
'pinterest' => 'Pinterest',
'whatsapp' => 'WhatsApp',
'telegram' => 'Telegram',
'fb-messenger' => 'Facebook Messenger',
'wechat' => 'WeChat',
'sms' => 'СМС',
'slack' => 'Slack',
'skype' => 'Skype',
'hackernews' => 'Hacker News',
'discord' => 'Discord',
'mastodon' => 'Mastodon',
'pocket' => 'Pocket',
'flipboard' => 'Flipboard',
'evernote' => 'Evernote',
'trello' => 'Trello',
'buffer' => 'Buffer',
'tumblr' => 'Tumblr',
'xing' => 'Xing',
'linkedin' => 'LinkedIn',
],
];

12
lang/ru_RU/stats.php Normal file
View File

@ -0,0 +1,12 @@
<?php
return [
'stats' => 'Статистика',
'total_links' => 'Всего ссылок',
'total_lists' => 'Всего списков',
'total_tags' => 'Всего тегов',
'total_notes' => 'Всего заметок',
'total_broken_links' => 'Неработающие ссылки',
];

28
lang/ru_RU/tag.php Normal file
View File

@ -0,0 +1,28 @@
<?php
return [
'tag' => 'Тег',
'tags' => 'Теги',
'all_tags' => 'Все теги',
'recent_tags' => 'Недавние теги',
'add' => 'Добавить тег',
'show' => 'Показать тег',
'edit' => 'Изменить тег',
'update' => 'Обновить тег',
'delete' => 'Удалить тег',
'filter_tags' => 'Фильтровать теги...',
'private' => 'Закрытые теги',
'name' => 'Имя тега',
'author' => 'от :user',
'no_tags' => 'Нет тегов',
'added_successfully' => 'Тег успешно добавлен.',
'updated_successfully' => 'Тег успешно обновлён.',
'deleted_successfully' => 'Тег успешно удалён.',
'deletion_error' => 'Тег не может быть удалён.',
];

31
lang/ru_RU/trash.php Normal file
View File

@ -0,0 +1,31 @@
<?php
return [
'trash' => 'Корзина',
'deleted_links' => 'Удалённые ссылки',
'deleted_lists' => 'Удалённые списки',
'deleted_tags' => 'Удаленные теги',
'deleted_notes' => 'Удалённые заметки',
'restore' => 'Восстановить запись',
'clear_trash' => 'Очистить корзину',
'delete_warning' => 'Окончательно удаленные записи не могут быть восстановлены!',
'delete_no_entries' => 'Нет записей для удаления.',
'delete_success.links' => 'Все ссылки удалены безвозвратно.',
'delete_success.lists' => 'Все списки удалены безвозвратно.',
'delete_success.tags' => 'Все теги удалены безвозвратно.',
'delete_success.notes' => 'Все заметки удалены безвозвратно.',
'restore.link' => 'Восстановлена ссылка из корзины.',
'restore.list' => 'Восстановлен список из корзины.',
'restore.tag' => 'Восстановлена метка из корзины.',
'restore.note' => 'Восстановлена заметка из корзины.',
'restore.not_found' => 'Элемент, подлежащий восстановлению, не найден.',
'restore.not_allowed' => 'Вы не можете восстановить этот элемент.',
];

10
lang/ru_RU/user.php Normal file
View File

@ -0,0 +1,10 @@
<?php
return [
'user' => 'Пользователь',
'users' => 'Пользователи',
'username' => 'Имя пользователя',
'email' => 'Email',
'hello' => 'Привет, :user!',
];

146
lang/ru_RU/validation.php Normal file
View File

@ -0,0 +1,146 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => ':attribute должен быть принят.',
'active_url' => ':attribute некорректный URL.',
'after' => 'В поле :attribute должна быть дата после :date.',
'after_or_equal' => 'В поле :attribute должна быть дата после или равняться :date.',
'alpha' => 'Поле :attribute может содержать только буквы.',
'alpha_dash' => 'Поле :attribute может содержать только буквы, цифры, дефисы и подчеркивания.',
'alpha_num' => 'Поле :attribute может содержать только буквы и цифры.',
'array' => 'Атрибут: должен быть массивом.',
'before' => 'В поле :attribute должна быть дата до :date.',
'before_or_equal' => 'В поле :attribute должна быть дата до или равна :date.',
'between' => [
'numeric' => 'Поле :attribute должно быть между :min и :max.',
'file' => 'Размер файла в поле :attribute должен быть между :min и :max килобайт.',
'string' => 'Количество символов в поле :attribute должно быть между :min и :max.',
'array' => 'Количество элементов в поле :attribute должно быть между :min и :max.',
],
'boolean' => 'Поле :attribute должно быть true или false.',
'confirmed' => 'Поле :attribute не совпадает с подтверждением.',
'date' => 'Поле :attribute не является датой.',
'date_format' => 'Поле :attribute не соответствует формату :format.',
'different' => 'Поля :attribute и :other должны различаться.',
'digits' => ':attribute должен содержать :digits цифр.',
'digits_between' => 'Длина цифрового поля :attribute должна быть между :min и :max.',
'dimensions' => 'Поле :attribute имеет недопустимые размеры изображения.',
'distinct' => 'Поле :attribute содержит повторяющееся значение.',
'email' => 'Поле :attribute должно быть действительным адресом электронной почты.',
'exists' => 'Выбранное значение для :attribute некорректно.',
'file' => ':attribute должно быть файлом.',
'filled' => 'Поле :attribute должно иметь значение.',
'gt' => [
'numeric' => 'Поле :attribute не может быть больше :value.',
'file' => 'Поле :attribute должно быть больше :value килобайт.',
'string' => 'Поле :attribute должно содержать более :value символов.',
'array' => 'Поле :attribute должно содержать более :value элементов.',
],
'gte' => [
'numeric' => 'Поле :attribute должно быть больше или равно :value.',
'file' => 'Поле :attribute должно быть больше или равно :value килобайт.',
'string' => 'Поле :attribute должно содержать :value символов или больше.',
'array' => 'Поле :attribute должно содержать :value элементов или больше.',
],
'image' => 'Поле :attribute должно быть изображением.',
'in' => 'Выбранное значение поля :attribute недопустимо.',
'in_array' => 'Поле :attribute не существует в :other.',
'integer' => 'Поле :attribute должно быть целым числом.',
'ip' => 'Поле :attribute должно быть допустимым IP-адресом.',
'ipv4' => 'Поле :attribute должно быть допустимым IPv4-адресом.',
'ipv6' => 'Поле :attribute должно быть допустимым IPv6-адресом.',
'json' => 'Поле :attribute должно быть допустимой JSON строкой.',
'lt' => [
'numeric' => 'Поле :attribute должно быть меньше :value.',
'file' => 'Поле :attribute должно быть меньше :value килобайт.',
'string' => 'Поле :attribute должно содержать меньше :value символов.',
'array' => 'Поле :attribute должно содержать менее :value элементов.',
],
'lte' => [
'numeric' => 'Поле :attribute должно быть меньше или равно :value.',
'file' => 'Поле :attribute должно быть меньше или равно :value килобайт.',
'string' => 'Поле :attribute должно содержать :value символов или меньше.',
'array' => 'Поле :attribute не должно содержать более :value элементов.',
],
'max' => [
'numeric' => 'Поле :attribute не может быть больше :max.',
'file' => 'Поле :attribute не может быть больше :max килобайт.',
'string' => 'Поле :attribute не может содержать более :max символов.',
'array' => 'Поле :attribute не может содержать более :max элементов.',
],
'mimes' => 'Поле :attribute должно быть файлом типа: :values.',
'mimetypes' => 'Поле :attribute должно быть файлом типа: :values.',
'min' => [
'numeric' => 'Поле :attribute должно содержать как минимум :min символов.',
'file' => 'Размер файла в поле :attribute должен быть не менее :min килобайт.',
'string' => 'Поле :attribute должен содержать как минимум :min символов.',
'array' => 'Поле :attribute должно содержать как минимум :min элементов.',
],
'not_in' => 'Выбранное значение для :attribute недопустимо.',
'not_regex' => 'Неправильный формат :attribute.',
'numeric' => 'Поле :attribute должно быть числом.',
'present' => 'Поле :attribute field должно присутствовать.',
'regex' => 'Неправильный формат :attribute.',
'required' => 'Поле :attribute обязательно для заполнения.',
'required_if' => 'Поле :attribute обязательно для заполнения, когда :other равно :value.',
'required_unless' => 'Поле ":attribute" обязательно, если ":other" находится в ":values".',
'required_with' => 'Поле :attribute обязательно для заполнения, когда :values указано.',
'required_with_all' => 'Поле :attribute обязательно для заполнения, когда :values указано.',
'required_without' => 'Поле :attribute обязательно для заполнения, когда :values не указано.',
'required_without_all' => 'Поле :attribute обязательно для заполнения, когда ни одно из :values не указано.',
'same' => 'Значение :attribute должно совпадать с :other.',
'size' => [
'numeric' => 'Поле :attribute должно быть равным :size.',
'file' => 'Размер файла в поле :attribute должен быть равен :size Кб.',
'string' => 'Количество символов :attribute должно быть из :size символов.',
'array' => 'Количество элементов в поле :attribute должно быть равным :size.',
],
'string' => ':attribute должен быть строкой.',
'timezone' => ':attribute должен быть действительной зоной.',
'unique' => ':attribute уже занят.',
'uploaded' => 'Не удалось загрузить :attribute.',
'url' => 'Неправильный формат :attribute.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'настраиваемое-сообщение',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => [],
];

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'PHP Extension: JSON',
'requirements.extension_mbstring' => 'PHP Extension: Mbstring',
'requirements.extension_openssl' => 'PHP Extension: OpenSSL',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO MySQL',
'requirements.extension_tokenizer' => 'PHP Extension: Tokenizer',
'requirements.extension_xml' => 'PHP Extension: XML',
'requirements.env_writable' => 'File .env đang tồn tại và có thể ghi được',

View File

@ -18,7 +18,7 @@ return [
'requirements.extension_json' => 'PHP Extension: JSON',
'requirements.extension_mbstring' => 'PHP Extension: Mbstring',
'requirements.extension_openssl' => 'PHP Extension: OpenSSL',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO',
'requirements.extension_pdo_mysql' => 'PHP Extension: PDO MySQL',
'requirements.extension_tokenizer' => 'PHP Extension: Tokenizer',
'requirements.extension_xml' => 'PHP Extension: XML',
'requirements.env_writable' => '.env 文件已存在并可写',

1777
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "linkace",
"version": "1.12.2",
"version": "1.14.0",
"description": "A small, selfhosted bookmark manager with advanced features, built with Laravel and Docker",
"homepage": "https://github.com/Kovah/LinkAce",
"repository": {

View File

@ -98,9 +98,7 @@ export default class TagsSelect {
this.$suggestionsContent.innerHTML = '';
tags.forEach(newTag => {
newTag = newTag.trim();
tags.slice(0, 20).forEach(newTag => {
const $tag = document.createElement('span');
$tag.classList.add('btn', 'btn-outline-secondary', 'btn-xs');
$tag.innerText = newTag;

View File

@ -76,7 +76,7 @@ export default class UrlField {
return;
}
fetch(window.appData.routes.fetch.htmlForUrl, {
fetch(window.appData.routes.fetch.keywordsForUrl, {
method: 'POST',
credentials: 'same-origin',
headers: {'Content-Type': 'application/json'},
@ -85,25 +85,11 @@ export default class UrlField {
url: url
})
})
.then(response => response.text())
.then(body => {
if (body !== null) {
this.parseHtmlForKeywords(body);
.then(response => response.json())
.then(data => {
if (data.keywords !== null) {
this.tagSuggestions.displayNewSuggestions(data.keywords);
}
});
}
parseHtmlForKeywords (body) {
const parser = new DOMParser();
const doc = parser.parseFromString(body, 'text/html');
if (doc.head.children.length > 0) {
const keywords = doc.head.children.namedItem('keywords')
|| doc.head.children.namedItem('Keywords');
if (keywords !== null && keywords.content.length > 0) {
this.tagSuggestions.displayNewSuggestions(keywords.content.split(','));
}
}
}
}

View File

@ -21,7 +21,7 @@ $teal: #20c997;
$cyan: #5bc0de;
$primary: $blue;
$secondary: $gray-500;
$secondary: $gray-400;
$success: $green;
$info: $cyan;
$warning: $yellow;
@ -71,8 +71,7 @@ $color-contrast-light: $black;
// Body
$body-bg: $darkmode-bg-darker;
$body-color: $gray-300;
$body-color-pale: $gray-400;
$body-color-muted: $gray-600;
$body-color-pale: $gray-500;
// Components
@ -90,6 +89,7 @@ $headings-color: $white;
// Tables
$table-color: $white;
$table-bg: $darkmode-bg;
$table-accent-bg: rgba($white, .05);
$table-hover-bg: $gray-900;
@ -99,6 +99,7 @@ $table-dark-border-color: $table-border-color;
$table-dark-color: $white;
// Forms
$input-bg: $gray-800;
$input-disabled-bg: $darkmode-bg-darkest;
@ -140,7 +141,7 @@ $pagination-hover-border-color: $darkmode-bg;
$pagination-active-bg: $gray-800;
$pagination-active-border-color: $darkmode-bg;
$pagination-disabled-color: $body-color-muted;
$pagination-disabled-color: $body-color-pale;
$pagination-disabled-bg: transparent;
$pagination-disabled-border-color: $pagination-border-color;
@ -161,6 +162,7 @@ $list-group-bg: $darkmode-bg;
$list-group-color: $body-color;
$list-group-border-color: $darkmode-bg-darker;
$list-group-hover-bg: $darkmode-bg-dark;
$list-group-hover-bg: $darkmode-bg-dark;
$list-group-active-color: $white;
$list-group-active-bg: $list-group-hover-bg;
@ -169,6 +171,7 @@ $list-group-active-border-color: $list-group-border-color;
$list-group-disabled-color: $gray-700;
$list-group-action-color: $white;
$list-group-action-hover-color: $white;
$list-group-action-active-color: $white;
$list-group-action-active-bg: $darkmode-bg-dark;

View File

@ -94,7 +94,7 @@ $enable-caret: false;
// Body
$body-color: $black;
$body-bg: $white;
$body-secondary-color: $gray-600;
$body-color-pale: $gray-500;
// Links
@ -120,8 +120,6 @@ $font-weight-normal: 400;
$font-size-base: 1rem;
$font-size-xs: $font-size-base * .75;
$text-muted: $body-secondary-color;
// Tables
$table-dark-bg: $gray-900;
@ -137,7 +135,7 @@ $input-btn-padding-x-xs: .3rem;
$input-btn-font-size-xs: $font-size-xs;
$input-btn-line-height-xs: $line-height-sm;
$input-placeholder-color: $text-muted;
$input-placeholder-color: $body-color-pale;
$input-btn-border-width: $border-width;

View File

@ -75,7 +75,7 @@ body:not(.bookmarklet) {
}
label {
color: $text-muted;
color: $body-color-pale;
cursor: pointer;
}
@ -108,7 +108,7 @@ a.badge {
}
.text-pale {
color: $body-secondary-color;
color: $body-color-pale !important;
}
.btn-xs {

View File

@ -33,3 +33,7 @@
white-space: normal;
max-width: 100%;
}
.table > :not(caption) > * > * {
box-shadow: none !important;
}

View File

@ -24,7 +24,7 @@ $select-color-dropdown-border-top: $input-border-color;
$select-color-dropdown-border-top: $darkmode-bg-dark;
$select-color-dropdown-item-active: $darkmode-bg-dark;
$select-color-dropdown-item-active-text: $body-color;
$select-color-dropdown-item-create-text: $body-color-muted;
$select-color-dropdown-item-create-text: $body-color-pale;
$select-color-dropdown-item-create-active-text: $body-color;
$select-opacity-disabled: 0.5;
$select-shadow-input: none;

View File

@ -1,7 +1,7 @@
# DOCKERFILE DEVELOPMENT
# Installs MySQL Client for database exports, xDebug with PCov and Composer
FROM php:8.0.29-fpm
FROM php:8.1.10-fpm
WORKDIR /app
RUN apt-get update && apt-get install -y \

View File

@ -1,8 +1,8 @@
FROM php:8.2-fpm-alpine
FROM php:8.3-fpm-alpine
# Install package and PHP dependencies
RUN apk add --no-cache mariadb-client postgresql postgresql-dev sqlite zip libzip-dev; \
docker-php-ext-configure zip; \
docker-php-ext-install bcmath pdo_mysql pdo_pgsql zip; \
docker-php-ext-install bcmath pdo_mysql pdo_pgsql zip ftp; \
mkdir /ssl-certs; \
docker-php-source delete

View File

@ -2,9 +2,13 @@
# ================================
# PHP Dependency Setup
FROM composer AS builder
FROM linkace/base-image:php-8.3-alpine AS builder
WORKDIR /app
# Pull composer and install required packages
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
RUN apk add --no-cache git
# Make needed parts of the app available in the container
COPY ./app /app/app
COPY ./bootstrap /app/bootstrap
@ -28,11 +32,13 @@ RUN mv vendor/spatie/laravel-backup/resources/lang/de vendor/spatie/laravel-back
mv vendor/spatie/laravel-backup/resources/lang/it vendor/spatie/laravel-backup/resources/lang/it_IT; \
mv vendor/spatie/laravel-backup/resources/lang/no vendor/spatie/laravel-backup/resources/lang/no_NO; \
mv vendor/spatie/laravel-backup/resources/lang/pl vendor/spatie/laravel-backup/resources/lang/pl_PL; \
mv vendor/spatie/laravel-backup/resources/lang/zh-CN vendor/spatie/laravel-backup/resources/lang/zh_CN
mv vendor/spatie/laravel-backup/resources/lang/ro vendor/spatie/laravel-backup/resources/lang/zh_CN; \
mv vendor/spatie/laravel-backup/resources/lang/ru vendor/spatie/laravel-backup/resources/lang/ro_RO; \
mv vendor/spatie/laravel-backup/resources/lang/zh-CN vendor/spatie/laravel-backup/resources/lang/ru_RU
# ================================
# Compile all assets
FROM node:18 AS npm_builder
FROM node:20 AS npm_builder
WORKDIR /srv
COPY ./resources/assets ./resources/assets
@ -43,7 +49,7 @@ RUN npm run production
# ================================
# Prepare the final image
FROM linkace/base-image:php-8.2-alpine
FROM linkace/base-image:php-8.3-alpine
WORKDIR /app
# Copy the app into the container

View File

@ -41,7 +41,7 @@
@lang('linkace.yes')
</option>
</select>
<p class="small text-muted mt-1">@lang('settings.guest_access_enabled_help')</p>
<p class="small text-pale mt-1">@lang('settings.guest_access_enabled_help')</p>
@if ($errors->has('guest_access_enabled'))
<p class="invalid-feedback" role="alert">
{{ $errors->first('guest_access_enabled') }}
@ -62,7 +62,7 @@
<textarea name="custom_header_content" id="custom_header_content" rows="4"
class="form-control{{ $errors->has('custom_header_content') ? ' is-invalid' : '' }}"
>{{ old('custom_header_content', systemsettings('custom_header_content')) }}</textarea>
<p class="small text-muted mt-1">@lang('settings.custom_header_content_help')</p>
<p class="small text-pale mt-1">@lang('settings.custom_header_content_help')</p>
@error('custom_header_content')
<p class="invalid-feedback" role="alert">

View File

@ -29,7 +29,7 @@
{{ $link->shortUrl() }}
</a>
</td>
<td class="text-muted small">{!! $link->addedAt() !!}</td>
<td class="text-pale small">{!! $link->addedAt() !!}</td>
</tr>
@endforeach
</tbody>

View File

@ -23,7 +23,7 @@
@lang('linkace.no')
</option>
</select>
<p class="text-muted small mt-1">@lang('settings.archive_backups_enabled_help')</p>
<p class="text-pale small mt-1">@lang('settings.archive_backups_enabled_help')</p>
@if ($errors->has('archive_backups_enabled'))
<p class="invalid-feedback" role="alert">
{{ $errors->first('archive_backups_enabled') }}
@ -50,7 +50,7 @@
@lang('linkace.no')
</option>
</select>
<p class="text-muted small mt-1">@lang('settings.archive_private_backups_enabled_help')</p>
<p class="text-pale small mt-1">@lang('settings.archive_private_backups_enabled_help')</p>
@if ($errors->has('archive_private_backups_enabled'))
<p class="invalid-feedback" role="alert">
{{ $errors->first('archive_private_backups_enabled') }}

View File

@ -37,7 +37,7 @@
</div>
<details>
<summary class="text-muted small">@lang('settings.two_factor_setup_url')</summary>
<summary class="text-pale small">@lang('settings.two_factor_setup_url')</summary>
<code>{{ $user->twoFactorQrCodeUrl() }}</code>
</details>

View File

@ -27,7 +27,7 @@
@includeWhen($links->isNotempty(), 'app.trash.partials.link-table', ['links' => $links])
@if($links->isEmpty())
<small class="text-muted">@lang('trash.delete_no_entries')</small>
<small class="text-pale">@lang('trash.delete_no_entries')</small>
@endif
</div>
@ -52,7 +52,7 @@
@includeWhen($lists->isNotEmpty(), 'app.trash.partials.list-table', ['lists' => $lists])
@if($lists->isEmpty())
<small class="text-muted">@lang('trash.delete_no_entries')</small>
<small class="text-pale">@lang('trash.delete_no_entries')</small>
@endif
</div>
@ -77,7 +77,7 @@
@includeWhen($tags->isNotEmpty(), 'app.trash.partials.tag-table', ['tags' => $tags])
@if($tags->isEmpty())
<small class="text-muted">@lang('trash.delete_no_entries')</small>
<small class="text-pale">@lang('trash.delete_no_entries')</small>
@endif
</div>
@ -103,7 +103,7 @@
@includeWhen($notes->isNotEmpty(), 'app.trash.partials.note-table', ['notes' => $notes])
@if($notes->isEmpty())
<small class="text-muted">@lang('trash.delete_no_entries')</small>
<small class="text-pale">@lang('trash.delete_no_entries')</small>
@endif
</div>

View File

@ -14,7 +14,7 @@
<td>
{{ $link->url }}
</td>
<td class="text-muted">
<td class="text-pale">
<small>{{ formatDateTime($link->created_at) }}</small>
</td>
<td class="text-end">

View File

@ -14,7 +14,7 @@
<td>
{{ $list->name }}
</td>
<td class="text-muted">
<td class="text-pale">
<small>{{ formatDateTime($list->created_at) }}</small>
</td>
<td class="text-end">

View File

@ -20,7 +20,7 @@
<td>
{{ $note->note }}
</td>
<td class="text-muted">
<td class="text-pale">
<small>{{ formatDateTime($note->created_at) }}</small>
</td>
<td class="text-end">

View File

@ -14,7 +14,7 @@
<td>
{{ $tag->name }}
</td>
<td class="text-muted">
<td class="text-pale">
<small>{{ formatDateTime($tag->created_at) }}</small>
</td>
<td class="text-end">

View File

@ -60,6 +60,6 @@
</div>
</div>
<div class="text-center text-muted mt-3 small">
<div class="text-center text-pale mt-3 small">
{!! trans('linkace.forgot_password_link', ['reset_url' => route('password.request')]) !!}
</div>

View File

@ -67,7 +67,7 @@
{{ $link->title }}
</a>
@empty
<li class="list-group-item text-danger">
<li class="list-group-item text-pale">
@lang('linkace.no_results_found', ['model' => trans('link.links')])
</li>
@endforelse
@ -130,7 +130,7 @@
<x-models.name-with-user :model="$list"/>
</a>
@empty
<div class="text-danger">
<div class="text-pale">
@lang('linkace.no_results_found', ['model' => trans('list.lists')])
</div>
@endforelse
@ -151,7 +151,7 @@
<x-models.name-with-user :model="$tag"/>
</a>
@empty
<div class="text-danger">
<div class="text-pale">
@lang('linkace.no_results_found', ['model' => trans('tag.tags')])
</div>
@endforelse

View File

@ -10,12 +10,12 @@
{{ $link->shortTitle() }}
</a>
<br>
<small class="text-muted">{{ $link->shortUrl() }}</small>
<small class="text-pale">{{ $link->shortUrl() }}</small>
</div>
</div>
</div>
<div class="px-3 py-2 text-xs text-muted text-end">
<div class="px-3 py-2 text-xs text-pale text-end">
@lang('linkace.added') {!! $link->addedAt() !!}
</div>
</div>

View File

@ -9,7 +9,7 @@
<div>
<a href="{{ $link->url }}" {!! linkTarget() !!}>{{ $link->title }}</a>
<br>
<small class="text-muted">{{ $link->shortUrl() }}</small>
<small class="text-pale">{{ $link->shortUrl() }}</small>
</div>
</div>
<div class="ms-auto text-end">
@ -45,12 +45,12 @@
@endif
@endforeach
@else
<span class="small text-muted">@lang('tag.no_tags')</span>
<span class="small text-pale">@lang('tag.no_tags')</span>
@endif
</div>
<div class="col-12 col-sm-6 d-sm-flex align-items-sm-center justify-content-sm-end flex-wrap">
<div class="text-xs text-muted mt-3 mt-sm-0">
<div class="text-xs text-pale mt-3 mt-sm-0">
@lang('linkace.added') {!! $link->addedAt() !!}
</div>
</div>

View File

@ -7,7 +7,7 @@
</a>
</div>
<div class="mt-2 mt-sm-0 ms-auto flex-shrink-0">
<small class="text-muted">{!! $link->domainOfURL() !!}</small>
<small class="text-pale">{!! $link->domainOfURL() !!}</small>
</div>
</div>
</li>

View File

@ -7,7 +7,7 @@
{{ $link->url }}
</a>
</td>
<td class="text-muted">
<td class="text-pale">
<small>
{!! $link->addedAt() !!}
</small>

View File

@ -39,7 +39,7 @@
</div>
</div>
<div class="col-xs-12 col-sm-6 text-md-right text-muted">
<div class="col-xs-12 col-sm-6 text-md-right text-pale">
<div>
<small>

View File

@ -10,7 +10,7 @@
</div>
<div class="py-2 px-3">
<div class="text-xs text-muted">
<div class="text-xs text-pale">
@if($list->links_count > 0)
{{ trans_choice('list.number_links', $list->links_count, ['number' => $list->links_count]) }}
@else

View File

@ -7,7 +7,7 @@
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'LinkAce') }}</title>
<title>@isset($pageTitle){{$pageTitle}} - @endisset{{ config('app.name', 'LinkAce') }}</title>
<link href="{{ mix('assets/dist/css/app.css') }}" rel="stylesheet">

View File

@ -23,7 +23,7 @@
<div>
<a href="{{ $link->url }}" {!! linkTarget() !!}>{{ $link->shortTitle() }}</a>
<br>
<small class="text-muted">{{ $link->shortUrl() }}</small>
<small class="text-pale">{{ $link->shortUrl() }}</small>
</div>
</div>
</div>
@ -36,12 +36,12 @@
</a>
@endforeach
@else
<span class="small text-muted">@lang('tag.no_tags')</span>
<span class="small text-pale">@lang('tag.no_tags')</span>
@endif
</div>
<div class="d-flex align-items-center my-1">
<div class="text-muted text-xs me-3 ps-3">
<div class="text-pale text-xs me-3 ps-3">
@lang('linkace.added') {!! $link->addedAt() !!}
</div>

View File

@ -9,13 +9,13 @@
<div>
<a href="{{ $link->url }}" {!! linkTarget() !!}>{{ $link->shortTitle() }}</a>
<br>
<small class="text-muted">{{ $link->shortUrl() }}</small>
<small class="text-pale">{{ $link->shortUrl() }}</small>
</div>
</div>
</div>
<div class="d-flex align-items-center my-1">
<div class="text-muted text-xs me-3 ps-3">
<div class="text-pale text-xs me-3 ps-3">
@lang('linkace.added') {!! $link->addedAt() !!}
</div>

View File

@ -21,9 +21,9 @@
</div>
<div>
<div><a href="{{ $link->url }}" {!! linkTarget() !!}>{{ $link->title }}</a></div>
<div><small class="text-muted">{{ $link->shortUrl(75) }}</small></div>
<div><small class="text-pale">{{ $link->shortUrl(75) }}</small></div>
@if($link->description)
<div class="text-pale"><small>{{ Str::limit($link->description, 200) }}</small></div>
<div><small>{{ Str::limit($link->description, 200) }}</small></div>
@endif
</div>
</div>
@ -62,13 +62,13 @@
</a>
@endforeach
@else
<span class="small text-muted">@lang('tag.no_tags')</span>
<span class="small text-pale">@lang('tag.no_tags')</span>
@endif
</div>
<div class="col-12 col-sm-6 d-sm-flex align-items-sm-center justify-content-sm-end flex-wrap">
<div class="text-xs text-muted mt-3 mt-sm-0">
<div class="text-xs text-pale mt-3 mt-sm-0">
@lang('linkace.added') {!! $link->addedAt() !!}
</div>

Some files were not shown because too many files have changed in this diff Show More