Merge branch 'main' into main

This commit is contained in:
Julian Prieber 2023-12-16 19:15:33 +01:00 committed by GitHub
commit 9d66e05c76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 956 additions and 1146 deletions

View File

@ -123,6 +123,9 @@ jobs:
# Upload 'linkstack.zip' # Upload 'linkstack.zip'
gh release upload "${GITHUB_REF##*/}" "linkstack.zip" --clobber -R "$REPO_NAME" gh release upload "${GITHUB_REF##*/}" "linkstack.zip" --clobber -R "$REPO_NAME"
# Mark the release as the latest
gh release edit "${GITHUB_REF##*/}" --title="${GITHUB_REF##*/}" -R "$REPO_NAME"
fi fi
- name: Update version.json - name: Update version.json

View File

@ -38,11 +38,12 @@ class LinkTypeViewController extends Controller
if (!empty($linkType) && $linkType->typename === 'predefined') { if (!empty($linkType) && $linkType->typename === 'predefined') {
// get buttons list if showing predefined form // get buttons list if showing predefined form
$buttons = Button::select('name')->orderBy('name', 'asc')->get(); $buttons = Button::select()->orderBy('name', 'asc')->get();
foreach ($buttons as $btn) { foreach ($buttons as $btn) {
$data['buttons'][] = [ $data['buttons'][] = [
'name' => $btn->name, 'name' => $btn->name,
'title' => ucwords($btn->name), 'title' => $btn->alt,
'exclude' => $btn->exclude,
'selected' => (is_object($data['params']) && $data['params']->button === $btn->name) 'selected' => (is_object($data['params']) && $data['params']->button === $btn->name)
]; ];
} }

View File

@ -219,7 +219,7 @@ class UserController extends Controller
$button = Button::where('name', $request->button)->first(); $button = Button::where('name', $request->button)->first();
if ($button && empty($LinkTitle)) if ($button && empty($LinkTitle))
$LinkTitle = ucwords($button->name); $LinkTitle = $button->alt;
if ($linkType->typename == 'video' && empty($LinkTitle)) { if ($linkType->typename == 'video' && empty($LinkTitle)) {
$embed = OEmbed::get($LinkURL); $embed = OEmbed::get($LinkURL);

View File

@ -3,6 +3,7 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
class UserData extends Model class UserData extends Model
{ {
@ -11,7 +12,7 @@ class UserData extends Model
public static function saveData($userId, $key, $value) public static function saveData($userId, $key, $value)
{ {
$userData = self::where('id', $userId)->first(); $userData = self::getCachedUserData($userId);
if (!$userData) { if (!$userData) {
return "null"; return "null";
@ -22,35 +23,51 @@ class UserData extends Model
$userData->image = json_encode($data); $userData->image = json_encode($data);
$userData->save(); $userData->save();
self::cacheUserData($userId, $userData);
} }
public static function getData($userId, $key) public static function getData($userId, $key)
{ {
$userData = self::where('id', $userId)->first(); $userData = self::getCachedUserData($userId);
if (!$userData || !$userData->image) { if (!$userData || !$userData->image) {
return "null"; return "null";
} }
$data = json_decode($userData->image, true) ?? []; $data = json_decode($userData->image, true) ?? [];
return isset($data[$key]) ? $data[$key] : null; return isset($data[$key]) ? $data[$key] : null;
} }
public static function removeData($userId, $key) public static function removeData($userId, $key)
{ {
$userData = self::where('id', $userId)->first(); $userData = self::getCachedUserData($userId);
if (!$userData || !$userData->image) { if (!$userData || !$userData->image) {
return "null"; return "null";
} }
$data = json_decode($userData->image, true) ?? []; $data = json_decode($userData->image, true) ?? [];
if (isset($data[$key])) { if (isset($data[$key])) {
unset($data[$key]); unset($data[$key]);
$userData->image = json_encode($data); $userData->image = json_encode($data);
$userData->save(); $userData->save();
self::cacheUserData($userId, $userData);
} }
} }
private static function getCachedUserData($userId)
{
return Cache::remember('user_data_' . $userId, now()->addMinutes(10), function () use ($userId) {
return self::where('id', $userId)->first();
});
}
private static function cacheUserData($userId, $userData)
{
Cache::put('user_data_' . $userId, $userData, now()->addMinutes(10));
}
} }

View File

@ -1,256 +0,0 @@
[
{"value": "REGISTER_AUTH",
"title": "Enable email verification",
"description": "Determines if users have to verify their email when they register."
},
{"value": "ALLOW_REGISTRATION",
"title": "Enable registration",
"description": "Determines whether users can register for your application."
},
{"value": "NOTIFY_EVENTS",
"title": "Notify on events",
"description": "Displays a notification if an event is in progress."
},
{"value": "NOTIFY_UPDATES",
"title": "Notify on updates",
"description": "Displays a notification if a new update is available."
},
{"value": "DISPLAY_FOOTER",
"title": "Show footer",
"description": "Determines whether the footer links should be displayed."
},
{"value": "DISPLAY_CREDIT",
"title": "Display credit on user pages",
"description": "Determines whether the credit notice should be displayed on users pages."
},
{"value": "DISPLAY_CREDIT_FOOTER",
"title": "Display credit in footer",
"description": "Determines whether the credit notice should be displayed in the footer."
},
{"value": "HOME_URL",
"title": "Set user page as Home Page",
"description": "Set user page as Home Page"
},
{"value": "ALLOW_USER_HTML",
"title": "Allow extended syntax in user's descriptions",
"description": "This enables users to use special formatting like headings and links in their page description.<br>This is generally considered safe."
},
{"value": "APP_NAME",
"title": "Application title",
"description": "Sets the title of your app. A change will logout every active user."
},
{"value": "APP_KEY",
"title": "APP_KEY",
"description": "APP_KEY"
},
{"value": "APP_URL",
"title": "APP_URL",
"description": "APP_URL"
},
{"value": "ENABLE_BUTTON_EDITOR",
"title": "Enable Button Editor",
"description": "Determines whether users are allowed to customize their own buttons using CSS."
},
{"value": "APP_DEBUG",
"title": "APP_DEBUG",
"description": "APP_DEBUG"
},
{"value": "APP_ENV",
"title": "APP_ENV",
"description": "APP_ENV"
},
{"value": "LOG_CHANNEL",
"title": "LOG_CHANNEL",
"description": "LOG_CHANNEL"
},
{"value": "LOG_LEVEL",
"title": "LOG_LEVEL",
"description": "LOG_LEVEL"
},
{"value": "MAINTENANCE_MODE",
"title": "Enable Maintenance Mode",
"description": "Displays a maintenance message on all public pages. This will disable the login pages."
},
{"value": "MAIL_MAILER",
"title": "MAIL_MAILER",
"description": "MAIL_MAILER"
},
{"value": "MAIL_HOST",
"title": "MAIL_HOST",
"description": "MAIL_HOST"
},
{"value": "MAIL_PORT",
"title": "MAIL_PORT",
"description": "MAIL_PORT"
},
{"value": "MAIL_USERNAME",
"title": "MAIL_USERNAME",
"description": "MAIL_USERNAME"
},
{"value": "MAIL_PASSWORD",
"title": "MAIL_PASSWORD",
"description": "MAIL_PASSWORD"
},
{"value": "MAIL_ENCRYPTION",
"title": "MAIL_ENCRYPTION",
"description": "MAIL_ENCRYPTION"
},
{"value": "MAIL_FROM_ADDRESS",
"title": "MAIL_FROM_ADDRESS",
"description": "MAIL_FROM_ADDRESS"
},
{"value": "JOIN_BETA",
"title": "Join the Beta Program",
"description": "Enables the use of beta versions when updating. Read more about this <a target='_blank' href='https://linkstack.org/b'>here</a>."
},
{"value": "SKIP_UPDATE_BACKUP",
"title": "Skip update backups",
"description": "Skips backups when updating. This option is recommended to be disabled at all times, <br>but it may cause errors in some configurations."
},
{"value": "CUSTOM_META_TAGS",
"title": "Enable custom meta tags",
"description": "Enables use of custom meta tags in the head of all pages. Defined in Advanced Config."
},
{"value": "FORCE_HTTPS",
"title": "Force links HTTPS",
"description": "Makes all links utilize HTTPS by default. It is advised to enable this option if you are using a reverse proxy."
},
{"value": "ALLOW_CUSTOM_CODE_IN_THEMES",
"title": "Allow custom code in themes",
"description": "Allows use of custom code in themes. If you use themes from unknown sources, <br>this may pose a security risk."
},
{"value": "ENABLE_THEME_UPDATER",
"title": "Enable Theme Updater",
"description": "Determines if the theme updater should be active."
},
{"value": "ENABLE_SOCIAL_LOGIN",
"title": "Enable social login",
"description": "Enables social login. This option requires further setup. Read more about this <a target='_blank' href='https://linkstack.org/social-login'>here</a>."
},
{"value": "USE_THEME_PREVIEW_IFRAME",
"title": "Use iframe as theme preview",
"description": "Determines if an internal iframe should be used as the preview for them theme page."
},
{"value": "FORCE_ROUTE_HTTPS",
"title": "Redirect all pages to HTTPS",
"description": "This option will break your setup when using a reverse proxy."
},
{"value": "DISPLAY_FOOTER_HOME",
"title": "Home footer link",
"description": "Enable Home footer link."
},
{"value": "DISPLAY_FOOTER_TERMS",
"title": "Terms footer link",
"description": "Enable Terms footer link."
},
{"value": "DISPLAY_FOOTER_PRIVACY",
"title": "Privacy footer link",
"description": "Enable Privacy link."
},
{"value": "DISPLAY_FOOTER_CONTACT",
"title": "Contact footer link",
"description": "Enable Contact link."
},
{"value": "TITLE_FOOTER_HOME",
"title": "<div style=\"margin-top:-40px\"></div>",
"description": "Title of home footer link."
},
{"value": "TITLE_FOOTER_TERMS",
"title": "<div style=\"margin-top:-40px\"></div>",
"description": "Title of terms footer link."
},
{"value": "TITLE_FOOTER_PRIVACY",
"title": "<div style=\"margin-top:-40px\"></div>",
"description": "Title of privacy link."
},
{"value": "TITLE_FOOTER_CONTACT",
"title": "<div style=\"margin-top:-40px\"></div>",
"description": "Title of contact link."
},
{"value": "HOME_FOOTER_LINK",
"title": "<div style=\"margin-top:-40px\">Home footer link URL</div>",
"description": "Enter any URL to redirect your home link URL.<br>Leave empty to use the default link."
},
{"value": "ALLOW_CUSTOM_BACKGROUNDS",
"title": "Allow custom backgrounds",
"description": "Allow users to upload custom background images for their pages."
},
{"value": "ALLOW_USER_IMPORT",
"title": "Allow users to import profiles from other instances",
"description": "Allows users to import their profile and links from an external file."
},
{"value": "ALLOW_USER_EXPORT",
"title": "Allow users to export their profile",
"description": "Allows users to export their own links and profile."
},
{"value": "MANUAL_USER_VERIFICATION",
"title": "Verify users manually",
"description": "Determines if admins have to manually verify newly registered users."
},
{"value": "ADMIN_EMAIL",
"title": "Admin email",
"description": "Used to send notification emails."
},
{"value": "HIDE_VERIFICATION_CHECKMARK",
"title": "Hide verification checkmark",
"description": "Hides verification badge displayed on admin and VIP pages."
}
]

View File

@ -16,6 +16,10 @@ class CreateButtonsTable extends Migration
Schema::create('buttons', function (Blueprint $table) { Schema::create('buttons', function (Blueprint $table) {
$table->id(); $table->id();
$table->string('name'); $table->string('name');
$table->string('alt')->nullable();
$table->boolean('exclude')->default(false);
$table->string('group')->nullable();
$table->boolean('mb')->default(false);
$table->timestamps(); $table->timestamps();
}); });
} }

File diff suppressed because it is too large Load Diff

View File

@ -361,6 +361,8 @@ return [
'disableverified' => 'Sie sind ein verifizierter Benutzer. Mit dieser Einstellung können Sie Ihr Häkchen auf Ihrer Seite ausblenden.', 'disableverified' => 'Sie sind ein verifizierter Benutzer. Mit dieser Einstellung können Sie Ihr Häkchen auf Ihrer Seite ausblenden.',
'Show share button' => 'Teilen-Button anzeigen', 'Show share button' => 'Teilen-Button anzeigen',
'disablesharebutton' => 'Mit dieser Einstellung können Sie die Schaltfläche „Teilen“ auf Ihrer Seite ausblenden.', 'disablesharebutton' => 'Mit dieser Einstellung können Sie die Schaltfläche „Teilen“ auf Ihrer Seite ausblenden.',
'Open links in new tab' => 'Links in neuem Tab öffnen',
'openlinksnewtab' => 'Diese Einstellung bestimmt, ob Ihre Links auf Ihrer Seite im gleichen oder einem neuen Tab geöffnet werden.',
/* /*

View File

@ -358,6 +358,8 @@ return [
'disableverified' => 'You are a verified user. This setting allows you to hide your checkmark on your page.', 'disableverified' => 'You are a verified user. This setting allows you to hide your checkmark on your page.',
'Show share button' => 'Show share button', 'Show share button' => 'Show share button',
'disablesharebutton' => 'This setting allows you to hide the share button on your page.', 'disablesharebutton' => 'This setting allows you to hide the share button on your page.',
'Open links in new tab' => 'Open links in new tab',
'openlinksnewtab' => 'This setting determines if your links on your links page get opened in the same or a new tab.',
/* /*

View File

@ -157,7 +157,6 @@ input[type=radio] + label {
<?php <?php
function toggle($key){ function toggle($key){
$configNames = json_decode(file_get_contents(base_path('config/config-legends.json')));
echo ' echo '
<form id="'.$key.'-form" action="'.route('editConfig').'" enctype="multipart/form-data" method="post"> <form id="'.$key.'-form" action="'.route('editConfig').'" enctype="multipart/form-data" method="post">
<div class="form-group col-lg-8"> <div class="form-group col-lg-8">
@ -182,7 +181,6 @@ document.getElementById("'.$key.'-form").addEventListener("change", function() {
<?php <?php
function toggle2($key){ function toggle2($key){
$configNames = json_decode(file_get_contents(base_path('config/config-legends.json')));
echo ' echo '
<form id="'.$key.'-form" action="'.route('editConfig').'" enctype="multipart/form-data" method="post"> <form id="'.$key.'-form" action="'.route('editConfig').'" enctype="multipart/form-data" method="post">
<div class="form-group col-lg-8"> <div class="form-group col-lg-8">
@ -207,7 +205,6 @@ document.getElementById("'.$key.'-form").addEventListener("change", function() {
<?php <?php
function text($key){ function text($key){
$configNames = json_decode(file_get_contents(base_path('config/config-legends.json')));
$configValue = str_replace('"', "", EnvEditor::getKey($key)); $configValue = str_replace('"', "", EnvEditor::getKey($key));
echo ' echo '
<form id="'.$key.'-form" action="'.route('editConfig').'" enctype="multipart/form-data" method="post"> <form id="'.$key.'-form" action="'.route('editConfig').'" enctype="multipart/form-data" method="post">
@ -413,7 +410,6 @@ document.getElementById("MAINTENANCE_MODE-form").addEventListener("change", func
{{text('TITLE_FOOTER_HOME')}} {{text('TITLE_FOOTER_HOME')}}
@php @php
$configNames = json_decode(file_get_contents(base_path('config/config-legends.json')));
$configValue = str_replace('"', "", EnvEditor::getKey('HOME_FOOTER_LINK')); $configValue = str_replace('"', "", EnvEditor::getKey('HOME_FOOTER_LINK'));
@endphp @endphp
<form id="HOME_FOOTER_LINK-form" action="{{route('editConfig')}}" enctype="multipart/form-data" method="post"> <form id="HOME_FOOTER_LINK-form" action="{{route('editConfig')}}" enctype="multipart/form-data" method="post">

View File

@ -151,19 +151,23 @@ use App\Models\Page;
/* Updates button database entries */ /* Updates button database entries */
Schema::disableForeignKeyConstraints(); Schema::disableForeignKeyConstraints();
$existingMigration = '2021_03_17_044922_create_buttons_table';
try { try {
if (DB::table('migrations')->where('migration', $existingMigration)->exists()) {
DB::table('migrations')->where('migration', $existingMigration)->delete();
}
Schema::dropIfExists('buttons');
$migrator = app('migrator'); $migrator = app('migrator');
$migrator->run(database_path('migrations'), ['--force' => true]); $migrator->run(database_path('migrations'));
} catch (exception $e) {}
try {DB::table('buttons')->delete();} catch (exception $e) {} $seeder = new ButtonSeeder();
try {DB::table('buttons')->truncate();} catch (exception $e) {} $seeder->run();
try {
$seeder = new ButtonSeeder();
$seeder->run();
} catch (exception $e) {} } catch (exception $e) {}
Schema::enableForeignKeyConstraints(); Schema::enableForeignKeyConstraints();
// Adds new column to the users table
if (!Schema::hasColumn('users', 'auth_as')) { if (!Schema::hasColumn('users', 'auth_as')) {
Schema::table('users', function (Blueprint $table) { Schema::table('users', function (Blueprint $table) {
$table->unsignedInteger('auth_as')->nullable(); $table->unsignedInteger('auth_as')->nullable();

View File

@ -4,7 +4,7 @@
<select name='button' class='form-control'> <select name='button' class='form-control'>
@if($buttonName != 0)<option value='{{$buttonName}}'>{{ucfirst($buttonName)}}</option>@endif @if($buttonName != 0)<option value='{{$buttonName}}'>{{ucfirst($buttonName)}}</option>@endif
@foreach ($buttons as $b) @foreach ($buttons as $b)
@if(!in_array($b["name"], ["custom_website", "custom", "custom", "heading", "space", "text", "icon", $buttonName])) @if($b["exclude"] != true)
<option class='button button-{{$b["name"]}}' value='{{$b["name"]}}' {{ $b["selected"] == true ? "selected" : ""}}>{{$b["title"]}}</option> <option class='button button-{{$b["name"]}}' value='{{$b["name"]}}' {{ $b["selected"] == true ? "selected" : ""}}>{{$b["title"]}}</option>
@endif @endif
@endforeach @endforeach

View File

@ -1,4 +1,5 @@
<!-- Buttons --> <?php use App\Models\UserData; ?>
@php $initial = 1; @endphp @php $initial = 1; @endphp
@foreach($links as $link) @foreach($links as $link)
@ -7,14 +8,14 @@
@case('icon') @case('icon')
@break @break
@case('phone') @case('phone')
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-default button button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}"><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/phone{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}phone.svg @endif"></i>{{ $link->title }}</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button button-default button-click button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}"><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/phone{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}phone.svg @endif"></i>{{ $link->title }}</a></div>
@break @break
@case('default email') @case('default email')
@case('default email_alt') @case('default email_alt')
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-default button button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}"><img alt="email" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/email{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}email.svg @endif"></i>{{ $link->title }}</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button button-default button-click button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}"><img alt="email" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/email{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}email.svg @endif"></i>{{ $link->title }}</a></div>
@break @break
@case('buy me a coffee') @case('buy me a coffee')
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-coffee button button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/coffee{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}coffee.svg @endif">Buy me a Coffee</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button button-coffee button-click button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}" @if((UserData::getData($userinfo->id, 'links-new-tab') != false))target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/coffee{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}coffee.svg @endif">Buy me a Coffee</a></div>
@break @break
@case('space') @case('space')
@php $title = $link->title; if (is_numeric($title)) { echo str_repeat("<br>", $title < 10 ? $title : 10); } else { echo "<br><br><br>"; } @endphp @php $title = $link->title; if (is_numeric($title)) { echo str_repeat("<br>", $title < 10 ? $title : 10); } else { echo "<br><br><br>"; } @endphp
@ -26,26 +27,54 @@
<div class="fadein"><span style="">@if(env('ALLOW_USER_HTML') === true){!! $link->title !!}@else{{ $link->title }}@endif</span></div> <div class="fadein"><span style="">@if(env('ALLOW_USER_HTML') === true){!! $link->title !!}@else{{ $link->title }}@endif</span></div>
@break @break
@case('vcard') @case('vcard')
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-default button button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('vcard') . '/' . $link->id }}"><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/vcard{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}vcard.svg @endif"></i>{{ $link->title }}</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button button-default button-click button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('vcard') . '/' . $link->id }}"><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/vcard{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/')}}vcard.svg @endif"></i>{{ $link->title }}</a></div>
@break @break
@case('custom') @case('custom')
@if($link->custom_css === "" or $link->custom_css === "NULL" or (theme('allow_custom_buttons') == "false")) @if($link->custom_css === "" or $link->custom_css === "NULL" or (theme('allow_custom_buttons') == "false"))
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-{{ $link->name }} button button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><i style="color: {{$link->custom_icon}}" class="icon hvr-icon fa {{$link->custom_icon}}"></i>{{ $link->title }}</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button button-{{ $link->name }} button-click button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}" @if((UserData::getData($userinfo->id, 'links-new-tab') != false))target="_blank"@endif ><i style="color: {{$link->custom_icon}}" class="icon hvr-icon fa {{$link->custom_icon}}"></i>{{ $link->title }}</a></div>
@break @break
@elseif($link->custom_css != "") @elseif($link->custom_css != "")
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-hover icon-hover" style="{{ $link->custom_css }}" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><i style="color: {{$link->custom_icon}}" class="icon hvr-icon fa {{$link->custom_icon}}"></i>{{ $link->title }}</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button-click button-hover icon-hover" style="{{ $link->custom_css }}" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}" @if((UserData::getData($userinfo->id, 'links-new-tab') != false))target="_blank"@endif ><i style="color: {{$link->custom_icon}}" class="icon hvr-icon fa {{$link->custom_icon}}"></i>{{ $link->title }}</a></div>
@break @break
@endif @endif
@case('custom_website') @case('custom_website')
@if($link->custom_css === "" or $link->custom_css === "NULL" or (theme('allow_custom_buttons') == "false")) @if($link->custom_css === "" or $link->custom_css === "NULL" or (theme('allow_custom_buttons') == "false"))
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-custom_website button button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(file_exists(base_path("assets/favicon/icons/").localIcon($link->id))){{url('assets/favicon/icons/'.localIcon($link->id))}}@else{{getFavIcon($link->id)}}@endif" onerror="this.onerror=null; this.src='{{asset('assets/linkstack/icons/website.svg')}}';">{{ $link->title }}</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button button-custom_website button-click button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}" @if((UserData::getData($userinfo->id, 'links-new-tab') != false))target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(file_exists(base_path("assets/favicon/icons/").localIcon($link->id))){{url('assets/favicon/icons/'.localIcon($link->id))}}@else{{getFavIcon($link->id)}}@endif" onerror="this.onerror=null; this.src='{{asset('assets/linkstack/icons/website.svg')}}';">{{ $link->title }}</a></div>
@break @break
@elseif($link->custom_css != "") @elseif($link->custom_css != "")
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-hover icon-hover" style="{{ $link->custom_css }}" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(file_exists(base_path("assets/favicon/icons/").localIcon($link->id))){{url('assets/favicon/icons/'.localIcon($link->id))}}@else{{getFavIcon($link->id)}}@endif" onerror="this.onerror=null; this.src='{{asset('assets/linkstack/icons/website.svg')}}';">{{ $link->title }}</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button-click button-hover icon-hover" style="{{ $link->custom_css }}" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}" @if((UserData::getData($userinfo->id, 'links-new-tab') != false))target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(file_exists(base_path("assets/favicon/icons/").localIcon($link->id))){{url('assets/favicon/icons/'.localIcon($link->id))}}@else{{getFavIcon($link->id)}}@endif" onerror="this.onerror=null; this.src='{{asset('assets/linkstack/icons/website.svg')}}';">{{ $link->title }}</a></div>
@break @break
@endif @endif
@default @default
<?php include base_path('config/button-names.php'); $newLinkName = $linkName; $isNewName = "false"; foreach($buttonNames as $key => $value) { if($newLinkName == $key) { $newLinkName = $value; $isNewName = "true"; }} ?> <?php include base_path('config/button-names.php'); $newLinkName = $linkName; $isNewName = "false"; foreach($buttonNames as $key => $value) { if($newLinkName == $key) { $newLinkName = $value; $isNewName = "true"; }} ?>
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-{{ $link->name }} button button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ route('clickNumber') . '/' . $link->id . "?" . $link->link }}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/{{$link->name}}{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/') . $link->name }}.svg @endif">@if($isNewName == "true"){{ ucfirst($newLinkName) }}@else{{ ucfirst($newLinkName) }}@endif</a></div> <div style="--delay: {{ $initial++ }}s" class="button-entrance"><a id="{{ $link->id }}" class="button button-{{ $link->name }} button-click button-hover icon-hover" rel="noopener noreferrer nofollow noindex" href="{{ $link->link }}" @if((UserData::getData($userinfo->id, 'links-new-tab') != false))target="_blank"@endif ><img alt="{{ $link->name }}" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/{{$link->name}}{{theme('custom_icon_extension')}} @else{{ asset('\/assets/linkstack/icons\/') . $link->name }}.svg @endif">@if($isNewName == "true"){{ ucfirst($newLinkName) }}@else{{ ucfirst($newLinkName) }}@endif</a></div>
@endswitch @endswitch
@endforeach @endforeach
<script>
document.addEventListener('DOMContentLoaded', function () {
function handleClickOrTouch(event) {
if (event.target.classList.contains('button-click')) {
var id = event.target.id;
if (!sessionStorage.getItem('clicked-' + id)) {
var url = '{{ route("clickNumber") }}/' + id;
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
sessionStorage.setItem('clicked-' + id, 'true');
}
}
}
document.addEventListener('mousedown', function (event) {
if (event.button === 0 || event.button === 1) {
handleClickOrTouch(event);
}
});
document.addEventListener('touchstart', handleClickOrTouch);
});
</script>

View File

@ -1,9 +1,10 @@
<!-- Icons --> <?php use App\Models\UserData; ?>
@php $icons = DB::table('links')->where('user_id', $userinfo->id)->where('button_id', 94)->get(); @endphp @php $icons = DB::table('links')->where('user_id', $userinfo->id)->where('button_id', 94)->get(); @endphp
@if(count($icons) > 0) @if(count($icons) > 0)
<div class="row fadein social-icon-div"> <div class="row fadein social-icon-div">
@foreach($icons as $icon) @foreach($icons as $icon)
<a class="social-hover social-link" href="{{ route('clickNumber') . '/' . $icon->id. "?" . $icon->link}}" title="{{ucfirst($icon->title)}}" aria-label="{{ucfirst($icon->title)}}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif><i class="dynamic-contrast social-icon fa-brands fa-{{$icon->title}}"></i></a> <a class="social-hover social-link" href="{{ $icon->link }}" title="{{ucfirst($icon->title)}}" aria-label="{{ucfirst($icon->title)}}" @if((UserData::getData($userinfo->id, 'links-new-tab') != false))target="_blank"@endif><i id="{{ $icon->id }}" class="button-click dynamic-contrast social-icon fa-brands fa-{{$icon->title}}"></i></a>
@endforeach @endforeach
</div> </div>
@endif @endif

View File

@ -3,20 +3,19 @@
@php @php
$ShowShrBtn = config('advanced-config.display_share_button'); $ShowShrBtn = config('advanced-config.display_share_button');
if ($ShowShrBtn === '') { if ($ShowShrBtn === 'false') {
$ShowShrBtn = 'true';
} elseif ($ShowShrBtn === 'false') {
$ShowShrBtn = 'false'; $ShowShrBtn = 'false';
} elseif ($ShowShrBtn === 'user') { } elseif ($ShowShrBtn === 'user') {
$ShowShrBtn = Auth::user()->littlelink_name ? 'true' : 'false'; $ShowShrBtn = Auth::user()->littlelink_name ? 'true' : 'false';
} elseif (UserData::getData($userinfo->id, 'disable-sharebtn') == "true") {
$ShowShrBtn = 'false';
} else { } else {
$ShowShrBtn = 'true'; $ShowShrBtn = 'true';
} }
$DisplayShowShrBtn = $ShowShrBtn === 'true' && UserData::getData($userinfo->id, 'disable-sharebtn') !== "true";
@endphp @endphp
<div align="right" @if($DisplayShowShrBtn == 'false') style="visibility:hidden" @endif class="sharediv"> <div align="right" @if($ShowShrBtn == 'false') style="visibility:hidden" @endif class="sharediv">
<div> <div>
<span class="sharebutton button-hover icon-hover share-button" data-share="{{url()->current()}}" tabindex="0" role="button" aria-label="{{__('messages.Share this page')}}"> <span class="sharebutton button-hover icon-hover share-button" data-share="{{url()->current()}}" tabindex="0" role="button" aria-label="{{__('messages.Share this page')}}">
<i style="color: black;" class="fa-solid fa-share sharebutton-img share-icon hvr-icon"></i> <i style="color: black;" class="fa-solid fa-share sharebutton-img share-icon hvr-icon"></i>
@ -26,6 +25,6 @@
</div> </div>
<span class="copy-icon" tabindex="0" role="button" aria-label="{{__('messages.Copy URL to clipboard')}}"></span> <span class="copy-icon" tabindex="0" role="button" aria-label="{{__('messages.Copy URL to clipboard')}}"></span>
@if($DisplayShowShrBtn == true) @if($ShowShrBtn == 'true')
<script>const shareButtons=document.querySelectorAll(".share-button");shareButtons.forEach((e=>{e.addEventListener("click",(()=>{const r=e.dataset.share;navigator.share?navigator.share({title:"{{__('messages.Share this page')}}",url:r}).catch((e=>console.error("Error:",e))):navigator.clipboard.writeText(r).then((()=>{alert("{{__('messages.URL has been copied to your clipboard!')}}")})).catch((e=>{alert("Error",e)}))}))}));</script> <script>const shareButtons=document.querySelectorAll(".share-button");shareButtons.forEach((e=>{e.addEventListener("click",(()=>{const r=e.dataset.share;navigator.share?navigator.share({title:"{{__('messages.Share this page')}}",url:r}).catch((e=>console.error("Error:",e))):navigator.clipboard.writeText(r).then((()=>{alert("{{__('messages.URL has been copied to your clipboard!')}}")})).catch((e=>{alert("Error",e)}))}))}));</script>
@endif @endif

View File

@ -272,6 +272,14 @@
<label class="form-check-label" for="sharebtn">{{__('messages.Enable')}}</label> <label class="form-check-label" for="sharebtn">{{__('messages.Enable')}}</label>
</div> </div>
<div class="form-group col-lg-8">
<h5 style="margin-top:50px">{{__('messages.Open links in new tab')}}</h5>
<p class="text-muted">{{__('messages.openlinksnewtab')}}</p>
<div class="mb-3 form-check form-switch">
<input name="tablinks" class="switch toggle-btn" type="checkbox" id="tablinks" <?php if(UserData::getData(Auth::user()->id, 'links-new-tab') != false){echo 'checked';} ?> />
<label class="form-check-label" for="tablinks">{{__('messages.Enable')}}</label>
</div>
<button type="submit" class="mt-3 ml-3 btn btn-primary">{{__('messages.Save')}}</button> <button type="submit" class="mt-3 ml-3 btn btn-primary">{{__('messages.Save')}}</button>
</form> </form>

View File

@ -8,7 +8,7 @@ $analytics =
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Add external analytics services to your LinkStack instance by adding them below. | Add external analytics services to your LinkStack instance by adding them below.
| Everything you enter below will be added to the <head> tag of every page. | Everything you enter below will be added to the <head> tag of every page.
| Formatting in plain HTML is expected. | Formatting in plain HTML is expected.
| |
*/ */
@ -33,7 +33,7 @@ return [
| |
| Will only be active if "CUSTOM_META_TAGS" is set to "true" in the config. | Will only be active if "CUSTOM_META_TAGS" is set to "true" in the config.
| These tags will only be applied to the home page or if a LinkStack page | These tags will only be applied to the home page or if a LinkStack page
| is set as the homepage in the config (for example: HOME_URL="admin"). | is set as the homepage in the config (for example: HOME_URL="admin").
| |
| Empty entries will be ignored. | Empty entries will be ignored.
| |
@ -43,7 +43,7 @@ return [
'description' => '', // Overrides the default meta page description. Leave empty to use your LinkStack page description as the description. 'description' => '', // Overrides the default meta page description. Leave empty to use your LinkStack page description as the description.
'robots' => 'index,follow', 'robots' => 'index,follow',
'viewport' => 'width=device-width, initial-scale=1', 'viewport' => 'width=device-width, initial-scale=1',
'canonical_url' => '', // Tells search engines to index "https://example.com/"  instead of "https://example.com/@admin",  for example. 'canonical_url' => '', // Tells search engines to index "https://example.com/" instead of "https://example.com/@admin", for example.
'twitter_creator' => '', // Twitter @username. 'twitter_creator' => '', // Twitter @username.
'author' => '', // Your name. 'author' => '', // Your name.
@ -123,19 +123,19 @@ return [
| 'custom_css' => '' | 'custom_css' => ''
| ), | ),
| |
| In the 'button' field, you have to enter the button name (i.e. 'mastodon', 'github', 'custom'...). | In the 'button' field, you have to enter the button name (i.e. 'mastodon', 'github', 'custom'...).
| You can find a list of all available buttons below. | You can find a list of all available buttons below.
| |
| In the 'link' field, you can enter your desired link you may leave this field empty for a display only, non-functional button. | In the 'link' field, you can enter your desired link you may leave this field empty for a display only, non-functional button.
| |
| In the 'title' field, changes the text on a button, such as 'custom' and 'custom_website'. | In the 'title' field, changes the text on a button, such as 'custom' and 'custom_website'.
| |
| In the 'icon' field, uses the same syntax as the Button Editor on the Admin Panel. | In the 'icon' field, uses the same syntax as the Button Editor on the Admin Panel.
| This allows you to add your own icons to 'custom' buttons. You can find a list of available icons on linkstack.org/fa. | This allows you to add your own icons to 'custom' buttons. You can find a list of available icons on linkstack.org/fa.
| |
| In the 'custom_css' field, here you can enter custom CSS to change the color of your button. | In the 'custom_css' field, here you can enter custom CSS to change the color of your button.
| If you don't feel comfortable working with CSS, | If you don't feel comfortable working with CSS,
| you can copy and paste the CSS from the 'Custom CSS' field of the Button Editor on the Admin Panel. | you can copy and paste the CSS from the 'Custom CSS' field of the Button Editor on the Admin Panel.
| |
*/ */

View File

@ -1 +1 @@
4.6.0 4.6.1