Add new PostFeedback and SocialShare components
Created the 'PostFeedback.astro' and 'SocialShare.astro' component files to enrich the UI interface. The PostFeedback component renders a user feedback section with a title and two responsive buttons. Whereas, the SocialShare component provides users with hyperlinks to popular social media platforms - it also enables copy-pasting of current page links using the ClipboardJS utility function and dropdown functionality from the Preline plugin.
This commit is contained in:
parent
b4f128b6e2
commit
991ec9a909
7 changed files with 369 additions and 0 deletions
7
public/scripts/vendor/clipboard.min.js
vendored
Normal file
7
public/scripts/vendor/clipboard.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
21
public/scripts/vendor/preline/dropdown/LICENSE
vendored
Normal file
21
public/scripts/vendor/preline/dropdown/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 Html Stream
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
65
public/scripts/vendor/preline/dropdown/index.d.ts
vendored
Normal file
65
public/scripts/vendor/preline/dropdown/index.d.ts
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
|
||||
export interface IDropdown {
|
||||
options?: {};
|
||||
open(): void;
|
||||
close(isAnimated: boolean): void;
|
||||
forceClearState(): void;
|
||||
}
|
||||
export interface IHTMLElementPopper extends HTMLElement {
|
||||
_popper: any;
|
||||
}
|
||||
export interface IBasePlugin<O, E> {
|
||||
el: E;
|
||||
options?: O;
|
||||
events?: {};
|
||||
}
|
||||
declare class HSBasePlugin<O, E = HTMLElement> implements IBasePlugin<O, E> {
|
||||
el: E;
|
||||
options: O;
|
||||
events?: any;
|
||||
constructor(el: E, options: O, events?: any);
|
||||
createCollection(collection: any[], element: any): void;
|
||||
fireEvent(evt: string, payload?: any): any;
|
||||
on(evt: string, cb: Function): void;
|
||||
}
|
||||
export interface ICollectionItem<T> {
|
||||
id: string | number;
|
||||
element: T;
|
||||
}
|
||||
declare class HSDropdown extends HSBasePlugin<{}, IHTMLElementPopper> implements IDropdown {
|
||||
private static history;
|
||||
private readonly toggle;
|
||||
menu: HTMLElement | null;
|
||||
private eventMode;
|
||||
private readonly closeMode;
|
||||
private animationInProcess;
|
||||
constructor(el: IHTMLElementPopper, options?: {}, events?: {});
|
||||
private init;
|
||||
resizeHandler(): void;
|
||||
private onClickHandler;
|
||||
private onMouseEnterHandler;
|
||||
private onMouseLeaveHandler;
|
||||
private destroyPopper;
|
||||
private absoluteStrategyModifiers;
|
||||
open(): boolean;
|
||||
close(isAnimated?: boolean): boolean;
|
||||
forceClearState(): void;
|
||||
static getInstance(target: HTMLElement | string, isInstance?: boolean): ICollectionItem<HSDropdown> | IHTMLElementPopper;
|
||||
static autoInit(): void;
|
||||
static open(target: HTMLElement): void;
|
||||
static close(target: HTMLElement): void;
|
||||
static accessibility(evt: KeyboardEvent): void;
|
||||
static onEscape(evt: KeyboardEvent): void;
|
||||
static onEnter(evt: KeyboardEvent): void;
|
||||
static onArrow(isArrowUp?: boolean): boolean;
|
||||
static onStartEnd(isStart?: boolean): boolean;
|
||||
static onFirstLetter(code: string): boolean;
|
||||
static closeCurrentlyOpened(evtTarget?: HTMLElement | null, isAnimated?: boolean): void;
|
||||
static on(evt: string, target: HTMLElement, cb: Function): void;
|
||||
}
|
||||
|
||||
export {
|
||||
HSDropdown as default,
|
||||
};
|
||||
|
||||
export {};
|
17
public/scripts/vendor/preline/dropdown/index.js
vendored
Normal file
17
public/scripts/vendor/preline/dropdown/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
public/scripts/vendor/preline/dropdown/package.json
vendored
Normal file
15
public/scripts/vendor/preline/dropdown/package.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@preline/dropdown",
|
||||
"version": "2.0.2",
|
||||
"description": "Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"repository": "https://github.com/htmlstreamofficial/preline.git",
|
||||
"homepage": "https://preline.co/plugins.html",
|
||||
"keywords": ["preline", "html", "css", "next", "nuxt", "vue", "react", "angular", "javascript", "typescript", "tailwind", "tailwind components", "tailwind elements", "tailwind library", "tailwind sections", "tailwind css", "tailwind ui", "tailwind css react", "tailwind css vue", "tailwind css angular", "tailwind css laravel", "tailwindcss plugin", "tailwindcss plugins", "accordion"],
|
||||
"author": "Htmlstream",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
189
src/components/ui/buttons/SocialShare.astro
Normal file
189
src/components/ui/buttons/SocialShare.astro
Normal file
|
@ -0,0 +1,189 @@
|
|||
---
|
||||
// Destructure the properties from Astro.props
|
||||
const { pageTitle } = Astro.props;
|
||||
|
||||
// Define TypeScript interface for the properties
|
||||
interface Props {
|
||||
pageTitle: string;
|
||||
}
|
||||
|
||||
type SocialPlatform = {
|
||||
name: string;
|
||||
url: string;
|
||||
svg: string;
|
||||
};
|
||||
|
||||
const socialPlatforms: SocialPlatform[] = [
|
||||
{
|
||||
name: "Facebook",
|
||||
url: `https://www.facebook.com/share.php?u=${Astro.url}&title=${pageTitle}`,
|
||||
svg: `<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
class="size-4 flex-shrink-0 fill-current"
|
||||
><title>Facebook</title><path
|
||||
d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"
|
||||
></path></svg
|
||||
>`,
|
||||
},
|
||||
{
|
||||
name: "X",
|
||||
url: `https://twitter.com/home/?status=${pageTitle}${Astro.url}`,
|
||||
svg: `<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
class="size-4 flex-shrink-0 fill-current"
|
||||
><title>X</title><path
|
||||
d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"
|
||||
></path></svg
|
||||
>`,
|
||||
},
|
||||
{
|
||||
name: "LinkedIn",
|
||||
url: `https://www.linkedin.com/shareArticle?mini=true&url=${Astro.url}&title=${pageTitle}`,
|
||||
svg: `<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
class="size-4 flex-shrink-0 fill-current"
|
||||
><title>LinkedIn</title><path
|
||||
d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
|
||||
></path></svg
|
||||
>`,
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<div
|
||||
class="hs-dropdown relative inline-flex [--auto-close:inside] [--placement:top-left]"
|
||||
>
|
||||
<button
|
||||
id="hs-dropup"
|
||||
type="button"
|
||||
class="hs-dropdown-toggle inline-flex items-center gap-x-2 rounded-lg px-4 py-3 text-sm font-medium text-neutral-600 outline-none ring-zinc-500 transition duration-300 hover:bg-neutral-100 hover:text-neutral-700 focus-visible:ring dark:text-neutral-400 dark:ring-zinc-200 dark:hover:bg-neutral-700 dark:hover:text-neutral-300 dark:focus:outline-none"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="h-4 w-4 group-hover:text-neutral-700"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
Share
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="hs-dropdown-menu duration z-10 hidden w-72 divide-y divide-neutral-200 rounded-lg bg-neutral-50 p-2 opacity-0 shadow-md transition-[opacity,margin] hs-dropdown-open:opacity-100 dark:divide-neutral-700 dark:border dark:border-neutral-700 dark:bg-neutral-800"
|
||||
aria-labelledby="hs-dropup"
|
||||
>
|
||||
<div class="py-2 first:pt-0 last:pb-0">
|
||||
{
|
||||
socialPlatforms.map((platform) => (
|
||||
<a
|
||||
class="flex items-center gap-x-3.5 rounded-lg px-3 py-2 text-sm text-neutral-700 hover:bg-neutral-200 focus:bg-neutral-100 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-700 dark:hover:text-neutral-300 dark:focus:bg-neutral-700 "
|
||||
href={platform.url}
|
||||
>
|
||||
<Fragment set:html={platform.svg} />
|
||||
Share on {platform.name}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div class="py-2 first:pt-0 last:pb-0">
|
||||
<button
|
||||
type="button"
|
||||
class="js-clipboard hover:text-dark focus-visible:ring-secondary group inline-flex w-full items-center gap-x-3.5 rounded-lg px-3 py-2 text-sm text-neutral-700 hover:bg-neutral-200 focus:bg-neutral-100 focus:outline-none focus-visible:outline-none focus-visible:ring-1 dark:text-neutral-300 dark:hover:bg-neutral-700 dark:hover:text-neutral-300 dark:focus:bg-neutral-700"
|
||||
data-clipboard-success-text="Copied"
|
||||
>
|
||||
<svg
|
||||
class="js-clipboard-default h-4 w-4 transition group-hover:rotate-6"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect width="8" height="4" x="8" y="2" rx="1" ry="1"></rect>
|
||||
<path
|
||||
d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
<svg
|
||||
class="js-clipboard-success text-primary-accent-light dark:text-primary-accent-dark hidden h-4 w-4"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<polyline points="20 6 9 17 4 12"></polyline>
|
||||
</svg>
|
||||
<span class="js-clipboard-success-text">Copy link</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Import the necessary Dropdown and Clipboard plugins-->
|
||||
<!--https://preline.co/plugins/html/dropdown.html-->
|
||||
<script is:inline src="/scripts/vendor/preline/dropdown/index.js"></script>
|
||||
|
||||
<!-- https://clipboardjs.com/ -->
|
||||
<script is:inline src="/scripts/vendor/clipboard.min.js"></script>
|
||||
|
||||
<script is:inline>
|
||||
// Initialization of Clipboard
|
||||
(function () {
|
||||
window.addEventListener("load", () => {
|
||||
const $clipboards = document.querySelectorAll(".js-clipboard");
|
||||
$clipboards.forEach((el) => {
|
||||
const clipboard = new ClipboardJS(el, {
|
||||
text: () => {
|
||||
return window.location.href;
|
||||
},
|
||||
});
|
||||
clipboard.on("success", () => {
|
||||
const $default = el.querySelector(".js-clipboard-default");
|
||||
const $success = el.querySelector(".js-clipboard-success");
|
||||
const $successText = el.querySelector(".js-clipboard-success-text");
|
||||
const successText = el.dataset.clipboardSuccessText || "";
|
||||
let oldSuccessText;
|
||||
|
||||
if ($successText) {
|
||||
oldSuccessText = $successText.textContent;
|
||||
$successText.textContent = successText;
|
||||
}
|
||||
if ($default && $success) {
|
||||
$default.style.display = "none";
|
||||
$success.style.display = "block";
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
if ($successText && oldSuccessText)
|
||||
$successText.textContent = oldSuccessText;
|
||||
if ($default && $success) {
|
||||
$success.style.display = "";
|
||||
$default.style.display = "";
|
||||
}
|
||||
}, 800);
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
55
src/components/ui/feedback/PostFeedback.astro
Normal file
55
src/components/ui/feedback/PostFeedback.astro
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
// Define props from Astro
|
||||
const { title, firstChoice, secondChoice } = Astro.props;
|
||||
|
||||
// Define TypeScript interface for props
|
||||
interface Props {
|
||||
title: string;
|
||||
firstChoice: string;
|
||||
secondChoice: string;
|
||||
}
|
||||
---
|
||||
|
||||
<div class="mt-12 flex items-center justify-center gap-x-2">
|
||||
<h3 class="text-neutral-700 dark:text-neutral-300">{title}</h3>
|
||||
<button
|
||||
type="button"
|
||||
class="group inline-flex items-center gap-x-2 rounded-lg border border-neutral-400 px-3 py-2 text-sm font-medium text-neutral-800 hover:border-yellow-500 hover:bg-yellow-500 hover:shadow-2xl hover:shadow-yellow-500 dark:border-neutral-500 dark:text-neutral-50 dark:hover:bg-yellow-500 dark:hover:text-neutral-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600"
|
||||
>
|
||||
<svg
|
||||
class="size-4 flex-shrink-0 transition duration-300 group-hover:-translate-y-1 group-focus-visible:-translate-y-1"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><path d="M7 10v12"></path><path
|
||||
d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z"
|
||||
></path></svg
|
||||
>
|
||||
{firstChoice}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="group inline-flex items-center gap-x-2 rounded-lg border border-neutral-400 px-3 py-2 text-sm font-medium text-neutral-800 hover:bg-neutral-400 dark:border-neutral-500 dark:text-neutral-50 dark:hover:bg-neutral-500 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-neutral-600"
|
||||
>
|
||||
<svg
|
||||
class="size-4 flex-shrink-0 transition duration-300 group-hover:translate-y-1 group-focus-visible:translate-y-1"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><path d="M17 14V2"></path><path
|
||||
d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z"
|
||||
></path></svg
|
||||
>
|
||||
{secondChoice}
|
||||
</button>
|
||||
</div>
|
Loading…
Add table
Reference in a new issue