Skip to content

Commit

Permalink
feat(redirection-warning): added LLink component to proxy every link …
Browse files Browse the repository at this point in the history
…by a warning if it goes outside of the current site
  • Loading branch information
Croos3r committed Jul 18, 2024
1 parent 2da7fe2 commit 05d7619
Show file tree
Hide file tree
Showing 13 changed files with 307 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/components/LLink.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script lang="ts" setup>
import { LinkHTMLAttributes, ref } from "vue";
import { AlertDialog, AlertDialogContent, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { AlertDialogOverlay, AlertDialogPortal } from "radix-vue";
import LButton from "@/components/LButton.vue";
interface IProps extends /* @vue-ignore */ LinkHTMLAttributes {}
withDefaults(defineProps<IProps>(), {});
const open = ref(false);
</script>

<template>
<RouterLink v-if="href && href.startsWith('/')" :to="href">
<slot />
</RouterLink>
<AlertDialog v-model:open="open">
<AlertDialogTrigger as-child>
<a>
<slot />
</a>
</AlertDialogTrigger>
<AlertDialogPortal>
<AlertDialogOverlay class="fixed inset-0 z-30 backdrop-blur-sm" />
<AlertDialogContent class="flex flex-col gap-y-6 bg-primary px-6 py-9 text-neutral-white">
<h6 class="body-default text-center font-bold">Leaving our website</h6>
<p class="body-tiny text-center">
You will be redirected to an external website <strong class="font-bold">({{ $attrs.href }})</strong> that is
not under our control. We cannot guarantee the accuracy, security, or reliability of the information provided
on these external sites.
</p>
<div class="gap-x- flex justify-center gap-x-3">
<a v-bind="$attrs">
<LButton class="w-[150px]" light text="Continue" @click="open = false" />
</a>
<LButton class="w-[150px]" light text="Cancel" @click="open = false" />
</div>
</AlertDialogContent>
</AlertDialogPortal>
</AlertDialog>
</template>

<style scoped></style>
14 changes: 14 additions & 0 deletions src/components/ui/alert-dialog/AlertDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script setup lang="ts">
import { type AlertDialogEmits, type AlertDialogProps, AlertDialogRoot, useForwardPropsEmits } from 'radix-vue'
const props = defineProps<AlertDialogProps>()
const emits = defineEmits<AlertDialogEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>

<template>
<AlertDialogRoot v-bind="forwarded">
<slot />
</AlertDialogRoot>
</template>
20 changes: 20 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogAction.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/components/ui/button'
const props = defineProps<AlertDialogActionProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>

<template>
<AlertDialogAction v-bind="delegatedProps" :class="cn(buttonVariants(), props.class)">
<slot />
</AlertDialogAction>
</template>
22 changes: 22 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogCancel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts" setup>
import { computed, type HTMLAttributes } from "vue";
import { AlertDialogCancel, type AlertDialogCancelProps } from "radix-vue";
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
const props = defineProps<AlertDialogCancelProps & { class?: HTMLAttributes["class"] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>

<template>
<AlertDialogCancel
:class="cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', props.class)"
v-bind="delegatedProps"
>
<slot />
</AlertDialogCancel>
</template>
42 changes: 42 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts" setup>
import { computed, type HTMLAttributes } from "vue";
import {
AlertDialogContent,
type AlertDialogContentEmits,
type AlertDialogContentProps,
AlertDialogOverlay,
AlertDialogPortal,
useForwardPropsEmits,
} from "radix-vue";
import { cn } from "@/lib/utils";
const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes["class"] }>();
const emits = defineEmits<AlertDialogContentEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>

<template>
<AlertDialogPortal>
<AlertDialogOverlay
class="bg-black/80 fixed inset-0 z-50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
/>
<AlertDialogContent
:class="
cn(
'fixed left-1/2 top-1/2 z-50 grid w-[45vw] max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
props.class,
)
"
v-bind="forwarded"
>
<slot />
</AlertDialogContent>
</AlertDialogPortal>
</template>
25 changes: 25 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogDescription.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import {
AlertDialogDescription,
type AlertDialogDescriptionProps,
} from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<AlertDialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>

<template>
<AlertDialogDescription
v-bind="delegatedProps"
:class="cn('text-sm text-muted-foreground', props.class)"
>
<slot />
</AlertDialogDescription>
</template>
21 changes: 21 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogFooter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

<template>
<div
:class="
cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
props.class,
)
"
>
<slot />
</div>
</template>
16 changes: 16 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

<template>
<div
:class="cn('flex flex-col gap-y-2 text-center sm:text-left', props.class)"
>
<slot />
</div>
</template>
22 changes: 22 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogTitle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { AlertDialogTitle, type AlertDialogTitleProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<AlertDialogTitleProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>

<template>
<AlertDialogTitle
v-bind="delegatedProps"
:class="cn('text-lg font-semibold', props.class)"
>
<slot />
</AlertDialogTitle>
</template>
11 changes: 11 additions & 0 deletions src/components/ui/alert-dialog/AlertDialogTrigger.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { AlertDialogTrigger, type AlertDialogTriggerProps } from 'radix-vue'
const props = defineProps<AlertDialogTriggerProps>()
</script>

<template>
<AlertDialogTrigger v-bind="props">
<slot />
</AlertDialogTrigger>
</template>
9 changes: 9 additions & 0 deletions src/components/ui/alert-dialog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export { default as AlertDialog } from './AlertDialog.vue'
export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue'
export { default as AlertDialogContent } from './AlertDialogContent.vue'
export { default as AlertDialogHeader } from './AlertDialogHeader.vue'
export { default as AlertDialogTitle } from './AlertDialogTitle.vue'
export { default as AlertDialogDescription } from './AlertDialogDescription.vue'
export { default as AlertDialogFooter } from './AlertDialogFooter.vue'
export { default as AlertDialogAction } from './AlertDialogAction.vue'
export { default as AlertDialogCancel } from './AlertDialogCancel.vue'
26 changes: 26 additions & 0 deletions src/components/ui/button/Button.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { Primitive, type PrimitiveProps } from 'radix-vue'
import { type ButtonVariants, buttonVariants } from '.'
import { cn } from '@/lib/utils'
interface Props extends PrimitiveProps {
variant?: ButtonVariants['variant']
size?: ButtonVariants['size']
class?: HTMLAttributes['class']
}
const props = withDefaults(defineProps<Props>(), {
as: 'button',
})
</script>

<template>
<Primitive
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"
>
<slot />
</Primitive>
</template>
35 changes: 35 additions & 0 deletions src/components/ui/button/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { type VariantProps, cva } from 'class-variance-authority'

export { default as Button } from './Button.vue'

export const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive:
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline:
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-10 px-4 py-2',
xs: 'h-7 rounded px-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
},
)

export type ButtonVariants = VariantProps<typeof buttonVariants>

0 comments on commit 05d7619

Please sign in to comment.