Laravel 9

Update to Laravel 9

Commit for the upcoming from-end update.
This commit is contained in:
Julian Prieber 2022-11-08 16:11:59 +01:00
parent b5a5c7db49
commit 951df23c91
75 changed files with 14235 additions and 10974 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
_ide_*

View File

@ -0,0 +1,130 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\LinkType;
use Illuminate\Http\Request;
use \App\Http\Requests\LinkTypeRequest;
class LinkTypeController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// get all the sharks
$LinkTypes = LinkType::all();
// load the view and pass the link types
return View('admin.linktype.index')
->with('linktype', $LinkTypes);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return View('admin.linktype.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(LinkTypeRequest $request)
{
// validate
// read more on validation at http://laravel.com/docs/validation
$validated = $request->validated();
// store
$LinkType = new LinkType;
$LinkType->typename = $request->typename;
$LinkType->title = $request->title;
$LinkType->description = $request->description;
$LinkType->icon = $request->icon;
$LinkType->params = $request->params;
$LinkType->save();
// redirect
return Redirect('admin/linktype')
->with('success', 'New link type has been added.');
}
/**
* Display the specified resource.
*
* @param \App\Models\LinkType $linkType
* @return \Illuminate\Http\Response
*/
public function show(LinkType $linkType)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\LinkType $linkType
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$lt = LinkType::find($id);
// show the edit form and pass the shark
return View('admin.linktype.edit', ['linktype' => $lt]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\LinkType $linkType
* @return \Illuminate\Http\Response
*/
public function update(LinkTypeRequest $request, $id)
{
$linktype = LinkType::find($id);
$validated = $request->validated();
// store
$linktype->title = $request->title;
$linktype->description = $request->description;
$linktype->icon = $request->icon;
$linktype->params = $request->params;
$linktype->save();
// redirect
return Redirect('admin/linktype')
->with('success', 'Link type updated.');
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\LinkType $linkType
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
// delete
$linktype = LinkType::find($id);
$linktype->delete();
// redirect
return Redirect('admin/linktype')
->with('success', 'Link type deleted');
}
}

View File

@ -154,7 +154,6 @@ class AdminController extends Controller
$data['user'] = User::where('id', $id)->get();
return view('panel/edit-user', $data);
}
//Show link, click number, up link in links page
@ -320,7 +319,8 @@ class AdminController extends Controller
function removeFolder($folderName) {
function removeFolder($folderName)
{
if (is_dir($folderName))
@ -345,9 +345,7 @@ class AdminController extends Controller
else
removeFolder($folderName . '/' . $file);
}
}
@ -355,14 +353,13 @@ class AdminController extends Controller
closedir($folderHandle);
rmdir($folderName);
}
removeFolder($folderName);
return Redirect('/panel/theme');
}}
}
}
// Update themes
public function updateThemes()
@ -376,13 +373,19 @@ class AdminController extends Controller
$text = file_get_contents(base_path('themes') . '/' . $entry . '/readme.md');
$pattern = '/Theme Version:.*/';
preg_match($pattern, $text, $matches, PREG_OFFSET_CAPTURE);
$verNr = substr($matches[0][0],15);}
if (!count($matches)) continue;
$verNr = substr($matches[0][0], 15);
}
$themeVe = NULL;
if ($entry != "." && $entry != "..") {
if (file_exists(base_path('themes') . '/' . $entry . '/readme.md')) {
if(!strpos(file_get_contents(base_path('themes') . '/' . $entry . '/readme.md'), 'Source code:')){$hasSource = false;}else{
if (!strpos(file_get_contents(base_path('themes') . '/' . $entry . '/readme.md'), 'Source code:')) {
$hasSource = false;
} else {
$hasSource = true;
$text = file_get_contents(base_path('themes') . '/' . $entry . '/readme.md');
@ -442,12 +445,13 @@ class AdminController extends Controller
}
}
}
}
}
}
}
}}}
}
}
}
return Redirect('/studio/theme');
@ -458,5 +462,4 @@ class AdminController extends Controller
{
return view('/panel/theme');
}
}

View File

@ -9,6 +9,7 @@ use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
class RegisteredUserController extends Controller
{
@ -38,14 +39,29 @@ class RegisteredUserController extends Controller
'password' => 'required|string|confirmed|min:8',
]);
$name = $request->input('name');
if(DB::table('users')->where('littlelink_name', $request->name)->exists())
{
Auth::login($user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'role' => 'user',
'block' => 'no',
]));
} else {
Auth::login($user = User::create([
'name' => $request->name,
'email' => $request->email,
'littlelink_name' => $request->name,
'password' => Hash::make($request->password),
'role' => 'user',
'block' => 'no',
]));
}
event(new Registered($user));

View File

@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\SocialAccount;
class SocialLoginController extends Controller
{
public function redirectToProvider(String $provider)
{
return \Socialite::driver($provider)->redirect();
}
public function providerCallback(String $provider)
{
try {
$social_user = \Socialite::driver($provider)->user();
// First Find Social Account
$account = SocialAccount::where([
'provider_name' => $provider,
'provider_id' => $social_user->getId()
])->first();
// If Social Account Exist then Find User and Login
if ($account) {
auth()->login($account->user);
return redirect('/studio/index');
}
// Find User
$user = User::where([
'email' => $social_user->getEmail()
])->first();
// If User not found, then create new user
if (!$user) {
$user = User::create([
'email' => $social_user->getEmail(),
'name' => $social_user->getName(),
'image' => $social_user->getAvatar(),
'littlelink_name' => $social_user->getNickname(),
'email_verified_at' => now(),
]);
}
// Create Social Accounts
$user->socialAccounts()->create([
'provider_id' => $social_user->getId(),
'provider_name' => $provider
]);
// Login
auth()->login($user);
return redirect('/studio/index');
} catch (\Exception $e) {
return redirect()->route('login')->withErrors($e->getMessage());
}
}
}

View File

@ -19,7 +19,7 @@ class HomeController extends Controller
$countButton = Button::count();
$updatedPages = DB::table('links')->join('users', 'users.id', '=', 'links.user_id')->select('users.littlelink_name', DB::raw('max(links.created_at) as created_at'))->groupBy('links.user_id')->orderBy('created_at', 'desc')->take(4)->get();
$updatedPages = DB::table('links')->join('users', 'users.id', '=', 'links.user_id')->select('users.littlelink_name', 'users.image', DB::raw('max(links.created_at) as created_at'))->groupBy('links.user_id')->orderBy('created_at', 'desc')->take(4)->get();
return view('home', ['message' => $message, 'countButton' => $countButton, 'updatedPages' => $updatedPages]);
}

View File

@ -0,0 +1,165 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\LinkType;
use App\Models\Link;
use App\Models\Button;
use micro\FormFactory;
use DB;
class LinkTypeViewController extends Controller
{
public function getParamForm($typeid, $linkId = 0)
{
$linkType = LinkType::select('params', 'typename')->where('id', $typeid)->First();
$data['params'] = '';
$data['link_title'] = '';
$data['link_url'] = '';
if ($linkId) {
$link = Link::find($linkId);
$data['params'] = json_decode($link['type_params']);
$data['link_title'] = $link->title;
$data['link_url'] = $link->link;
}
if (!empty($linkType) && $linkType->typename === 'predefined') {
// get buttons list if showing predefined form
$buttons = Button::select('name')->orderBy('name', 'asc')->get();
foreach ($buttons as $btn) {
$data['buttons'][] = [
'name' => $btn->name,
'title' => ucwords($btn->name),
'selected' => (is_object($data['params']) && $data['params']->button === $btn->name)
];
}
//echo "<pre>"; print_r($data['params']); exit;
}
return view('components.pageitems.'. $linkType->typename.'-form', $data);
$jsonForm = FormFactory::jsonForm();
try {
$json = $linkType->params;
} catch (\Throwable $th) {
//throw $th;
}
// dynamiclly create params for predefined website to fill a select list with available buttons
if (!empty($linkType) && $linkType->typename === 'predefined') {
$buttons = Button::select('name')->orderBy('name', 'asc')->get();
$pdParams[] = ['tag' => 'select', 'name' => 'button', 'id'=> 'button'];
foreach ($buttons as $btn) {
$pdParams[0]['value'][] = [
'tag'=>'option',
'label' => ucwords($btn->name),
'value' => $btn->name
];
}
$pdParams[] = ['tag' => 'input', 'name' => 'link_title', 'id' => 'link_title', 'name' => 'link_title', 'tip' => 'Leave blank for default title'];
$pdParams[] = ['tag' => 'input', 'name' => 'link_url', 'id' => 'link_url', 'name' => 'link_url', 'tip' => 'Enter the url address for this site.'];
$json = json_encode($pdParams);
}
if (empty($json)) {
$json =
<<<EOS
[{
"tag": "input",
"id": "link_title",
"for": "link_title",
"label": "Link Title *",
"type": "text",
"name": "link_title",
"class": "form-control",
"tip": "Enter a title for this link",
"required": "required"
},
{
"tag": "input",
"id": "link",
"for": "link",
"label": "Link Address *",
"type": "text",
"name": "link_title",
"class": "form-control",
"tip": "Enter the website address",
"required": "required"
}
]
EOS;
}
if ($linkId) {
$link = Link::find($linkId);
}
// cleanup json
$params = json_decode($json, true);
$idx = 0;
foreach ($params as $p) {
if (!array_key_exists('for', $p))
$params[$idx]['for'] = $p['name'];
if (!array_key_exists('label', $p))
$params[$idx]['label'] = ucwords(preg_replace('/[^a-zA-Z0-9-]/', ' ', $p['name']));
if (!array_key_exists('label', $p) || !str_contains($p['class'], 'form-control')) {
$params[$idx]['class'] = " form-control";
}
// get existing values if any
if ($link) {
$typeParams = json_decode($link['type_params']);
//echo "<pre>";
// print_r($typeParams);
//print_r($params[$idx]);
//echo "</pre>";
if ($typeParams && property_exists($typeParams, $params[$idx]['name'])) {
if (key_exists('value', $params[$idx]) && is_array($params[$idx]['value'])) {
$optIdx = 0;
foreach ($params[$idx]['value'] as $option) {
//echo $option['value']."<br />";
//echo $typeParams->{$params[$idx]['name']};
if ($option['value'] == $typeParams->{$params[$idx]['name']}) {
$params[$idx]['value'][$optIdx]['selected'] = true;
break;
}
//echo $key ." = ".$value;
$optIdx++;
}
} else {
$params[$idx]['value'] = $typeParams->{$params[$idx]['name']};
}
}
}
$idx++;
}
$json = json_encode($params);
echo $jsonForm->render($json);
}
}

View File

@ -4,6 +4,8 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Cohensive\OEmbed\Facades\OEmbed;
use Illuminate\Support\Facades\Schema;
use Auth;
use DB;
@ -13,10 +15,12 @@ use File;
use App\Models\User;
use App\Models\Button;
use App\Models\Link;
use App\Models\LinkType;
//Function tests if string starts with certain string (used to test for illegal strings)
function stringStartsWith($haystack,$needle,$case=true) {
function stringStartsWith($haystack, $needle, $case = true)
{
if ($case) {
return strpos($haystack, $needle, 0) === 0;
}
@ -24,7 +28,8 @@ function stringStartsWith($haystack,$needle,$case=true) {
}
//Function tests if string ends with certain string (used to test for illegal strings)
function stringEndsWith($haystack,$needle,$case=true) {
function stringEndsWith($haystack, $needle, $case = true)
{
$expectedPosition = strlen($haystack) - strlen($needle);
if ($case) {
return strrpos($haystack, $needle, 0) === $expectedPosition;
@ -41,12 +46,30 @@ class UserController extends Controller
$userId = Auth::user()->id;
$littlelink_name = Auth::user()->littlelink_name;
$userinfo = User::find($userId);
$links = Link::where('user_id', $userId)->select('link')->count();
$clicks = Link::where('user_id', $userId)->sum('click_number');
$topLinks = Link::where('user_id', $userId)->orderby('click_number', 'desc')
->whereNotNull('link')->where('link', '<>', '')
->take(5)->get();
return view('studio/index', ['littlelink_name' => $littlelink_name, 'links' => $links, 'clicks' => $clicks]);
$pageStats = [
'visitors' => [
'all' => visits('App\Models\User', $littlelink_name)->count(),
'day' => visits('App\Models\User', $littlelink_name)->period('day')->count(),
'week' => visits('App\Models\User', $littlelink_name)->period('week')->count(),
'month' => visits('App\Models\User', $littlelink_name)->period('month')->count(),
'year' => visits('App\Models\User', $littlelink_name)->period('year')->count(),
],
'os' => visits('App\Models\User', $littlelink_name)->operatingSystems(),
'referers' => visits('App\Models\User', $littlelink_name)->refs(),
'countries' => visits('App\Models\User', $littlelink_name)->countries(),
];
return view('studio/index', ['greeting' => $userinfo->name, 'toplinks' => $topLinks, 'links' => $links, 'clicks' => $clicks, 'pageStats' => $pageStats]);
}
//Show littlelink page. example => http://127.0.0.1:8000/+admin
@ -70,6 +93,7 @@ class UserController extends Controller
//Show littlelink page as home page if set in config
public function littlelinkhome(request $request)
{
$littlelink_name = env('HOME_URL');
$id = User::select('id')->where('littlelink_name', $littlelink_name)->value('id');
@ -77,68 +101,148 @@ class UserController extends Controller
return abort(404);
}
$userinfo = User::select('name', 'littlelink_name', 'littlelink_description', 'theme')->where('id', $id)->first();
$information = User::select('name', 'littlelink_name', 'littlelink_description', 'theme')->where('id', $id)->get();
$userinfo = User::select('name', 'littlelink_name', 'littlelink_description', 'image', 'theme')->where('id', $id)->first();
$information = User::select('name', 'littlelink_name', 'littlelink_description', 'image', 'theme')->where('id', $id)->get();
$links = DB::table('links')->join('buttons', 'buttons.id', '=', 'links.button_id')->select('links.link', 'links.id', 'links.button_id', 'links.title', 'links.custom_css', 'links.custom_icon', 'buttons.name')->where('user_id', $id)->orderBy('up_link', 'asc')->orderBy('order', 'asc')->get();
$links = DB::table('links')
->where('user_id', $id)
->orderBy('up_link', 'asc')->orderBy('order', 'asc')
->get();
return view('littlelink', ['userinfo' => $userinfo, 'information' => $information, 'links' => $links, 'littlelink_name' => $littlelink_name]);
}
//Show buttons for add link
public function showButtons()
//Show add/update form
public function AddUpdateLink($id = 0)
{
$data['buttons'] = Button::select('name')->orderBy('name', 'asc')->get();
return view('studio/add-link', $data);
if ($id !== 0) {
$linkData = Link::find($id);
} else {
$linkData = new Link(['typename' => 'link', 'id'=>'0']);
}
$data['LinkTypes'] = LinkType::get();
$data['LinkData'] = $linkData;
$data['LinkID'] = $id;
$data['title'] = "link";
foreach ($data['LinkTypes']->toArray() as $key => $val) {
if ($val['typename'] === $linkData['typename']) {
$data['SelectedLinkType'] = $val;
break;
}
}
return view('studio/edit-link', $data);
}
//Save add link
public function addLink(request $request)
public function saveLink(request $request)
{
if ($request->button == 'heading' or $request->button == 'space')
$request->validate([
'link' => '',
'title' => '',
'button' => 'required'
]);
else
$request->validate([
'link' => 'required',
'title' => '',
'button' => 'required'
]);
// if ($request->button == 'heading' or $request->button == 'space')
// $request->validate([
// 'link' => '',
// 'title' => '',
// 'button' => 'required'
// ]);
// else
// $request->validate([
// 'link' => 'required',
// 'title' => '',
// 'button' => 'required'
// ]);
if ($request->button == 'phone')
$link1 = 'tel:' . $request->link;
elseif ($request->button == 'default email' or $request->button == 'default email_alt')
$link1 = 'mailto:' . $request->link;
elseif (stringStartsWith($request->link,'http://') == 'true' or stringStartsWith($request->link,'https://') == 'true')
$link1 = $request->link;
else
$link1 = 'https://' . $request->link;
if (stringEndsWith($request->link,'/') == 'true')
$link = rtrim($link1, "/ ");
else
$link = $link1;
if ($request->title == '')
$title = $request->button;
else
$title = $request->title;
$button = $request->button;
$linkType = LinkType::find($request->linktype_id);
$LinkTitle = ($request->link_text ?? $request->link_title) ?? $request->title;
$LinkURL = $request->link_url ?? $request->link;
$OrigLink = Link::find($request->linkid);
// if (stringStartsWith($LinkURL, 'http://') == 'true' or stringStartsWith($LinkURL, 'https://') == 'true')
// $link1 = $LinkURL;
// elseif (!empty($LinkURL))
// $link1 = 'https://' . $LinkURL;
// if (stringEndsWith($LinkURL, '/') == 'true')
// $link = rtrim($link1, "/ ");
// else
// $link = $link1;
$customParams = [];
foreach ($request->all() as $key => $param) {
//echo $key . " = " . $param . "<br />";
if (str_starts_with($key, "_") || in_array($key, ['linktype_id', 'linktype_title', 'link_text', 'link_url']))
continue;
$customParams[$key] = $param;
}
$userId = Auth::user()->id;
$buttonId = Button::select('id')->where('name' , $button)->value('id');
$button = Button::where('name', $request->button)->first();
if ($button && empty($LinkTitle))
$LinkTitle = ucwords($button->name);
if ($linkType->typename == 'video' && empty($LinkTitle)) {
$embed = OEmbed::get($LinkURL);
if ($embed) {
$LinkTitle = $embed->data()['title'];
}
}
$message = (ucwords($button?->name) ?? ucwords($linkType->typename)). " has been ";
if ($OrigLink) {
//EDITING EXISTING
$OrigLink->update([
'link' => $LinkURL,
'title' => $LinkTitle,
'button_id' => $button?->id,
]);
$message .="updated";
} else {
// ADDING NEW
$isCustomWebsite = $customParams['GetSiteIcon'] ?? null;
$SpacerHeight = $customParams['height'] ?? null;
$links = new Link;
$links->link = $link;
$links->link = $LinkURL;
$links->user_id = $userId;
$links->title = $title;
$links->button_id = $buttonId;
$links->save();
$links->order = ($links->id - 1);
if($linkType->typename == "spacer"){
$links->title = $SpacerHeight;
}else{
$links->title = $LinkTitle;
}
if($linkType->typename == "link" and $isCustomWebsite == "1"){
$links->button_id = "2";
}elseif($linkType->typename == "link"){
$links->button_id = "1";
}elseif($linkType->typename == "spacer"){
$links->button_id = "43";
}elseif($linkType->typename == "heading"){
$links->button_id = "42";
}else{
$links->button_id = $button?->id;
}
// $links->type_params = json_encode($customParams);
// $links->typename = $linkType->typename;
$links->save();
return back();
$links->order = ($links->id - 1);
$links->save();
$message .= "added";
}
return Redirect('studio/links')
->with('success', $message);
// echo $customParams['GetSiteIcon'];
}
public function sortLinks(Request $request)
@ -179,19 +283,27 @@ class UserController extends Controller
]);
}
//Count the number of clicks and redirect to link
public function clickNumber(request $request)
{
$link = $request->link;
$query = $request->query();
$linkId = $request->id;
if(empty($link && $linkId))
{
if (empty($link && $linkId)) {
return abort(404);
}
if (!empty($query)) {
$qs = [];
foreach ($query as $qk => $qv) {
$qs[] = $qk . '=' . $qv;
}
$link = $link . '?' . implode('&', $qs);
}
Link::where('id', $linkId)->increment('click_number', 1);
$link = Link::select('link')->where('id', $linkId)->get()[0]['link'];
return redirect()->away($link);
}
@ -243,7 +355,7 @@ class UserController extends Controller
Link::where('id', $linkId)->delete();
return back();
return back()->with('success', 'Link Deleted');
}
//Raise link on the littlelink page
@ -278,7 +390,6 @@ class UserController extends Controller
$buttons = Button::select('id', 'name')->orderBy('name', 'asc')->get();
return view('studio/edit-link', ['custom_css' => $custom_css, 'buttonId' => $buttonId, 'buttons' => $buttons, 'link' => $link, 'title' => $title, 'order' => $order, 'id' => $linkId, 'buttonName' => $buttonName]);
}
//Show custom CSS + custom icon
@ -296,7 +407,6 @@ class UserController extends Controller
$buttons = Button::select('id', 'name')->get();
return view('studio/button-editor', ['custom_icon' => $custom_icon, 'custom_css' => $custom_css, 'buttonId' => $buttonId, 'buttons' => $buttons, 'link' => $link, 'title' => $title, 'order' => $order, 'id' => $linkId]);
}
//Save edit link
@ -350,7 +460,7 @@ class UserController extends Controller
{
$userId = Auth::user()->id;
$data['pages'] = User::where('id', $userId)->select('littlelink_name', 'littlelink_description')->get();
$data['pages'] = User::where('id', $userId)->select('littlelink_name', 'littlelink_description', 'image', 'name')->get();
return view('/studio/page', $data);
}
@ -358,14 +468,20 @@ class UserController extends Controller
//Save littlelink page (name, description, logo)
public function editPage(request $request)
{
$request->validate([
'littlelink_name' => 'required|string|max:255|unique:users',
'name' => 'required|string|max:255|unique:users',
]);
$userId = Auth::user()->id;
$littlelink_name = Auth::user()->littlelink_name;
$profilePhoto = $request->file('image');
$pageName = $request->pageName;
$pageDescription = $request->pageDescription;
$name = $request->Name;
User::where('id', $userId)->update(['littlelink_name' => $pageName, 'littlelink_description' => $pageDescription]);
User::where('id', $userId)->update(['littlelink_name' => $pageName, 'littlelink_description' => $pageDescription, 'name' => $name]);
if (!empty($profilePhoto)) {
$profilePhoto->move(base_path('/img'), $littlelink_name . ".png");
@ -396,9 +512,12 @@ class UserController extends Controller
$zipfile = $request->file('zip');
$theme = $request->theme;
$message = "";
User::where('id', $userId)->update(['theme' => $theme]);
if (!empty($zipfile)) {
$zipfile->move(base_path('/themes'), "temp.zip");
@ -429,11 +548,10 @@ class UserController extends Controller
}
}
}
}
return Redirect('/studio/theme');
return Redirect('/studio/theme')->with("success", $message);
}
//Show user (name, email, password)
@ -489,4 +607,23 @@ if($request->name != '' ) {
return view('components/theme', ['userinfo' => $userinfo, 'information' => $information, 'links' => $links, 'littlelink_name' => $littlelink_name]);
}
//Delete existing user
public function deleteUser(request $request)
{
// echo $request->id;
// echo "<br>";
// echo Auth::id();
$id = $request->id;
if($id == Auth::id() and $id != "1") {
$user = User::find($id);
Schema::disableForeignKeyConstraints();
$user->forceDelete();
Schema::enableForeignKeyConstraints();
}
return redirect('/');
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Http\Requests;
use Auth;
use Illuminate\Foundation\Http\FormRequest;
class LinkTypeRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::user()->role == 'admin';
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required',
'typename' => 'required',
'icon' => 'required',
'params' => 'json|nullable'
];
}
}

View File

@ -5,7 +5,11 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Link extends Model
{
use HasFactory;
protected $fillable = ['link', 'title', 'button_id', 'type_params', 'typename'];
}

13
app/Models/LinkType.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class LinkType extends Model
{
use HasFactory;
protected $fillable = ['typename', 'title', 'description', 'icon', 'params'];
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SocialAccount extends Model
{
use HasFactory;
protected $fillable = [
'user_id', 'provider_name', 'provider_id'
];
// User
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@ -19,7 +19,13 @@ class User extends Authenticatable implements MustVerifyEmail
protected $fillable = [
'name',
'email',
'image',
'password',
'provider',
'provider_id',
'email_verified_at',
'littlelink_name',
];
/**
@ -40,4 +46,13 @@ class User extends Authenticatable implements MustVerifyEmail
protected $casts = [
'email_verified_at' => 'datetime',
];
public function visits()
{
return visits($this)->relation();
}
public function socialAccounts()
{
return $this->hasMany(socialAccount::class);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Modal extends Component
{
public $title = '';
public $id = '';
/**
* Create a new component instance.
*
* @return void
*/
public function __construct($title, $id = '')
{
$this->title = $title;
$this->id = $id;
}
/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
return view('components.modal');
}
public function getModalIdString(): string
{
if ($this->id != '') {
return $this->id;
}
return "model" . rand(1111, 9999);
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\View\Components;
use Illuminate\View\Component;
use Cohensive\OEmbed\Facades\OEmbed;
class PageItemDisplay extends Component
{
public $link;
public $id = '';
/**
* Create a new component instance.
*
* @return void
*/
public function __construct($link)
{
// $this->title = $title;
$this->link = $link;
}
/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
$params = json_decode($this->link->type_params);
return view('components.pageitems.'.$this->link->typename.'-display', ['link' => $this->link, 'params' => $params]);
}
public function getModalIdString(): string
{
if ($this->id != '') {
return $this->id;
}
return "model" . rand(1111, 9999);
}
}

View File

@ -7,21 +7,26 @@
"require": {
"php": "^7.3|^8.0",
"codedge/laravel-selfupdater": "^3.4",
"awssat/laravel-visits": "^4.0",
"doctrine/dbal": "^3.0",
"fideloper/proxy": "^4.4",
"fruitcake/laravel-cors": "^3.0",
"geo-sot/laravel-env-editor": "^1.1",
"geo-sot/laravel-env-editor": "^2.0",
"guzzlehttp/guzzle": "^7.4",
"laravel/framework": "^8.12",
"laravel/framework": "^9.0",
"laravel/socialite": "^5.5",
"laravel/tinker": "^2.5",
"spatie/laravel-backup": "^6.16"
"spatie/laravel-backup": "^8.13",
"cohensive/oembed": "^0.16"
},
"require-dev": {
"facade/ignition": "^2.5",
"barryvdh/laravel-ide-helper": "^2.12",
"spatie/laravel-ignition": "^1.0",
"fakerphp/faker": "^1.9.1",
"laravel/breeze": "^1.1",
"laravel/sail": "^1.0.1",
"mockery/mockery": "^1.4.2",
"nunomaduro/collision": "^5.0",
"nunomaduro/collision": "^6.1",
"phpunit/phpunit": "^9.3.3"
},
"autoload": {

3651
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ return [
|
*/
'name' => env('APP_NAME', 'Admin Littlelink'),
'name' => env('APP_NAME', 'LittleLink Custom'),
/*
|--------------------------------------------------------------------------
@ -161,11 +161,15 @@ return [
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
Laravel\Socialite\SocialiteServiceProvider::class,
/*
* Package Service Providers...
*/
/*
* Application Service Providers...
*/
@ -226,6 +230,8 @@ return [
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Socialite'=> Laravel\Socialite\Facades\Socialite::class,
'OEmbed' => Cohensive\OEmbed\Facades\OEmbed::class
],

View File

@ -29,5 +29,20 @@ return [
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'),
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
'redirect' => env('FACEBOOK_CALLBACK_URL'),
],
'twitter' => [
'client_id' => env('TWITTER_CLIENT_ID'),
'client_secret' => env('TWITTER_CLIENT_SECRET'),
'redirect' => env('TWITTER_CALLBACK_URL'),
],
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_CALLBACK_URL'),
],
];

78
config/visits.php Normal file
View File

@ -0,0 +1,78 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Database Engine & Connection Name
|--------------------------------------------------------------------------
|
| Supported Engines: "redis", "eloquent"
| Connection Name: see config/database.php
|
*/
'engine' => \Awssat\Visits\DataEngines\EloquentEngine::class,
'connection' => 'laravel-visits',
/*
|--------------------------------------------------------------------------
| Counters periods
|--------------------------------------------------------------------------
|
| Record visits (total) of each one of these periods in this set (can be empty)
|
*/
'periods' => [
'day',
'week',
'month',
'year',
],
/*
|--------------------------------------------------------------------------
| Redis prefix
|--------------------------------------------------------------------------
*/
'keys_prefix' => 'visits',
/*
|--------------------------------------------------------------------------
| Remember ip for x seconds of time
|--------------------------------------------------------------------------
|
| Will count only one visit of an IP during this specified time.
|
*/
'remember_ip' => 15 * 60,
/*
|--------------------------------------------------------------------------
| Always return uncached fresh top/low lists
|--------------------------------------------------------------------------
*/
'always_fresh' => false,
/*
|--------------------------------------------------------------------------
| Ignore Crawlers
|--------------------------------------------------------------------------
|
| Ignore counting crawlers visits or not
|
*/
'ignore_crawlers' => true,
/*
|--------------------------------------------------------------------------
| Global Ignore Recording
|--------------------------------------------------------------------------
|
| stop recording specific items (can be any of these: 'country', 'refer', 'periods', 'operatingSystem', 'language')
|
*/
'global_ignore' => ['country'],
];

View File

@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\User;
class Sociallogin extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('provider')->nullable();
$table->string('provider_id')->nullable();
$table->string('image')->nullable();
$table->string('password')->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
User::whereNull('password')->delete();
}
}

View File

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class SocialAccounts extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('social_accounts', function (Blueprint $table) {
$table->id();
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('provider_name')->nullable();
$table->string('provider_id')->unique()->nullable();
$table->timestamps();
});
Schema::table('users', function (Blueprint $table) {
//$table->dropColumn('provider');
//$table->dropColumn('provider_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::dropIfExists('social_accounts');
}
}

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateVisitsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('visits', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('primary_key');
$table->string('secondary_key')->nullable();
$table->unsignedBigInteger('score');
$table->json('list')->nullable();
$table->timestamp('expired_at')->nullable();
$table->timestamps();
$table->unique(['primary_key', 'secondary_key']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('visits');
}
}

View File

@ -0,0 +1,186 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class LinkType extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
var $TableName = 'link_types';
public function up()
{
Schema::create($this->TableName, function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('typename', 100);
$table->string('title')->nullable();
$table->string('description')->nullable();
$table->string('icon');
$table->string('params', 65535)->nullable();
$table->boolean('active')->default(true);
});
$this->SeedLinkTypes();
Schema::table('links', function (Blueprint $table) {
$table->string('link')->nullable()->change();
$table->string('title')->nullable()->change();
$table->unsignedBigInteger('button_id')->nullable()->constrained()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('link_types');
Schema::table('links', function (Blueprint $table) {
$table->string('link')->nullable(false)->change();
$table->unsignedBigInteger('button_id')->nullable(false)->change();
$table->string('title')->nullable(false)->change();
});
}
public function SeedLinkTypes() {
DB::table($this->TableName)->updateOrInsert([
'typename' => 'link',
'title' => 'Website Link',
'icon' => 'bi bi-link',
'description' => 'Create a Custom Button that goes to any website. ',
'params' => '[{
"tag": "input",
"id": "link_title",
"for": "link_title",
"label": "Link Title *",
"type": "text",
"name": "link_title",
"class": "form-control",
"tip": "Enter a title for this link",
"required": "required"
},
{
"tag": "input",
"id": "link_url",
"for": "link_url",
"label": "Link Address *",
"type": "text",
"name": "link_url",
"class": "form-control",
"tip": "Enter the website address",
"required": "required"
}
]'
]);
DB::table($this->TableName)->updateOrInsert([
'typename' => 'predefined',
'title' => 'Predefined Site',
'icon' => 'bi bi-boxes',
'description' => 'Select from a list of predefined websites and have your link automatically styled using that sites brand colors and icon.'
]);
DB::table($this->TableName)->updateOrInsert([
'typename' => 'heading',
'title' => 'Heading',
'icon' => 'bi bi-card-heading',
'description' => 'Use headings to organize your links and separate them into groups',
'params' => '[{
"tag": "input",
"id": "heading-text",
"for": "link_title",
"label": "Heading Text",
"type": "text",
"name": "link_title",
"class": "form-control"
}]'
]);
DB::table($this->TableName)->updateOrInsert([
'typename' => 'spacer',
'title' => 'Spacer',
'icon' => 'bi bi-distribute-vertical',
'description' => 'Add blank space to your list of links. You can choose how big. ',
'params' => '[
{
"tag": "input",
"type": "number",
"min": "1","max":"10",
"name": "spacer_size",
"id": "spacer_size",
"value": 3
}
]'
]);
// DB::table($this->TableName)->updateOrInsert([
// 'typename' => 'video',
// 'title' => 'Video',
// 'icon' => 'bi bi-play-btn',
// 'description' => 'Embed or link to a video on another website, such as TikTok, YouTube etc.',
// 'params' => '[
// {
// "tag": "input",
// "id": "link_url",
// "for": "link_url",
// "label": "URL of video",
// "type": "text",
// "name": "link_url",
// "class": "form-control",
// "tip": "Enter the website address",
// "required": "required"
// }
// {
// "tag": "select",
// "name": "video-option",
// "id": "video-option",
// "value": [
// {
// "tag": "option",
// "label": "Link to video ",
// "value": "link"
// },
// {
// "tag": "option",
// "label": "Embed Video",
// "value": "embed"
// },
// ]
// }
// ]'
// ]);
// DB::table($this->TableName)->updateOrInsert([
// 'typename' => 'text',
// 'title' => 'Text',
// 'icon' => 'bi bi-fonts',
// 'description' => 'Add static text to your page that is not clickable.',
// 'params' => '[{
// "tag": "textarea",
// "id": "static-text",
// "for": "static_text",
// "label": "Text",
// "name": "static_text",
// "class": "form-control"
// }
// ]'
// ]);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
<svg width="74" height="79" viewBox="0 0 74 79" fill="white" xmlns="http://www.w3.org/2000/svg">
<path d="M73.7014 17.9592C72.5616 9.62034 65.1774 3.04876 56.424 1.77536C54.9472 1.56019 49.3517 0.7771 36.3901 0.7771H36.2933C23.3281 0.7771 20.5465 1.56019 19.0697 1.77536C10.56 3.01348 2.78877 8.91838 0.903306 17.356C-0.00357857 21.5113 -0.100361 26.1181 0.068112 30.3439C0.308275 36.404 0.354874 42.4535 0.91406 48.489C1.30064 52.498 1.97502 56.4751 2.93215 60.3905C4.72441 67.6217 11.9795 73.6395 19.0876 76.0945C26.6979 78.6548 34.8821 79.0799 42.724 77.3221C43.5866 77.1245 44.4398 76.8953 45.2833 76.6342C47.1867 76.0381 49.4199 75.3714 51.0616 74.2003C51.0841 74.1839 51.1026 74.1627 51.1156 74.1382C51.1286 74.1138 51.1359 74.0868 51.1368 74.0592V68.2108C51.1364 68.185 51.1302 68.1596 51.1185 68.1365C51.1069 68.1134 51.0902 68.0932 51.0695 68.0773C51.0489 68.0614 51.0249 68.0503 50.9994 68.0447C50.9738 68.0391 50.9473 68.0392 50.9218 68.045C45.8976 69.226 40.7491 69.818 35.5836 69.8087C26.694 69.8087 24.3031 65.6569 23.6184 63.9285C23.0681 62.4347 22.7186 60.8764 22.5789 59.2934C22.5775 59.2669 22.5825 59.2403 22.5934 59.216C22.6043 59.1916 22.621 59.1702 22.6419 59.1533C22.6629 59.1365 22.6876 59.1248 22.714 59.1191C22.7404 59.1134 22.7678 59.1139 22.794 59.1206C27.7345 60.2936 32.799 60.8856 37.8813 60.8843C39.1036 60.8843 40.3223 60.8843 41.5447 60.8526C46.6562 60.7115 52.0437 60.454 57.0728 59.4874C57.1983 59.4628 57.3237 59.4416 57.4313 59.4098C65.3638 57.9107 72.9128 53.2051 73.6799 41.2895C73.7086 40.8204 73.7803 36.3758 73.7803 35.889C73.7839 34.2347 74.3216 24.1533 73.7014 17.9592ZM61.4925 47.6918H53.1514V27.5855C53.1514 23.3526 51.3591 21.1938 47.7136 21.1938C43.7061 21.1938 41.6988 23.7476 41.6988 28.7919V39.7974H33.4078V28.7919C33.4078 23.7476 31.3969 21.1938 27.3894 21.1938C23.7654 21.1938 21.9552 23.3526 21.9516 27.5855V47.6918H13.6176V26.9752C13.6176 22.7423 14.7157 19.3795 16.9118 16.8868C19.1772 14.4 22.1488 13.1231 25.8373 13.1231C30.1064 13.1231 33.3325 14.7386 35.4832 17.9662L37.5587 21.3949L39.6377 17.9662C41.7884 14.7386 45.0145 13.1231 49.2765 13.1231C52.9614 13.1231 55.9329 14.4 58.2055 16.8868C60.4017 19.3772 61.4997 22.74 61.4997 26.9752L61.4925 47.6918Z" fill="inherit"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M22.53 14.35c-.32 1.66-2.9 3.48-5.85 3.84-1.54.18-3.06.35-4.68.28-2.65-.12-4.73-.63-4.73-.63 0 .26.02.5.05.73.34 2.61 2.59 2.77 4.72 2.84 2.15.07 4.06-.53 4.06-.53l.09 1.94s-1.5.81-4.18.95c-1.47.08-3.31-.04-5.44-.6-4.63-1.22-5.42-6.16-5.54-11.16-.04-1.49-.01-2.89-.01-4.06 0-5.12 3.35-6.62 3.35-6.62C6.06.55 8.96.23 11.98.2h.07c3.02.02 5.92.35 7.61 1.13 0 0 3.35 1.5 3.35 6.62-.01 0 .03 3.78-.48 6.4" fill="#3088d4"/>
<path d="M19.05 8.35v6.2H16.6V8.53c0-1.27-.53-1.91-1.6-1.91-1.18 0-1.77.76-1.77 2.27v3.29h-2.44V8.89c0-1.51-.59-2.27-1.77-2.27-1.07 0-1.6.64-1.6 1.91v6.01H4.95v-6.2c0-1.27.32-2.27.97-3.02.67-.74 1.54-1.13 2.63-1.13 1.26 0 2.21.48 2.84 1.45L12 6.68l.61-1.02c.63-.97 1.58-1.45 2.84-1.45 1.09 0 1.96.38 2.63 1.13.64.74.97 1.74.97 3.01" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 846 B

View File

@ -62,7 +62,7 @@ var copyToClipboard = (function () {
copyToClipboard.handleCopyIconClick();
document.querySelector('#share-share-button').addEventListener('click', () => {
$('#share-share-button').on('click', () => {
if (navigator.share) {
navigator.share({
title: '',

2
resources/js/app.js vendored
View File

@ -1,3 +1,3 @@
require('./bootstrap');
require('alpinejs');
// require('alpinejs');

View File

@ -0,0 +1,90 @@
@extends('layouts.sidebar')
@section('content')
<div class='card'>
<div class='card-header'>
<h4 class='card-title'>Create New Link Type</h1>
</div>
<div class='card-body'>
<!-- if there are creation errors, they will show here -->
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action='/admin/linktype' method="post">
@csrf
<div class="form-group">
<label for="icon">Icon</label>
<input type='text' value="{{@old('icon')}}" name='icon' class="form-control @error('icon') is-invalid @enderror">
<a href="https://icons.getbootstrap.com/" target="_blank">View Icons Here</a>
@error('icon')
<span class="text-danger d-blcok">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="typename">Short Name</label>
<input type='text' value="{{@old('typename')}}" name='typename' class="form-control @error('typename') is-invalid @enderror">
@error('typename')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="title">Title</label>
<input type='text' name='title' value="{{@old('title')}}" class='form-control @error("title") is-invalid @enderror'>
@error('title')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name='description' class="form-control @error('description') is-invalid @enderror" rows='3'>{{@old('description')}}</textarea>
@error('description')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="params">Parms</label>
<textarea name='params' class="form-control @error('params') is-invalid @enderror" rows='20'>{{@old('params')}}</textarea>
@error('params')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div>
<button type="submit" class="mt-3 ml-3 btn btn-info">Save</button>
</div>
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,95 @@
@extends('layouts.sidebar')
@section('content')
<div class='card'>
<div class='card-header'>
<h4 class='card-title'>Edit Link Type</h1>
</div>
<div class='card-body'>
<!-- if there are creation errors, they will show here -->
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action='/admin/linktype/{{$linktype->id}}' method="POST">
@method('PUT')
@csrf
<div class="form-group">
<label for="icon">Icon</label>
<input type='text' value="{{$linktype->icon}}" name='icon' class="form-control @error('icon') is-invalid @enderror">
<a href="https://icons.getbootstrap.com/" target="_blank">View Icons Here</a>
@error('icon')
<span class="text-danger d-blcok">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="typename">Short Name</label>
<input type='text' value="{{$linktype->typename}}" name='typename' readonly class="form-control @error('typename') is-invalid @enderror">
@error('typename')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="title">Title</label>
<input type='text' name='title' value="{{$linktype->title}}" class='form-control @error("title") is-invalid @enderror'>
@error('title')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name='description' class="form-control @error('description') is-invalid @enderror" rows='3'>{{$linktype->description}}</textarea>
@error('description')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group">
<label for="params">Parms</label>
<textarea name='params' class="form-control @error('params') is-invalid @enderror" rows='20'>{{$linktype->params}}</textarea>
@error('params')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div>
<button type="submit" class="mt-3 ml-3 btn btn-info">Save</button>
</div>
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,43 @@
@extends('layouts.sidebar')
@section('content')
<h1>Link Types</h1>
<div>
<a href="{{ url('admin/linktype/create') }}">Add New</a>
</div>
<!-- will be used to show any messages -->
@if (Session::has('message'))
<div class="alert alert-info">{{ Session::get('message') }}</div>
@endif
<div class=''>
@foreach($linktype as $key => $value)
<div class='row mb-2 border shdadow'>
<div class='col-12 h5'><i class='{{ $value->icon }}'></i> {{ $value->title }} <span class='small text-muted'>[{{ $value->typename }}]</span></div>
<div class='col-12'>{{ $value->description }}</div>
<div class='col-12 card-footer bg-light border border-top border-light'>
<form action='/admin/linktype/{{$value->id}}' method="POST">
<a class="btn btn-link btn-sm" href="{{ URL::to('admin/linktype/' . $value->id . '/edit') }}"><i class='bi bi-pencil'></i> Edit</a>
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-link p-2 text-danger" href="{{ URL::to('admin/linktype/' . $value->id . '/edit') }}" onclick="return confirm('Are you sure?')"><i class='bi bi-trash'></i> Delete</a>
</form>
</div>
</div>
@endforeach
</div>
@endsection

View File

@ -1,17 +1,65 @@
<x-guest-layout>
<x-auth-card>
<x-slot name="logo">
<a href="{{ url('') }}">
<x-application-logo class="w-20 h-20 fill-current text-gray-500" />
</a>
</x-slot>
<!-- Session Status -->
<x-auth-session-status class="mb-4" :status="session('status')" />
<!-- Validation Errors -->
<x-auth-validation-errors class="mb-4" :errors="$errors" />
@if(env('ENABLE_SOCIAL_LOGIN') === 'true')
<p class="mb-4 text-center">Login with</p>
<div class="flex flex-nowrap justify-center mb-3">
@if(!empty(env('FACEBOOK_CLIENT_ID')))
<a href="{{ route('social.redirect','facebook') }}" class="text-white bg-blue-600 bg-blue-600/90 focus:ring-4 focus:outline-none focus:ring-[#3b5998]/50 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-[#3b5998]/55 mr-2 mb-2">
<svg class="mr-2 -ml-1 w-4 h-4" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="facebook-f" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
<path fill="currentColor" d="M279.1 288l14.22-92.66h-88.91v-60.13c0-25.35 12.42-50.06 52.24-50.06h40.42V6.26S260.4 0 225.4 0c-73.22 0-121.1 44.38-121.1 124.7v70.62H22.89V288h81.39v224h100.2V288z"></path>
</svg>
Facebook
</a>
@endif
@if(!empty(env('TWITTER_CLIENT_ID')))
<a href="{{ route('social.redirect','twitter') }}" class="text-white bg-blue-400 bg-blue-400/90 focus:ring-4 focus:outline-none focus:ring-[#1da1f2]/50 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-[#1da1f2]/55 mr-2 mb-2">
<svg class="mr-2 -ml-1 w-4 h-4" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor" d="M459.4 151.7c.325 4.548 .325 9.097 .325 13.65 0 138.7-105.6 298.6-298.6 298.6-59.45 0-114.7-17.22-161.1-47.11 8.447 .974 16.57 1.299 25.34 1.299 49.06 0 94.21-16.57 130.3-44.83-46.13-.975-84.79-31.19-98.11-72.77 6.498 .974 12.99 1.624 19.82 1.624 9.421 0 18.84-1.3 27.61-3.573-48.08-9.747-84.14-51.98-84.14-102.1v-1.299c13.97 7.797 30.21 12.67 47.43 13.32-28.26-18.84-46.78-51.01-46.78-87.39 0-19.49 5.197-37.36 14.29-52.95 51.65 63.67 129.3 105.3 216.4 109.8-1.624-7.797-2.599-15.92-2.599-24.04 0-57.83 46.78-104.9 104.9-104.9 30.21 0 57.5 12.67 76.67 33.14 23.72-4.548 46.46-13.32 66.6-25.34-7.798 24.37-24.37 44.83-46.13 57.83 21.12-2.273 41.58-8.122 60.43-16.24-14.29 20.79-32.16 39.31-52.63 54.25z"></path>
</svg>
Twitter
</a>
@endif
@if(!empty(env('GOOGLE_CLIENT_ID')))
<a href="{{ route('social.redirect','google') }}" class="text-white bg-blue-500 hover:bg-blue-500/90 focus:ring-4 focus:outline-none focus:ring-[#4285F4]/50 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-[#4285F4]/55 mr-2 mb-2">
<svg class="mr-2 -ml-1 w-4 h-4" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="google" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 488 512">
<path fill="currentColor" d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"></path>
</svg>
Google
</a>
@endif
</div>
<hr class="block w-full mb-4 border-0 border-t border-gray-300" />
<p class="mb-4 text-center">OR</p>
@endif
<form method="POST" action="{{ route('login') }}">
@csrf
@ -26,10 +74,7 @@
<div class="mt-4">
<x-label for="password" :value="__('Password')" />
<x-input id="password" class="block mt-1 w-full"
type="password"
name="password"
required autocomplete="current-password" />
<x-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="current-password" />
</div>
<!-- Remember Me -->
@ -51,6 +96,13 @@
{{ __('Log in') }}
</x-button>
</div>
</div>
</form>
</x-auth-card>
</x-guest-layout>

View File

@ -17,6 +17,44 @@ foreach($pages as $page)
<!-- Validation Errors -->
<x-auth-validation-errors class="mb-4" :errors="$errors" />
<p class="mb-4 text-center">Login with</p>
<div class="flex flex-nowrap justify-center mb-3">
@if(!empty(env('FACEBOOK_CLIENT_ID')))
<a href="{{ route('social.redirect','facebook') }}" class="text-white bg-blue-600 bg-blue-600/90 focus:ring-4 focus:outline-none focus:ring-[#3b5998]/50 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-[#3b5998]/55 mr-2 mb-2">
<svg class="mr-2 -ml-1 w-4 h-4" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="facebook-f" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
<path fill="currentColor" d="M279.1 288l14.22-92.66h-88.91v-60.13c0-25.35 12.42-50.06 52.24-50.06h40.42V6.26S260.4 0 225.4 0c-73.22 0-121.1 44.38-121.1 124.7v70.62H22.89V288h81.39v224h100.2V288z"></path>
</svg>
Facebook
</a>
@endif
@if(!empty(env('TWITTER_CLIENT_ID')))
<a href="{{ route('social.redirect','twitter') }}" class="text-white bg-blue-400 bg-blue-400/90 focus:ring-4 focus:outline-none focus:ring-[#1da1f2]/50 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-[#1da1f2]/55 mr-2 mb-2">
<svg class="mr-2 -ml-1 w-4 h-4" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor" d="M459.4 151.7c.325 4.548 .325 9.097 .325 13.65 0 138.7-105.6 298.6-298.6 298.6-59.45 0-114.7-17.22-161.1-47.11 8.447 .974 16.57 1.299 25.34 1.299 49.06 0 94.21-16.57 130.3-44.83-46.13-.975-84.79-31.19-98.11-72.77 6.498 .974 12.99 1.624 19.82 1.624 9.421 0 18.84-1.3 27.61-3.573-48.08-9.747-84.14-51.98-84.14-102.1v-1.299c13.97 7.797 30.21 12.67 47.43 13.32-28.26-18.84-46.78-51.01-46.78-87.39 0-19.49 5.197-37.36 14.29-52.95 51.65 63.67 129.3 105.3 216.4 109.8-1.624-7.797-2.599-15.92-2.599-24.04 0-57.83 46.78-104.9 104.9-104.9 30.21 0 57.5 12.67 76.67 33.14 23.72-4.548 46.46-13.32 66.6-25.34-7.798 24.37-24.37 44.83-46.13 57.83 21.12-2.273 41.58-8.122 60.43-16.24-14.29 20.79-32.16 39.31-52.63 54.25z"></path>
</svg>
Twitter
</a>
@endif
@if(!empty(env('GOOGLE_CLIENT_ID')))
<a href="{{ route('social.redirect','google') }}" class="text-white bg-blue-500 hover:bg-blue-500/90 focus:ring-4 focus:outline-none focus:ring-[#4285F4]/50 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-[#4285F4]/55 mr-2 mb-2">
<svg class="mr-2 -ml-1 w-4 h-4" aria-hidden="true" focusable="false" data-prefix="fab" data-icon="google" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 488 512">
<path fill="currentColor" d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"></path>
</svg>
Google
</a>
@endif
</div>
<form method="POST" action="{{ route('register') }}">
@csrf

View File

@ -0,0 +1,4 @@
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $slot }}</strong>
</div>

View File

@ -1,5 +1,5 @@
@if(file_exists(base_path("littlelink/images/avatar.png" )))
<img class="mb-5" src="{{ asset('littlelink/images/avatar.png') }}" srcset="{{ asset('littlelink/images/avatar@2x.png 2x') }}" style="width: 150px;">
@if(file_exists(base_path("/littlelink/images/avatar.png" )))
<img class="mb-5" src="{{ asset('/littlelink/images/avatar.png') }}" srcset="{{ asset('/littlelink/images/avatar@2x.png 2x') }}" style="width: 150px;">
@else
<img class="mb-5" src="{{ asset('littlelink/images/avatar@2x.png') }}">
<img class="mb-5" src="{{ asset('/littlelink/images/avatar@2x.png') }}">
@endif

View File

@ -19,6 +19,9 @@
if(EnvEditor::keyExists('ENABLE_THEME_UPDATER')){ /* Do nothing if key already exists */
} else {EnvEditor::addKey('ENABLE_THEME_UPDATER', 'true');}
if(EnvEditor::keyExists('ENABLE_SOCIAL_LOGIN')){ /* Do nothing if key already exists */
} else {EnvEditor::addKey('ENABLE_SOCIAL_LOGIN', 'false');}
if (!config()->has('advanced-config.expand_panel_admin_menu_permanently') and !config()->has('disable_default_password_notice')) {
function getStringBetween($string, $start, $end) {

View File

@ -0,0 +1,42 @@
@if ($message = Session::get('success'))
<div class="alert alert-success alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
@endif
@if ($message = Session::get('error'))
<div class="alert alert-danger alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
@endif
@if ($message = Session::get('warning'))
<div class="alert alert-warning alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
@endif
@if ($message = Session::get('info'))
<div class="alert alert-info alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

View File

@ -0,0 +1,25 @@
<div class="modal" tabindex="-1" role="dialog" id="{{ $getModalIdString() }}">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ $title }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{ $slot }}
</div>
<div class="modal-footer">
{{$buttons}}
{{-- <button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> --}}
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,5 @@
<div class='button-heading'>
<h2>{{$link->title}}</h2>
</div>

View File

@ -0,0 +1,4 @@
<label for='title' class='form-label'>Heading Text:</label>
<input type='text' name='title' value='{{$link_title}}' class='form-control' />

View File

@ -0,0 +1,13 @@
@php
$BaseURL = str_replace(array('http://', 'https://'), '', $link->link)
@endphp
<a class="button button-custom button button-hover icon-hover" rel="noopener noreferrer nofollow" href="{{ route('clickNumber') . '/' . $link->id . '/' . $link->link}}" @if(theme('open_links_in_same_tab') !="true" )target="_blank" @endif>
@if($params->GetSiteIcon ?? true)
<img alt="button-icon" class="icon hvr-icon" src="https://icons.duckduckgo.com/ip3/{{$BaseURL}}.ico">
@endif
{{ $link->title }}
</a>

View File

@ -0,0 +1,15 @@
<label for='title' class='form-label'>Title</label>
<input type='text' name='title' value='{{$link_title}}' class='form-control' required />
<label for='title' class='form-label'>URL</label>
<input type='url' name='link' value='{{$link_url}}' class='form-control' />
<div class="custom-control custom-checkbox m-2">
<input type="checkbox" class="custom-control-input" value='1' {{((isset($params->GetSiteIcon) ? boolval($params->GetSiteIcon) : false) ? 'checked': '') }} name='GetSiteIcon' id="GetSiteIcon">
<label class="custom-control-label" for="GetSiteIcon">Show website icon on button</label>
</div>

View File

@ -0,0 +1,6 @@
<a class="button button-{{ $params->button }} button button-hover icon-hover" rel="noopener noreferrer nofollow" href="{{ route('clickNumber') . '/' . $link->id . '/' . $link->link}}" @if(theme('open_links_in_same_tab') !="true" )target="_blank" @endif>
<img alt="button-icon" class="icon hvr-icon" src="@if(theme('use_custom_icons') == " true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/{{$params->button}}{{theme('custom_icon_extension')}} @else{{ asset('\/littlelink/icons\/') . $params->button }}.svg @endif">
{{ ucfirst($link->title) }}
</a>

View File

@ -0,0 +1,18 @@
<label for='button' class='form-label'>Select a predefined site</label>
<select name='button' class='form-control'>
@foreach ($buttons as $b)
<option class='button button-{{$b["name"]}}' value='{{$b["name"]}}' {{ $b["selected"] == true ? "selected" : ""}}>{{$b["title"]}}</option>
@endforeach
</select>
<label for='title' class='form-label'>Custom Title</label>
<input type='text' name='title' value='{{$link_title}}' class='form-control' />
<span class='small text-muted'>Leave blank for default title</span>
<label for='link' class='form-label'>URL</label>
<input type='url' name='link' value='{{$link_url}}' class='form-control' required />
<span class='small text-muted'>Enter the URL for to your profile page</span>

View File

@ -0,0 +1,7 @@
<div class='button-spacer' style='height: {{$params->height *5}}px'> </div>

View File

@ -0,0 +1,8 @@
<label for='title' class='form-label'>Spacing height</label>
{{-- <input type='number' name='height' value="{{$params->height ?? ''}}" class='form-control w-25' /> --}}
<input type="range" class="custom-range" id="height" name='height' value={{$params->height??5}} oninput="this.nextElementSibling.value = this.value"><output class='font-weight-bold'>{{$params->height??5}}</output>

View File

@ -0,0 +1,3 @@
<div class='button-text'> {{$params->text}}</div>

View File

@ -0,0 +1,3 @@
<label for='text' class='form-label'>Text to display</label>
<textarea name='text' class='form-control'>{{$params->text ?? ''}}
</textarea>

View File

@ -0,0 +1,34 @@
<div class='button-video'>
<?php
$embed = OEmbed::get($link->link);
if ($embed) {
echo $embed->html();
// Print default embed html code.
//--echo $embed->html();
// Print embed html code with custom width. Works for IFRAME and VIDEO html embed code.
// echo $embed->html(['width' => 600]);
// Checks if embed data contains details on thumbnail.
//--$embed->hasThumbnail();
// Returns an array containing thumbnail details: url, width and height.
//--$embed->thumbnail();
// Return thumbnail url if it exists or null.
//--$embed->thumbnailUrl();
// Returns an array containing all available embed data including default HTML code.
//print_r( $embed->data());
}
?>
</div>

View File

@ -0,0 +1,7 @@
<label for='title' class='form-label'>Title</label>
<input type='text' name='title' value='{{$link_title}}' placeholder="Leave blank for default video title" class='form-control' />
<label for='link' class='form-label'>URL</label>
<input type='url' name='link' value='{{$link_url}}' class='form-control' />
<span class='small text-muted'>URL to the video</span>

View File

@ -88,6 +88,46 @@ return $path;}
{{-- custom font for logo text --}}
<style>@font-face{font-family:'ll';src:url({{ asset('littlelink/fonts/littlelink-custom.otf') }}) format("opentype")}</style>
<style>
.reg {
background-color: #0085FF;
border: 1px solid transparent;
}
.reg a {
color: #fff;
}
.log {
background-color: #fefefe;
border: 1px solid #000;
}
.log a {
color: #333;
}
.btns {
display: inline-block;
font-weight: 400;
text-align: center;
vertical-align: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin-left: 0.75rem;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
border-radius: 0.25rem;
-webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out;
-o-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out;
}
</style>
</head>
<body>
@ -127,14 +167,14 @@ foreach($pages as $page)
<div class="sign" style="margin-top: 30px; text-align: right;">
@if (Route::has('login'))
@auth
<a href="{{ route('studioIndex') }}" class="underline spacing">Studio</a>
<div class="fadein btns log"><a href="{{ route('studioIndex') }}" class="underline spacing">Studio</a></div>
@else
<a href="{{ route('login') }}" class="underline spacing">Log in</a>
<div class="fadein btns log"><a href="{{ route('login') }}" class="underline spacing">Log in</a></div>
@if (Route::has('register') and $page->register == 'true')
<a href="{{ route('register') }}" class="underline spacing">Register</a>
<div class="fadein btns reg"><a href="{{ route('register') }}" class="underline spacing">Register</a></div>
@elseif (env('REGISTER_OVERRIDE') === true)
<a href="{{ route('register') }}" class="underline spacing">Register</a>
<div class="fadein btns reg"><a href="{{ route('register') }}" class="underline spacing">Register</a></div>
@endif
@endauth
@endif

View File

@ -6,6 +6,8 @@
@include('layouts.analytics')
<base href="{{url()->current()}}" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="{{ asset('littlelink/css/hover-min.css') }}">
@ -109,9 +111,67 @@ if($url1sb == '200' or $url2sb == '200') {
@endif
@stack('sidebar-stylesheets')
<style>
.segmented-button {
display: flex;
margin-right: 0.75rem;
margin-top: 0.1rem;
}
.segmented-button .dropdown-button {
padding: 0 1rem;
margin-left: 1px;
}
.btn-seg, .btn-seg-large {
text-decoration: none;
color: #fff;
background-color: #f8b739;
text-align: center;
letter-spacing: .5px;
transition: .2s ease-out;
cursor: pointer;
}
.btn-seg:hover {
color: #fff;
}
.btn-seg, .btn-seg-large, .btn-seg-floating, .btn-seg-large, .btn-seg-flat {
outline: 0;
}
.btn-seg, .btn-seg-large, .btn-seg-flat {
border: none;
border-radius: 0.25rem;
display: inline-block;
height: 36px;
line-height: 36px;
padding: 0 2rem;
text-transform: uppercase;
vertical-align: middle;
-webkit-tap-highlight-color: transparent;
}
.z-depth-1, nav, .card-panel, .card, .toast, .btn-seg, .btn-seg-large, .btn-seg-floating, .dropdown-content, .collapsible, .side-nav {
box-shadow: 0 2px 2px 0 rgb(0 0 0 / 14%), 0 1px 5px 0 rgb(0 0 0 / 12%), 0 3px 1px -2px rgb(0 0 0 / 20%);
}
</style>
{{-- Couldn't get this fixed so I did this: --}}
@if (request()->route()->getName() == 'env-editor.index')
<style>
.btn-seg-ico {
position: relative;
top: 10px;
left: 1px;
}
</style>
@endif
</head>
<body>
<div class="wrapper d-flex align-items-stretch">
<nav id="sidebar">
<div class="p-4 pt-5">
@ -138,13 +198,13 @@ if($url1sb == '200' or $url2sb == '200') {
<a href="{{ url('env-editor') }}">Config</a>
</li>
<li>
<a href="{{ url('panel/users/all') }}">Users</a>
<a href="{{ url('panel/users/all') }}">Manage Users</a>
</li>
<li>
<a href="{{ url('panel/pages') }}">Pages</a>
<a href="{{ url('panel/pages') }}">Footer Pages</a>
</li>
<li>
<a href="{{ url('panel/site') }}">Site</a>
<a href="{{ url('panel/site') }}">Home Page</a>
</li>
</ul>
</li>
@ -152,19 +212,19 @@ if($url1sb == '200' or $url2sb == '200') {
<li>
<li class="active">
<a href="{{ url('/studio/add-link') }}">Add Link</a>
<a href="{{ url('/studio/add-link') }}">Add Page Item</a>
</li>
<li>
<a href="{{ url('/studio/links') }}">Links</a>
<a href="{{ url('/studio/links') }}">Your Links</a>
</li>
<li>
<a href="{{ url('/studio/page') }}">Page</a>
<a href="{{ url('/studio/page') }}">Your Page</a>
</li>
<li>
<a href="{{ url('/studio/theme') }}">Themes</a>
<a href="{{ url('/studio/theme') }}">Your Themes</a>
</li>
<li>
<a href="{{ url('/studio/profile') }}">Profile</a>
<a href="{{ url('/studio/profile') }}">Account Settings</a>
</li>
<form action="{{ route('logout') }}" method="post">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
@ -236,29 +296,95 @@ if($url1sb == '200' or $url2sb == '200') {
@endif
@endif
@elseif(env('NOTIFY_UPDATES') == 'true' or env('NOTIFY_UPDATES') === 'major' or env('NOTIFY_UPDATES') === 'all')
<?php // Checks if URL exists
try {
function URL_exists(string $urlsb): bool
{
return str_contains(get_headers($urlsb)[0], "200 OK");
}
// Sets $ServerExists to true if URL exists
if (URL_exists("https://julianprieber.github.io/littlelink-custom/version.json")){
$ServerExists = "true";
}
} catch (exception $e) {
$ServerExists = "false";
}
?>
<! Checks if file version.json exists AND if version.json exists on server to continue (without this PHP will throw ErrorException ) >
@if(file_exists(base_path("version.json")))
@if(file_exists(base_path("version.json")) and $ServerExists == 'true')
<?php // Requests newest version from server and sets it as variable
try{
$Vgit = file_get_contents("https://version.littlelink-custom.com/");
$Vgit = file_get_contents("https://julianprieber.github.io/littlelink-custom/version.json");
// Requests current version from the local version file and sets it as variable
$Vlocal = file_get_contents(base_path("version.json"));
}
catch (Exception $e){
$Vgit = "0";
$Vlocal = "0";
}
?>
<! If user has role admin AND newest GitHub release version is higher than the local one an update notice will be displayed >
@if(auth()->user()->role == 'admin' and $Vgit > $Vlocal)
<a style="color:#007bff" class="nav-link" href="{{ url('update') }}" title="Click here to learn more about how to update">An update is available</a>
<button class="update-notification"><a class="update-link nav-link" href="{{ url('update') }}" title="Click here to learn more about how to update">Update</a></button>
<?php
$version1 = $Vlocal;
$version2 = $Vgit;
$version1_steps = explode(".", $version1);
$version2_steps = explode(".", $version2);
$count = 0;
// first digit
if ($version2_steps[0] - $version1_steps[0] == 1) {
$count += 10;
}
// second digit
if ($version2_steps[1] - $version1_steps[1] == 1) {
$count += 10;
}
for ($i = 2; $i < count($version1_steps); $i++) {
$count += $version2_steps[$i] - $version1_steps[$i];
}
$count = abs($count);
?>
<style>
:root {
@if($count < 4)
--bg-color: rgba(63, 144, 90, 0.2);
--bo-color: rgb(63, 144, 90);
@elseif($count > 3 and $count < 6)
--bg-color: rgb(213, 184, 95, 0.2);
--bo-color: rgba(213, 183, 95);
@else
--bg-color: rgb(255, 99, 71, 0.2);
--bo-color: rgb(255, 99, 71);
@endif
}
.update-link{
color: var(--bo-color) !important;
}
.update-notification{
display: inline-block;
margin-bottom: 0;
font-size: 14px;
height: 2.5rem;
line-height: 1rem;
width: auto;
font-weight: 500;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: var(--bg-color);
border: 1px solid var(--bo-color);
border-radius: 25px;
}
</style>
@endif
@endif
@endif
@ -283,7 +409,23 @@ if($url1sb == '200' or $url2sb == '200') {
<script>function ColorOverrride(){document.cookie="color_scheme_override=dark; path=/",location.reload()}var btn=document.getElementById("myBtn");btn.addEventListener("click",ColorOverrride);</script>
@endif
<a class="nav-link" href="{{ url('') }}/@<?= Auth::user()->littlelink_name ?>" target="_blank">View Page</a>
<div class="segmented-button">
<a style="font-weight: 130%" href="{{ url('') }}/@<?= Auth::user()->littlelink_name ?>" target="_blank" class="btn-seg">View Page</a>
<a onclick="copyText('{{ url('') }}/@<?= Auth::user()->littlelink_name ?>')" style="color:#fff" class="btn-seg dropdown-button"><i class="btn-seg-ico bi bi-share-fill"></i></a>
</div>
<div id='dropdown1' class='dropdown-content'>
</div>
<script>
function copyText(text) {
var dummy = document.createElement("textarea");
document.body.appendChild(dummy);
dummy.value = text;
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
alert('URL has been copied to your clipboard!')
}
</script>
</div>
</li>
</ul>
@ -301,7 +443,7 @@ $userdbs = DB::table('users')->where('id', $littlelink_current)->get();
@foreach($userdbs as $userdb)
@if(Hash::check('12345678', $userdb->password))
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<nav class="shadow navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a style="background-color:tomato;color:#fff;border-radius:5px;" class="nav-link" href="{{ url('/studio/profile') }}" target=""><i class="bi bi-exclamation-circle-fill"></i> <strong>You are still using the default password! Click here to change this.</strong></a>
</div>
@ -312,10 +454,22 @@ $userdbs = DB::table('users')->where('id', $littlelink_current)->get();
@endif
<! #### begin event detection #### >
@if(env('NOTIFY_EVENTS') === true)
<?php
try {
$GetEventJson = file_get_contents("https://event.littlelink-custom.com/");
function URL_event_exists(string $urlsb): bool
{
return str_contains(get_headers($urlsb)[0], "200 OK");
}
if (URL_event_exists("https://julianprieber.github.io/littlelink-custom-events/event.json")){
$EventServerExists = "true";
}
} catch (exception $e) {
$EventServerExists = "false";
}
?>
@if(env('NOTIFY_EVENTS') === true and $EventServerExists == 'true')
<?php
$GetEventJson = file_get_contents("https://julianprieber.github.io/littlelink-custom-events/event.json");
$EventJson = json_decode($GetEventJson, true);
if(isset($_COOKIE['HideEvent']) == NULL) {
setcookie("HideEvent",$_COOKIE['ID'] = "0", time()+60*60*24*5, "/");
@ -350,7 +504,6 @@ if(localStorage.getItem("firstTime")==null){
}
</script>
@endif
<?php } catch (Exception $e){} ?>
@endif
<! #### end event detection #### >
@yield('content')

View File

@ -95,11 +95,7 @@ return $path;}
<meta name="designer" href="{{ url('') . "/theme/@" . $littlelink_name}}" content="{{ url('') . "/theme/@" . $littlelink_name}}">
<link rel="stylesheet" href="themes/{{$info->theme}}/share.button.css">
@if(theme('use_default_buttons') == "true")
<link rel="stylesheet" href="{{ asset('littlelink/css/brands.css') }}">
@else
<link rel="stylesheet" href="themes/{{$info->theme}}/brands.css">
@endif
<link rel="stylesheet" href="themes/{{$info->theme}}/skeleton-auto.css">
@if(file_exists(base_path('themes/' . $info->theme . '/animations.css')))
<link rel="stylesheet" href="<?php echo asset('themes/' . $info->theme . '/animations.css') ?>">
@ -272,6 +268,8 @@ function get_operating_system() {
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-hover icon-hover" style="{{ $link->custom_css }}" rel="noopener noreferrer nofollow" 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>
@elseif($link->name === "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" href="{{ route('clickNumber') . '/' . $link->id . '/' . $link->link}}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="button-icon" 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('\/littlelink/icons\/')}}coffee.svg @endif">Buy me a Coffee</a></div>
@elseif($link->name === "mastodon")
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-{{ $link->name }} button button-hover icon-hover" rel="me noopener noreferrer nofollow" href="{{ route('clickNumber') . '/' . $link->id . '/' . $link->link}}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="button-icon" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/{{$linkName}}{{theme('custom_icon_extension')}} @else{{ asset('\/littlelink/icons\/') . $linkName }}.svg @endif">{{ $link->title }}</a></div>
@elseif($link->name === "custom_website"and $link->custom_css === "" or $link->custom_css === "NULL" or (theme('allow_custom_buttons') == "false" and $link->name === "custom"))
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-custom_website button button-hover icon-hover" rel="noopener noreferrer nofollow" href="{{ route('clickNumber') . '/' . $link->id . '/' . $link->link}}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="button-icon" class="icon hvr-icon" src="https://icons.duckduckgo.com/ip3/{{strp($link->link)}}.ico">{{ $link->title }}</a></div>
@elseif($link->name === "custom_website" and $link->custom_css != "")
@ -288,8 +286,7 @@ function get_operating_system() {
@elseif($link->name === "heading")
<h2>{{ $link->title }}</h2>
@else
<?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" href="{{ route('clickNumber') . '/' . $link->id . '/' . $link->link}}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="button-icon" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/{{$linkName}}{{theme('custom_icon_extension')}} @else{{ asset('\/littlelink/icons\/') . $linkName }}.svg @endif">@if($isNewName == "true"){{ $newLinkName }}@else{{ ucfirst($newLinkName) }}@endif</a></div>
<div style="--delay: {{ $initial++ }}s" class="button-entrance"><a class="button button-{{ $link->name }} button button-hover icon-hover" rel="noopener noreferrer nofollow" href="{{ route('clickNumber') . '/' . $link->id . '/' . $link->link}}" @if(theme('open_links_in_same_tab') != "true")target="_blank"@endif ><img alt="button-icon" class="icon hvr-icon" src="@if(theme('use_custom_icons') == "true"){{ url('themes/' . $GLOBALS['themeName'] . '/extra/custom-icons')}}/{{$linkName}}{{theme('custom_icon_extension')}} @else{{ asset('\/littlelink/icons\/') . $linkName }}.svg @endif">{{ $link->title }}</a></div>
@endif
@endforeach

View File

@ -2,7 +2,10 @@
@section('content')
<h2 class="mb-4"><i class="bi bi-person"> Edit User</i></h2>
<section class="shadow text-gray-400">
<h2 class="mb-4 card-header"><i class="bi bi-person"> Edit User</i></h2>
<div class="card-body p-0 p-md-3">
@foreach($user as $user)
<form action="{{ route('editUser', $user->id) }}" enctype="multipart/form-data" method="post">
@csrf
@ -65,4 +68,6 @@
<button type="submit" class="mt-3 ml-3 btn btn-info">Submit</button>
</form>
</div>
</section>
@endsection

View File

@ -2,7 +2,9 @@
@section('content')
<h2 class="mb-4"><i class="bi bi-link-45deg"> Links</i></h2>
<section class="shadow text-gray-400">
<h2 class="mb-4 card-header"><i class="bi bi-link-45deg"> Links</i></h2>
<div class="card-body p-0 p-md-3">
<div style="overflow-y: auto;">
<table class="table table-bordered">
@ -33,4 +35,6 @@
<a class="btn btn-primary" href="{{ url('/panel/users/all') }}"> Back</a>
</div>
</section>
@endsection

View File

@ -4,7 +4,9 @@
<script src="{{ asset('resources/ckeditor/ckeditor.js') }}"></script>
<h2 class="mb-4"><i class="bi bi-person"> Edit Pages</i></h2>
<section class="shadow text-gray-400">
<h2 class="mb-4 card-header"><i class="bi bi-person"> Edit Pages</i></h2>
<div class="card-body p-0 p-md-3">
<form action="{{ route('editSitePage') }}" method="post">
@csrf
@ -37,4 +39,6 @@
<button type="submit" class="mt-3 ml-3 btn btn-info">Submit</button>
</form>
</div>
</section>
@endsection

View File

@ -4,7 +4,9 @@
<script src="{{ asset('resources/ckeditor/ckeditor.js') }}"></script>
<h2 class="mb-4"><i class="bi bi-person"> Site</i></h2>
<section class="shadow text-gray-400">
<h2 class="mb-4 card-header"><i class="bi bi-person"> Site</i></h2>
<div class="card-body p-0 p-md-3">
<form action="{{ route('editSite') }}" enctype="multipart/form-data" method="post">
@csrf
@ -19,4 +21,7 @@
<button type="submit" class="mt-3 ml-3 btn btn-info">Submit</button>
</form>
</div>
</section>
@endsection

File diff suppressed because one or more lines are too long

View File

@ -156,7 +156,9 @@ var button_css = {
<script src="https://kit.fontawesome.com/c4a5e06183.js" crossorigin="anonymous"></script>
<div>
<h2 class="mb-4"><i class="bi bi-pen"> Button Editor</i>
<section class="shadow text-gray-400">
<h2 class="mb-4 card-header"><i class="bi bi-pen"> Button Editor</i></h2>
<div class="card-body p-0 p-md-3">
<br><br><a class="btn btn-primary" href="{{ url('/studio/links') }}"> Back</a>
@ -336,5 +338,7 @@ NULL
<a class="btn btn-primary" href="{{ url('/studio/links') }}"> Back</a>
</div>
</section>
@endsection
@endif

View File

@ -2,44 +2,127 @@
@section('content')
<h2 class="mb-4"><i class="bi bi-pen"> Edit Link</i></h2>
<section class=' shadow text-gray-400'>
<form action="{{ route('editLink', $id) }}" method="post">
<h3 class="card-header"><i class="bi bi-journal-plus"> @if($LinkID !== 0) Edit @else Add @endif Page Item</i></h3>
<div class='card-body'>
<form action="{{ route('addLink') }}" method="post">
@method('POST')
@csrf
<div class="form-group col-lg-8">
<label>Link</label>
<input type="text" name="link" value="{{ $link }}" class="form-control" placeholder="https://example.com" required>
</div>
<div class="form-group col-lg-8">
<label>Title</label>
<input type="text" name="title" value="{{ $title }}" class="form-control" placeholder="Example">
</div>
<div class="form-group col-lg-8">
<label for="exampleFormControlSelect1">Button</label>
<select class="form-control" name="button">
<option style="background-color:#1e90ff;color:#fff"> {{ $buttonName }} </option>
<input type='hidden' name='linkid' value="{{ $LinkID }}" />
<div class="form-group col-lg-8 flex justify-around">
<label class='font-weight-bold'>Link Type: </label>
<div class="btn-group shadow m-2">
<button type="button" id='btnLinkType' class="border-0 p-1" title='Click to change link type' data-toggle="modal" data-target="#SelectLinkType">link</button>
<button type="button" class="dropdown-toggle border-0 border-left-1 px-2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu">
@foreach ( $LinkTypes as $lt )
<a data-typeid='{{$lt['id']}}' data-typename='{{$lt['title']}}' class="dropdown-item doSelectLinkType" href="#">
<i class="{{$lt['icon']}}"></i> {{$lt['title']}}
</a>
@if ($buttonName != "custom")<option style="background-color:#ffe8e4;"> custom </option>@endif
@if ($buttonName != "custom_website")<option style="background-color:#ffe8e4;"> custom_website </option>@endif
@foreach($buttons as $button)
@if (!in_array($button->name, ['custom', 'custom_website', 'heading', 'space']))
@if ($button->name != $buttonName)
<option> {{ $button->name }} </option>
@endif
@endif
@endforeach
@if ($buttonName != "heading")<option style="background-color:#ebebeb;"> heading </option>@endif
@if ($buttonName != "space")<option style="background-color:#ebebeb;"> space </option>@endif
</select>
</div>
<input type='hidden' name='linktype_id' value='1'>
</div>
</div>
<div class="form-group col-lg-8">
<label>Order</label>
<input type="number" name="order" value="{{ $order }}" class="form-control" placeholder="use for ordering links">
{{-- @include("components.pageitems.".$SelectedLinkType['typename']."-form", ['some' => 'data']) --}}
<div id='link_params' class='col-lg-8'></div>
<div class="row">
<a class="btn btn-secondary mt-3 ml-3 btn" href="{{ url()->previous() }}">Cancel</a>
<button type="submit" class="mt-3 ml-3 btn btn-primary">Save</button>
</div>
<button type="submit" class="mt-3 ml-3 btn btn-info">Submit</button>
</form>
</div>
</section>
<br><br>
{{-- <details>
<summary>More information</summary>
<pre style="color: grey;">
The 'Custom' button allows you to add a custom link, where the text on the button is determined with the link title set above.
The 'Custom_website' button functions similar to the Custom button, with the addition of a function that requests the favicon from the chosen URL and uses it as the button icon.
The 'Space' button will be replaced with an empty space, so buttons could be visually separated into groups. Entering a number between 1-10 in the title section will change the empty space's distance.
The 'Heading' button will be replaced with a sub-heading, where the title defines the text on that heading.
</pre>
</details> --}}
<!-- Modal -->
<x-modal title="Select Link Type" id="SelectLinkType">
<div class="d-flex flex-row flex-wrap p-3">
@foreach ( $LinkTypes as $lt )
<a href="#" data-typeid='{{$lt['id']}}' data-typename='{{$lt['title']}}'' class="hvr-grow m-2 w-100 d-block doSelectLinkType">
<div class="card w-100">
<div class="row no-gutters">
<div class="col-auto bg-light justify-content-center p-3">
<i class="card-img h1 text-primary {{$lt['icon']}} d-block"></i>
</div>
<div class="col">
<div class="card-body">
<h5 class="card-title mb-0">{{$lt['title']}}</h5>
<p class="card-text text-muted">{{$lt['description']}}</p>
</div>
</div>
</div>
</div>
</a>
@endforeach
</div>
<x-slot name="buttons">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</x-slot>
</x-modal>
@endsection
@push("sidebar-scripts")
<script>
$(function() {
LoadLinkTypeParams($("input[name='linktype_id']").val() , $("input[name=linkid]").val());
$('.doSelectLinkType').on('click', function() {
$("input[name='linktype_id']").val($(this).data('typeid'));
$("#btnLinkType").html($(this).data('typename'));
LoadLinkTypeParams($(this).data('typeid'), $("input[name=linkid]").val());
$('#SelectLinkType').modal('hide');
});
function LoadLinkTypeParams($TypeId, $LinkId) {
var baseURL = <?php echo "\"" . url('') . "\""; ?>;
$("#link_params").html(' <img width="70px" src="' + baseURL + '/img/loading.gif" />').load(baseURL + `/studio/linkparamform_part/${$TypeId}/${$LinkId}`);
}
});
</script>
@endpush

View File

@ -0,0 +1,45 @@
@extends('layouts.sidebar')
@section('content')
<h2 class="mb-4"><i class="bi bi-pen"> Edit Link</i></h2>
<form action="{{ route('editLink', $id) }}" method="post">
@csrf
<div class="form-group col-lg-8">
<label>Link</label>
<input type="text" name="link" value="{{ $link }}" class="form-control" placeholder="https://example.com" required>
</div>
<div class="form-group col-lg-8">
<label>Title</label>
<input type="text" name="title" value="{{ $title }}" class="form-control" placeholder="Example">
</div>
<div class="form-group col-lg-8">
<label for="exampleFormControlSelect1">Button</label>
<select class="form-control" name="button">
<option style="background-color:#1e90ff;color:#fff"> {{ $buttonName }} </option>
@if ($buttonName != "custom")<option style="background-color:#ffe8e4;"> custom </option>@endif
@if ($buttonName != "custom_website")<option style="background-color:#ffe8e4;"> custom_website </option>@endif
@foreach($buttons as $button)
@if (!in_array($button->name, ['custom', 'custom_website', 'heading', 'space']))
@if ($button->name != $buttonName)
<option> {{ $button->name }} </option>
@endif
@endif
@endforeach
@if ($buttonName != "heading")<option style="background-color:#ebebeb;"> heading </option>@endif
@if ($buttonName != "space")<option style="background-color:#ebebeb;"> space </option>@endif
</select>
</div>
<div class="form-group col-lg-8">
<label>Order</label>
<input type="number" name="order" value="{{ $order }}" class="form-control" placeholder="use for ordering links">
</div>
<button type="submit" class="mt-3 ml-3 btn btn-info">Submit</button>
</form>
@endsection

View File

@ -1,18 +1,95 @@
@extends('layouts.sidebar')
@section('content')
@if($littlelink_name == '')
<h2 class="mb-4"> 👋 Hi, stranger</h2>
@if($greeting == '')
<h3 class="mb-3"> 👋 Hi, stranger</h2>
<h5>You do not have a Page URL set, yet you can change that on the <a href="{{ url('/studio/page') }}">Page section</a></h5>
@else
<h2 class="mb-4"> 👋 Hi, @<?= $littlelink_name ?></h2>
<h3 class="mb-3"> 👋 Hi, <?= $greeting ?></h2>
@endif
<p>
Welcome to {{ config('app.name') }}!
</p>
<div class="mt-5 row">
<h5 class="mb-4"><i class="bi bi-link"> link: {{ $links }} </i></h5>
<h5 class="mb-4 ml-5"><i class="bi bi-eye"> click: {{ $clicks }} </i></h5>
<!-- Section: Design Block -->
<section class="mb-3 text-gray-800 text-center shadow p-4 w-full">
<div class='font-weight-bold text-left'>Visitor analytics:</div>
<div class="d-flex flex-wrap justify-content-around">
<div class="p-2">
<h3 class="text-primary"><strong>{{ $pageStats['visitors']['day']}}</strong></h3>
<span class="text-muted">Today</span>
</div>
<div class="p-2">
<h3 class="text-primary"><strong>{{ $pageStats['visitors']['week']}}</strong></h3>
<span class="text-muted">Week</span>
</div>
<div class="p-2">
<h3 class="text-primary"><strong>{{ $pageStats['visitors']['month']}}</strong></h3>
<span class="text-muted">Month</span>
</div>
<div class="p-2">
<h3 class="text-primary"><strong>{{ $pageStats['visitors']['year']}}</strong></h3>
<span class="text-muted">Year</span>
</div>
<div class="p-2">
<h3 class="text-primary"><strong>{{ $pageStats['visitors']['all']}}</strong></h3>
<span class="text-muted">All Time</span>
</div>
</div>
</section>
<section class="mb-3 text-center shadow p-4 w-full">
<div class=" d-flex">
<div class='p-2 h6'><i class="bi bi-link"></i> Total Links: <span class='text-primary'>{{ $links }} </span></div>
<div class='p-2 h6'><i class="bi bi-eye"></i> Link Clicks: <span class='text-primary'>{{ $clicks }}</span></div>
</div>
<div class='text-center w-100'>
<a href="{{ url('/studio/links') }}">View/Edit Links</a>
</div>
<div class='w-100 text-left'>
<h6><i class="bi bi-sort-up"></i> Top Links:</h6>
@php $i = 0; @endphp
@foreach($toplinks as $link)
@php $linkName = str_replace('default ','',$link->name) @endphp
@php $i++; @endphp
<ol class='list-group list-group-flush bg-transparent'>
@if($link->name !== "phone" && $link->name !== 'heading')
<li class="list-group-item bg-transparent">
{{ $i }}.) {{$link->title}} -- <span class='text-primary' title='Click Count'>{{$link->click_number}} </span> <br />
<a href="{{$link->link}}" class='small ml-3' title='{{$link->link}}' target="_blank">{{$link->link}}</a></li>
@endif
</ol>
@endforeach
</section>
{{-- <pre>{{ print_r($pageStats) }}</pre> --}}
@endsection

View File

@ -2,10 +2,6 @@
@section('content')
@push('sidebar-stylesheets')
<base href="{{asset('')}}" />
@endpush
@if(Request::is('studio/links/10'))
@php setcookie("LinkCount", "10", time()+60*60*24*5, "/"); @endphp
@elseif(Request::is('studio/links/20'))
@ -16,46 +12,103 @@
@php setcookie("LinkCount", "all", time()+60*60*24*5, "/"); @endphp
@endif
<h2 class="mb-4"><i class="bi bi-link-45deg"> Links</i></h2>
<section class=' shadow text-gray-400'>
<h3 class="card-header"><i class="bi bi-link-45deg">My Links</i>
<a class="btn btn-primary float-right" href="{{ url('/studio/add-link') }}">Add new <span class='d-none d-md-inline'>item</span></a>
<div style="text-align: right;"><a href="{{ url('/studio/links') }}/10">10</a> | <a href="{{ url('/studio/links') }}/20">20</a> | <a href="{{ url('/studio/links') }}/30">30</a> | <a href="{{ url('/studio/links') }}/all">all</a></div>
<div style="overflow-y: auto;">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Link</th>
<th scope="col">Title</th>
<th scope="col">Clicks</th>
<th scope="col">Order </th>
{{-- <th scope="col">Pin Link </th> --}}
<th scope="col">Edit</th>
@if(env('ENABLE_BUTTON_EDITOR') === true)<th scope="col">Button Editor</th>@endif
<th scope="col">Delete</th>
</tr>
</thead>
<tbody id="links-table-body" data-page="{{request('page', 1)}}" data-per-page="{{$pagePage ? $pagePage : 0}}">
</h3>
<div class='card-body p-0 p-md-3'>
{{-- <div style="text-align: right;"><a href="{{ url('/studio/links') }}/10">10</a> | <a href="{{ url('/studio/links') }}/20">20</a> | <a href="{{ url('/studio/links') }}/30">30</a> | <a href="{{ url('/studio/links') }}/all">all</a></div> --}}
<div style="overflow-y: none;" class="col col-md-7 ">
<div id="links-table-body" data-page="{{request('page', 1)}}" data-per-page="{{$pagePage ? $pagePage : 0}}">
@foreach($links as $link)
<tr data-id="{{$link->id}}">
<td title="{{ $link->link }}"><span class="sortable-handle"></span> {{ Str::limit($link->link, 30) }}</td>
<td title="{{ $link->title }}">{{ Str::limit($link->title, 30) }}</td>
<td class="text-right">{{ $link->click_number }}</td>
<td class="text-right">{{ $link->order }}</td>
{{-- <td><a href="{{ route('upLink', ['up' => $link->up_link, 'id' => $link->id]) }}" class="text-primary">{{ $link->up_link }}</a></td> --}}
<td><a href="{{ route('editLink', $link->id ) }}">Edit</a></td>
@if(env('ENABLE_BUTTON_EDITOR') === true)
@if($link->button_id == 1 or $link->button_id == 2)
<td><a href="{{ route('editCSS', $link->id ) }}" class="text-success">Customize Button</a></td>
<div class='row h-100 pb-0 mb-2 border rounded hvr-glow ' data-id="{{$link->id}}">
<div class='col-auto p-2 my-auto mr-2' title="{{ $link->link }}">
<span class=" sortable-handle"></span>
</div>
<div class='col border-left h-100'>
<div class='row h-100'>
<div class='col-12 p-2' title="{{ $link->title }}">
<span class='h6'>
@if($link->typename == 'predefined')
<span class='button button-{{$link->params['button']}} p-0' style='max-width: 25px; max-height: 25px; line-height: 0; cursor: none;'>
<img alt="button-icon" height="15" class="m-1 " src="{{ asset('\/littlelink/icons\/') . $link->params['button'] }}.svg ">
</span>
@else
<td><a> - </a></td>
{{-- Change later!!!! fa-external-link --}}
<i class="fa-external-link" title="{{$link->title}}"></i>
@endif
{{$link->title}}</span>
@if(!empty($link->link))
<br /><a title='{{$link->link}}' href="{{ $link->link}}" target="_blank" class="ml-4 text-muted small">{{Str::limit($link->link, 75 )}}</a>
@endif
</div>
<div class='col' class="text-right">
{{Str::limit($link->params['text'] ?? null, 150) }}
@if($link->typename == 'video')
@php
$embed = OEmbed::get($link->link);
if ($embed && $embed->hasThumbnail()) {
echo "<img style='max-height: 150px;' src='".$embed->thumbnailUrl()."' />";
}
@endphp
@endif
</div>
<div class='col-12 py-1 px-3 m-0 bg-blend-darken card-footer mt-2'>
<a href="{{ route('editLink', $link->id ) }}" class="hvr-grow mr-2"><i class='bi bi-pencil'></i> Edit</a>
@if(env('ENABLE_BUTTON_EDITOR') === true)
@if($link->id == '1' or $link->id == '2')
<a href="{{ route('editCSS', $link->id ) }}" class="mr-2 hvr-grow text-success">Customize</a>
@endif
@endif
<td><a href="{{ route('deleteLink', $link->id ) }}" class="text-danger">Delete</a></td>
</tr>
@if(!empty($link->link))
<span class='hvr-grow'><i class="bi bi-bar-chart-line"></i> {{ $link->click_number }} Clicks</span>
@endif
<a href="{{ route('deleteLink', $link->id ) }}" onclick="return confirm('Are you sure you want to delete `{{$link->title}}` ?')" class="float-right hvr-grow p-1 text-danger"><i class='bi bi-trash'></i></a>
</div>
</div>
</div>
</div>
@endforeach
</tbody>
</table>
</div>
<script type="text/javascript">
const linksTableOrders = "{{ implode("|", $links->pluck('id')->toArray()) }}"
const linksTableOrders = "{{ implode(' | ', $links->pluck('id')->toArray()) }}"
</script>
</div>
@ -63,6 +116,7 @@
{!! $links ?? ''->links() !!}
</ul>
<a class="btn btn-primary" href="{{ url('/studio/add-link') }}">Add a link</a>
<a class="btn btn-primary" href="{{ url('/studio/add-link') }}">Add new item</a>
</div>
</section>
@endsection

View File

@ -2,10 +2,25 @@
@section('content')
@if(env('ALLOW_USER_HTML') === true) <script src="{{ asset('resources/ckeditor/ckeditor.js') }}"></script> @endif
<style>
.ck-editor__editable[role="textbox"] {
/* editing area */
min-height: 200px;
}
<h2 class="mb-4"><i class="bi bi-file-earmark-break"> Page</i></h2>
.ck-content .image {
/* block images */
max-width: 80%;
margin: 20px auto;
}
</style>
<section class=' shadow text-gray-400'>
<h3 class="mb-4 card-header"><i class="bi bi-file-earmark-break"> My Page</i></h3>
<div class="card-body p-0 p-md-3">
<div class="card-body"></div>
@foreach($pages as $page)
<form action="{{ route('editPage') }}" enctype="multipart/form-data" method="post">
@csrf
@ -20,8 +35,12 @@
@if(file_exists(base_path("img/$page->littlelink_name" . ".png" )))
<img src="{{ asset("img/$page->littlelink_name" . ".png") }}" style="width: 75px; height: 75px; border-radius: 50%; object-fit: cover;">
@else
@if(!empty($page->image))
<img src="{{ $page->image }}" style="width: 75px; height: 75px; object-fit: cover;">
@else
<img src="{{ asset('littlelink/images/logo.svg') }}" style="width: 75px; height: 75px; object-fit: cover;">
@endif
@endif
</div>
<!--<div class="form-group col-lg-8">
@ -41,6 +60,14 @@
</div>
<input type="text" class="form-control" name="pageName" value="{{ $page->littlelink_name ?? '' }}" required>
</div>
<label style="margin-top:15px">Display name</label>
<div class="input-group">
{{-- <div class="input-group-prepend">
<div class="input-group-text">Name:</div>
</div> --}}
<input type="text" class="form-control" name="Name" value="{{ $page->name }}" required>
</div>
</div>
<div class="form-group col-lg-8">
@ -51,4 +78,59 @@
<button type="submit" class="mt-3 ml-3 btn btn-info">Submit</button>
</form>
@if(env('ALLOW_USER_HTML') === true)
<script src="https://cdn.ckeditor.com/ckeditor5/35.1.0/classic/ckeditor.js"></script>
<script>
ClassicEditor
.create(document.querySelector('.ckeditor'), {
toolbar: {
items: [
'exportPDF', 'exportWord', '|'
, 'findAndReplace', 'selectAll', '|'
, 'heading', '|'
, 'bold', 'italic', 'strikethrough', 'underline', 'code', 'subscript', 'superscript', 'removeFormat', '|'
, 'bulletedList', 'numberedList', 'todoList', '|'
, 'outdent', 'indent', '|'
, 'undo', 'redo'
, 'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor', 'highlight', '|'
, 'alignment', '|'
, 'link', 'blockQuote', '|'
, 'specialCharacters', 'horizontalLine', '|'
, 'textPartLanguage', '|'
]
, shouldNotGroupWhenFull: true
}
, fontFamily: {
options: [
'default'
, 'Arial, Helvetica, sans-serif'
, 'Courier New, Courier, monospace'
, 'Georgia, serif'
, 'Lucida Sans Unicode, Lucida Grande, sans-serif'
, 'Tahoma, Geneva, sans-serif'
, 'Times New Roman, Times, serif'
, 'Trebuchet MS, Helvetica, sans-serif'
, 'Verdana, Geneva, sans-serif'
]
, supportAllValues: true
},
fontSize: {
options: [ 10, 12, 14, 'default', 18, 20, 22 ],
supportAllValues: true
},
})
.catch(error => {
console.error(error);
});
</script>
@endif
</div>
</div>
</section>
@endsection

View File

@ -2,24 +2,27 @@
@section('content')
<h2 class="mb-4"><i class="bi bi-person"> Profile</i></h2>
@if($_SERVER['QUERY_STRING'] === '')
<section class="shadow text-gray-400">
<h3 class="mb-4 card-header"><i class="bi bi-person"> Account Settings</i></h3>
<div class="card-body p-0 p-md-3">
@foreach($profile as $profile)
<form action="{{ route('editProfile') }}" method="post">
{{-- <form action="{{ route('editProfile') }}" method="post">
@csrf
<div class="form-group col-lg-8">
<h3>Name</h3>
<input type="text" class="form-control" name="name" value="{{ $profile->name }}" required>
</div>
<button type="Change " class="mt-3 ml-3 btn btn-info">Change name</button>
</form>
</form><br><br> --}}
@if(env('REGISTER_AUTH') != 'verified' or auth()->user()->role == 'admin')
<br><br><form action="{{ route('editProfile') }}" method="post">
<form action="{{ route('editProfile') }}" method="post">
@csrf
<div class="form-group col-lg-8">
<h3>Email</h3>
<h4>Email</h4>
<input type="email" class="form-control" name="email" value="{{ $profile->email }}" required>
</div>
<button type="Change " class="mt-3 ml-3 btn btn-info">Change email</button>
@ -29,7 +32,7 @@
<br><br><form action="{{ route('editProfile') }}" method="post">
@csrf
<div class="form-group col-lg-8">
<h3>Password</h3>
<h4>Password</h4>
<input type="password" name="password" class="form-control" placeholder="At least 8 characters" required>
</div>
<button type="Change " class="mt-3 ml-3 btn btn-info">Change password</button>
@ -37,8 +40,44 @@
@csrf
<br><br><div class="form-group col-lg-8">
<h3>Role</h3>
<h4>Role</h4>
<input type="text" class="form-control" value="{{ strtoupper($profile->role) }}" readonly>
</div>
<br><button class="mt-3 ml-3 btn btn-primary" style="margin-bottom:2rem;margin-top:2rem!important;background-color:tomato!important;border-color:tomato!important;"><a href="{{ url('/studio/profile/?delete')}}" style="color:#FFFFFF;"><i class="bi bi-exclamation-octagon-fill"></i> Delete your account</a></button>
</div>
</section>
@endforeach
@endif
@if($_SERVER['QUERY_STRING'] === 'delete')
<center style="margin-top: 14%;">
<h2 style="text-decoration: underline;">You are about to delete your account!</h2>
<p>You are about to delete your account! This action cannot be undone.</p>
<div>
<button class="redButton mt-3 ml-3 btn btn-primary" style="width:10rem; background-color:tomato!important;border-color:tomato!important; filter: grayscale(100%);" disabled onclick="window.location.href = '{{ url('/studio/delete-user/') . "/" . Auth::id() }}';"><i class="bi bi-exclamation-diamond-fill"></i></button>
<button type="submit" class="mt-3 ml-3 btn btn-info"><a style="color:#fff;" href="{{ url('/studio/profile') }}">Cancel</a></button>
</div>
<script>
var seconds = 10;
var interval = setInterval(function() {
document.querySelector(".redButton").innerHTML = --seconds;
if (seconds <= 0)
clearInterval(interval);
}, 1000);
setTimeout(function(){
document.querySelector(".redButton").disabled = false;
document.querySelector(".redButton").innerHTML = 'Delete account';
document.querySelector(".redButton").style.filter = "none";
}, 10000);
</script>
</center>
@endif
@endsection

View File

@ -2,38 +2,57 @@
@section('content')
@foreach($pages as $page)
<h2 class="mb-4"><i class="bi bi-brush"> Select a theme</i></h2>
<section class=' shadow text-gray-400'>
<h3 class="mb-4 card-header"><i class="bi bi-brush"> Select a theme</i></h3>
<div class="card-body p-0 p-md-3">
<section class="shadow text-gray-400"></section>
<div class="card-body p-0 p-md-3">
<form action="{{ route('editTheme') }}" enctype="multipart/form-data" method="post">
@csrf
<br><br><div class="form-group col-lg-8">
<div class="form-group row">
<div class="col-8 col-md-4">
<select style="margin-left: 15px; margin-bottom: 20px;" class="form-control" name="theme" data-base-url="{{ url('') }}/@<?= Auth::user()->littlelink_name ?>">
<?php if ($handle = opendir('themes')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo '<option >'; print_r($entry); echo '</option>'; }}} ?>
<option selected>default</option>
</select>
</div>
<div class="col">
<button type="submit" class="btn btn-primary">Apply</button>
</div>
</div>
{{-- <br><br><div class="form-group col-lg-8">
<h3>Current theme</h3>
@if(empty($page->theme))
<input type="text" class="form-control" value="default" readonly>
@else
<input type="text" class="form-control" value="{{ $page->theme }}" readonly>
@endif
</div><br>
</div><br> --}}
<div id="result" style="left: 1%; position: relative; background-color:#2c2d3a; border-radius: 25px; min-width:300px; max-width:950px; box-shadow: 0 10px 20px -10px rgba(0,0,0, 0.6);">
<div style="padding:5%5%;">
<h3 align="center" style="color:white">Preview:</h3>
@if(env('USE_THEME_PREVIEW_IFRAME') === false or $page->littlelink_name == '')
<center><img style="width:95%;max-width:700px;argin-left:1rem!important;" src="@if(file_exists(base_path() . '/themes/' . $page->theme . '/preview.png')){{url('/themes/' . $page->theme . '/preview.png')}}@elseif($page->theme === 'default' or empty($page->theme)){{url('/littlelink/images/themes/default.png')}}@else{{url('/littlelink/images/themes/no-preview.png')}}@endif"></img></center>
</div></div><br>
@else
<iframe allowtransparency="true" id="frPreview" style="background: #FFFFFF;height:400px;" class='w-100' src="{{ url('') }}/@<?= Auth::user()->littlelink_name ?>">Your browser isn't compatible</iframe>
@endif
<div class="form-group col-lg-8">
<h3>Select a theme</h3>
<select class="form-control" name="theme">
<?php if ($handle = opendir('themes')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo '<option>'; print_r($entry); echo '</option>'; }}} ?>
<option>default</option>
</select>
</div>
<button type="submit" class="mt-3 ml-3 btn btn-info">Update theme</button>
</div><br>
</form>
</details>
@ -43,7 +62,14 @@
details {
width: 65%;
margin-left: 15px;
{{-- max-width: calc(100% - 20rem); --}}
{
{
-- max-width: calc(100% - 20rem);
--
}
}
position: relative;
border: 1px solid #78909C;
border-radius: 6px;
@ -114,7 +140,10 @@ summary {
display: none;
}
}
table, th, td {
table,
th,
td {
border: 1px solid black;
}
@ -149,7 +178,10 @@ table, th, td {
$text = file_get_contents(base_path('themes') . '/' . $entry . '/readme.md');
$pattern = '/Theme Version:.*/';
preg_match($pattern, $text, $matches, PREG_OFFSET_CAPTURE);
$verNr = substr($matches[0][0],15);}
if(sizeof($matches) > 0) {
$verNr = substr($matches[0][0],15);
}
}
$themeVe = NULL;
@ -213,7 +245,13 @@ table, th, td {
</table>
</div>
<a href="{{url('update/theme')}}" onclick="updateicon()" class="mt-3 ml-3 btn btn-info row"><span id="updateicon" class=""><i class="bi bi-arrow-repeat"></i></span> Update all themes</a><br><br>
<script>function updateicon() { var element = document.getElementById("updateicon"); element.classList.add("updatespin");}</script>
<script>
function updateicon() {
var element = document.getElementById("updateicon");
element.classList.add("updatespin");
}
</script>
</details>
<?php
@ -237,16 +275,35 @@ try{ if($GLOBALS['updateAv'] == true) echo '<img style="padding-left:40px; paddi
<label>Upload theme</label>
<input type="file" accept=".zip" class="form-control-file" name="zip">
</div>
<style>.deltheme{color:tomato;font-size:120%;}.deltheme:hover{color:red;text-decoration:underline;}</style>
<a class="deltheme" href="{{ url('/panel/theme') }}">&emsp; Delete themes</a>
<style>
.deltheme {
color: tomato;
font-size: 120%;
}
.deltheme:hover {
color: red;
text-decoration: underline;
}
</style>
<div class="row">
<button type="submit" class="mt-3 ml-3 btn btn-info">Upload theme</button>
<button class="mt-3 ml-3 btn btn-primary" style="background-color:tomato!important;border-color:tomato!important;" title="Delete themes"><a href="{{ url('/panel/theme') }}" target="_blank" style="color:#FFFFFF;">Delete themes</a></button>
<button class="mt-3 ml-3 btn btn-primary" title="Download more themes"><a href="https://littlelink-custom.com/themes.php" target="_blank" style="color:#FFFFFF;">Download themes</a></button>
</div>
</form>
</details>
@push('sidebar-scripts')
<script>
$(function() {
$('select[name=theme]').on('change', function() {
var s = $(this).data('base-url') + "?t=" + $(this).val();
$("#frPreview").prop('src', s);
})
});
class Accordion {
constructor(el) {
// Store the <details> element
@ -300,8 +357,8 @@ class Accordion {
// Set the keyframes from the startHeight to endHeight
height: [startHeight, endHeight]
}, {
duration: 400,
easing: 'ease-out'
duration: 400
, easing: 'ease-out'
});
// When the animation is complete, call onAnimationFinish()
@ -338,8 +395,8 @@ class Accordion {
// Set the keyframes from the startHeight to endHeight
height: [startHeight, endHeight]
}, {
duration: 400,
easing: 'ease-out'
duration: 400
, easing: 'ease-out'
});
// When the animation is complete, call onAnimationFinish()
this.animation.onfinish = () => this.onAnimationFinish(true);
@ -365,7 +422,9 @@ document.querySelectorAll('details').forEach((el) => {
});
</script>
</div>
</section>
@endpush
@endif
@endforeach

View File

@ -4,7 +4,7 @@
<div class="container">
<?php // Requests newest version from server and sets it as variable
$Vgit = file_get_contents("https://version.littlelink-custom.com/");
$Vgit = file_get_contents("https://julianprieber.github.io/littlelink-custom/version.json");
// Requests current version from the local version file and sets it as variable
$Vlocal = file_get_contents(base_path("version.json"));
@ -210,7 +210,5 @@ exit(); ?>
@endif
@if("8" > phpversion()) <br><br><a style="background-color:tomato;color:#fff;border-radius:5px;" class="nav-link" href="{{ url('/studio/profile') }}" target=""><i class="bi bi-exclamation-circle-fill"></i> <strong>You are using an outdated version of PHP! Official support for this version will end soon.</strong></a> @endif
</div>
@endpush

View File

@ -4,7 +4,9 @@ use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AdminController;
use App\Http\Controllers\UserController;
use App\Http\Controllers\Auth\SocialLoginController;
use App\Http\Controllers\LinkTypeViewController;
use App\Http\Controllers\PagesController;
/*
|--------------------------------------------------------------------------
@ -29,7 +31,7 @@ if(file_exists(base_path('storage/app/ISINSTALLED'))){
// Disables routes if in Maintenance Mode
if(env('MAINTENANCE_MODE') != 'true' and !file_exists(base_path("storage/MAINTENANCE"))){
//Changes the homepage to a LittleLink Custom profile if set in the config
//Changes the homepage to a littlelink Custom profile if set in the config
if(config('advanced-config.custom_home_url') != '') {
$custom_home_page_url = config('advanced-config.custom_home_url');
} else {
@ -61,8 +63,7 @@ Route::get('/panel/diagnose', function () {
//Public route
$custom_prefix = config('advanced-config.custom_url_prefix');
Route::get('/going/{id?}/{link?}', [UserController::class, 'clickNumber'])->where('link', '.*')->name('clickNumber');
if (!str_contains(url()->full(), '@') and !in_array(url()->full(), [url('login'), url('register'), url('update'), url('update?error='), url('update?success='), url('update?finishing='), url('update?updating='), url('update?backups='), url('update?backup='), url('update?updating-windows='), url('updating'), url('backup')])) {
Route::get('/' . $custom_prefix . '{littlelink}', [UserController::class, 'littlelink'])->name('littlelink');}
Route::get('/' . $custom_prefix . '{littlelink}', [UserController::class, 'littlelink'])->name('littlelink');
Route::get('/@{littlelink}', [UserController::class, 'littlelink'])->name('littlelink');
Route::get('/pages/{name}', [AdminController::class, 'pages'])->name('pages');
Route::get('/theme/@{littlelink}', [UserController::class, 'theme'])->name('theme');
@ -74,9 +75,10 @@ Route::group([
if(env('FORCE_HTTPS') == 'true'){URL::forceScheme('https');}
if(isset($_COOKIE['LinkCount'])){if($_COOKIE['LinkCount'] == '20'){$LinkPage = 'showLinks20';}elseif($_COOKIE['LinkCount'] == '30'){$LinkPage = 'showLinks30';}elseif($_COOKIE['LinkCount'] == 'all'){$LinkPage = 'showLinksAll';} else {$LinkPage = 'showLinks';}} else {$LinkPage = 'showLinks';} //Shows correct link number
Route::get('/studio/index', [UserController::class, 'index'])->name('studioIndex');
Route::get('/studio/add-link', [UserController::class, 'showButtons'])->name('showButtons');
Route::get('/studio/add-link', [UserController::class, 'AddUpdateLink'])->name('showButtons');
Route::post('/studio/edit-link', [UserController::class, 'saveLink'])->name('addLink');
Route::get('/studio/edit-link/{id}', [UserController::class, 'AddUpdateLink'])->name('showLink');
Route::post('/studio/sort-link', [UserController::class, 'sortLinks'])->name('sortLinks');
Route::post('/studio/add-link', [UserController::class, 'addLink'])->name('addLink');
Route::get('/studio/links', [UserController::class, $LinkPage])->name($LinkPage);
Route::get('/studio/links/10', [UserController::class, 'showLinks'])->name('showLinks');
Route::get('/studio/links/20', [UserController::class, 'showLinks20'])->name('showLinks20');
@ -86,7 +88,6 @@ Route::get('/studio/theme', [UserController::class, 'showTheme'])->name('showThe
Route::post('/studio/theme', [UserController::class, 'editTheme'])->name('editTheme');
Route::get('/deleteLink/{id}', [UserController::class, 'deleteLink'])->name('deleteLink');
Route::get('/upLink/{up}/{id}', [UserController::class, 'upLink'])->name('upLink');
Route::get('/studio/edit-link/{id}', [UserController::class, 'showLink'])->name('showLink');
Route::post('/studio/edit-link/{id}', [UserController::class, 'editLink'])->name('editLink');
Route::get('/studio/button-editor/{id}', [UserController::class, 'showCSS'])->name('showCSS');
Route::post('/studio/button-editor/{id}', [UserController::class, 'editCSS'])->name('editCSS');
@ -95,10 +96,17 @@ Route::get('/studio/no_page_name', [UserController::class, 'showPage'])->name('s
Route::post('/studio/page', [UserController::class, 'editPage'])->name('editPage');
Route::get('/studio/profile', [UserController::class, 'showProfile'])->name('showProfile');
Route::post('/studio/profile', [UserController::class, 'editProfile'])->name('editProfile');
Route::get('/studio/delete-user/{id}', [UserController::class, 'deleteUser'])->name('deleteUser')->middleware('verified');
Route::get('/studio/linkparamform_part/{typeid}/{linkid}', [LinkTypeViewController::class, 'getParamForm'])->name('linkparamform.part');
});
}
//Social login route
Route::get('/social-auth/{provider}/callback', [SocialLoginController::class, 'providerCallback']);
Route::get('/social-auth/{provider}', [SocialLoginController::class, 'redirectToProvider'])->name('social.redirect');
//Admin route
Route::group([
'middleware' => 'admin',
@ -131,6 +139,14 @@ Route::get('/update/theme', [AdminController::class, 'updateThemes'])->name('upd
Route::get('/update', function () {return view('update', []);});
Route::get('/backup', function () {return view('backup', []);});
Route::group(['namespace'=>'App\Http\Controllers\Admin', 'prefix'=>'admin', 'as'=>'admin'],function() {
//Route::resource('/admin/linktype', LinkTypeController::class);
Route::resources([
'linktype'=>LinkTypeController::class
]);
});
Route::get('/updating', function (\Codedge\Updater\UpdaterManager $updater) {
// Check if new version is available
@ -161,7 +177,7 @@ Route::get('/updating', function (\Codedge\Updater\UpdaterManager $updater) {
});
});
}); // ENd Admin authenticated routes
// Displays Maintenance Mode page
if(env('MAINTENANCE_MODE') == 'true' or file_exists(base_path("storage/MAINTENANCE"))){

View File

@ -89,3 +89,10 @@ ALLOW_CUSTOM_CODE_IN_THEMES=true
#ENABLE_THEME_UPDATER=Determines if the theme updater should be enabled or not, default is true.
#=ENABLE_THEME_UPDATER either true or false.
ENABLE_THEME_UPDATER=true
#Needs to be configured first.
#Read more at: https://s.llc.ovh/social-login
ENABLE_SOCIAL_LOGIN=false
#Sets if a plain PNG or iframe should be used for the theme preview image
USE_THEME_PREVIEW_IFRAME=true

View File

@ -105,7 +105,7 @@ return [
// The URL prefix is the symbol that comes before a LittleLink URL.
// For example the '@' in 'example.com/@admin'.
// If empty no prefix is required.
// If empty no prefix is required. Use with caution.
'custom_url_prefix' => '+', // The '@' prefix will always work regardless of this setting.

View File

@ -8327,3 +8327,4 @@ a[data-toggle="collapse"] {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAA7AAAAOwBeShxvQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGDSURBVFiF7dexThRBHMfxj0BDAgUKvZhAZWen3JXHGxA638DYGAOVwUfgKVBewDeQmAiNpdDRHdwlJiYUtxY75G7nZm8351oY9pdssbPf/c1vdnf+M8tD12JN7gm6ge9XsNt4gVv8nj/aWN1glmGEoxnsx8BkuEGniQAXwfD+GGErwW1PdH5/fK8yX6gRYDM6f5Rog6fh2qSe1fCv1GfFUfWxluAeyx/7JHvSRID1EGIgf6Q7M9hOYAah8/UmArRq9U9VtxTv4y2eywvTXQm3ind4jWX8+NuAcKg4t8+wlOCW8C1iD5oIcB2ZZniZ4HYS3HWVeZ1SnFJWs200p39BB4qj+qr8FZxF7Psq83jxKNMeeviJY/wq4VbwRr4IfZGX8Fat/n9t4BRDnJu90ezKS/VQPgMa2ZCcKs7tG+VbstuI/dREgKHpEttLcLsJblBlXqcUX0bnGa4S3JXpchzfO5c6xrvdET7MYI+M/w36eNVEAPL325P+IYm1FdjUd9JqSn8A5m9yuDzg2a8AAAAASUVORK5CYII=");
background-size: 22px;
}

6
studio/js/ckeditor.js vendored Normal file

File diff suppressed because one or more lines are too long

21
studio/js/components/addlink.js vendored Normal file
View File

@ -0,0 +1,21 @@
// for use in add-link blade
$(function() {
LoadLinkTypeParams($("input[name='linktype_id']").val() , $("input[name=linkid]").val());
$('.doSelectLinkType').on('click', function() {
$("input[name='linktype_id']").val($(this).data('typeid'));
$("#btnLinkType").html($(this).data('typename'));
LoadLinkTypeParams($(this).data('typeid'), $("input[name=linkid]").val());
$('#SelectLinkType').hide();
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
});
function LoadLinkTypeParams($TypeId, $LinkId) {
$("#link_params").html(' <img width="70px" src="/img/loading.gif" />').load(`/studio/linkparamform_part/${$TypeId}/${$LinkId}`);
}
});

View File

@ -1,3 +1,4 @@
(function ($) {
"use strict";
@ -25,6 +26,9 @@
if (sortableTbody) {
const sortableLinkTable = Sortable.create(sortableTbody, {
handle: ".sortable-handle",
animation: 150,
swapThreshold: 0.60,
ghostClass: 'bg-info',
onChange: function (event) {
},
store: {
@ -41,22 +45,27 @@
'currentPage': currentPage,
'perPage': perPage,
};
$.blockUI({
message: '<img width="70px" src="img/loading.gif" />',
css: {
backgroundColor: 'transparent',
border: 'none',
color: '#444444',
}
});
$.post("studio/sort-link", formData, function(response) {
// $.blockUI({
// message: '<img width="70px" src="img/loading.gif" />',
// css: {
// backgroundColor: 'transparent',
// border: 'none',
// color: '#444444',
// }
// });
// VERY janky solution; have to fix later
var str = window.location.pathname;
str = str.replace("/studio/links", "");
$.post(str + "/studio/sort-link", formData, function (response) {
if (response.linkOrders) {
$.each(response.linkOrders, function (linkId, linkOrder) {
$("#links-table-body tr[data-id='"+linkId+"']")
.find("td:eq(3)")
.html(linkOrder);
// $("#links-table-body div[data-id='"+linkId+"']")
// .find("div:eq(3)")
// .html(linkOrder);
});
$.unblockUI();
//$.unblockUI();
} else {
alert("Something went wrong! Please, Try again.")
}
@ -65,4 +74,7 @@
}
});
}
})(jQuery);