@team14/cms-library 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@team14/cms-library",
3
3
  "private": false,
4
- "version": "0.1.0",
4
+ "version": "0.1.2",
5
5
  "description": "Library of Components for CMS Web App.",
6
6
  "repository": {
7
7
  "type": "git",
@@ -11,12 +11,16 @@
11
11
  "author": "Team 14 - EmanuelFuneS",
12
12
  "license": "MIT",
13
13
  "homepage": "https://github.com/No-Country-simulation/S03-26-Equipo-14-Web-App-Development",
14
+ "files": [
15
+ "dist"
16
+ ],
14
17
  "type": "module",
15
18
  "main": "./dist/index.cjs.js",
16
19
  "module": "./dist/index.es.js",
17
20
  "types": "./dist/index.d.ts",
18
21
  "exports": {
19
22
  ".": {
23
+ "types": "./dist/index.d.ts",
20
24
  "import": "./dist/index.es.js",
21
25
  "require": "./dist/index.cjs.js"
22
26
  },
package/dev/App.css DELETED
@@ -1,184 +0,0 @@
1
- .counter {
2
- font-size: 16px;
3
- padding: 5px 10px;
4
- border-radius: 5px;
5
- color: var(--accent);
6
- background: var(--accent-bg);
7
- border: 2px solid transparent;
8
- transition: border-color 0.3s;
9
- margin-bottom: 24px;
10
-
11
- &:hover {
12
- border-color: var(--accent-border);
13
- }
14
- &:focus-visible {
15
- outline: 2px solid var(--accent);
16
- outline-offset: 2px;
17
- }
18
- }
19
-
20
- .hero {
21
- position: relative;
22
-
23
- .base,
24
- .framework,
25
- .vite {
26
- inset-inline: 0;
27
- margin: 0 auto;
28
- }
29
-
30
- .base {
31
- width: 170px;
32
- position: relative;
33
- z-index: 0;
34
- }
35
-
36
- .framework,
37
- .vite {
38
- position: absolute;
39
- }
40
-
41
- .framework {
42
- z-index: 1;
43
- top: 34px;
44
- height: 28px;
45
- transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
46
- scale(1.4);
47
- }
48
-
49
- .vite {
50
- z-index: 0;
51
- top: 107px;
52
- height: 26px;
53
- width: auto;
54
- transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
55
- scale(0.8);
56
- }
57
- }
58
-
59
- #center {
60
- display: flex;
61
- flex-direction: column;
62
- gap: 25px;
63
- place-content: center;
64
- place-items: center;
65
- flex-grow: 1;
66
-
67
- @media (max-width: 1024px) {
68
- padding: 32px 20px 24px;
69
- gap: 18px;
70
- }
71
- }
72
-
73
- #next-steps {
74
- display: flex;
75
- border-top: 1px solid var(--border);
76
- text-align: left;
77
-
78
- & > div {
79
- flex: 1 1 0;
80
- padding: 32px;
81
- @media (max-width: 1024px) {
82
- padding: 24px 20px;
83
- }
84
- }
85
-
86
- .icon {
87
- margin-bottom: 16px;
88
- width: 22px;
89
- height: 22px;
90
- }
91
-
92
- @media (max-width: 1024px) {
93
- flex-direction: column;
94
- text-align: center;
95
- }
96
- }
97
-
98
- #docs {
99
- border-right: 1px solid var(--border);
100
-
101
- @media (max-width: 1024px) {
102
- border-right: none;
103
- border-bottom: 1px solid var(--border);
104
- }
105
- }
106
-
107
- #next-steps ul {
108
- list-style: none;
109
- padding: 0;
110
- display: flex;
111
- gap: 8px;
112
- margin: 32px 0 0;
113
-
114
- .logo {
115
- height: 18px;
116
- }
117
-
118
- a {
119
- color: var(--text-h);
120
- font-size: 16px;
121
- border-radius: 6px;
122
- background: var(--social-bg);
123
- display: flex;
124
- padding: 6px 12px;
125
- align-items: center;
126
- gap: 8px;
127
- text-decoration: none;
128
- transition: box-shadow 0.3s;
129
-
130
- &:hover {
131
- box-shadow: var(--shadow);
132
- }
133
- .button-icon {
134
- height: 18px;
135
- width: 18px;
136
- }
137
- }
138
-
139
- @media (max-width: 1024px) {
140
- margin-top: 20px;
141
- flex-wrap: wrap;
142
- justify-content: center;
143
-
144
- li {
145
- flex: 1 1 calc(50% - 8px);
146
- }
147
-
148
- a {
149
- width: 100%;
150
- justify-content: center;
151
- box-sizing: border-box;
152
- }
153
- }
154
- }
155
-
156
- #spacer {
157
- height: 88px;
158
- border-top: 1px solid var(--border);
159
- @media (max-width: 1024px) {
160
- height: 48px;
161
- }
162
- }
163
-
164
- .ticks {
165
- position: relative;
166
- width: 100%;
167
-
168
- &::before,
169
- &::after {
170
- content: '';
171
- position: absolute;
172
- top: -4.5px;
173
- border: 5px solid transparent;
174
- }
175
-
176
- &::before {
177
- left: 0;
178
- border-left-color: var(--border);
179
- }
180
- &::after {
181
- right: 0;
182
- border-right-color: var(--border);
183
- }
184
- }
package/dev/App.tsx DELETED
@@ -1,29 +0,0 @@
1
- import reactLogo from '../public/assets/react.svg';
2
- import viteLogo from '../public/assets/vite.svg';
3
- import heroImg from '../public/assets/hero.png';
4
- import './App.css';
5
- import TestimonialCarrousel from '../src/components/TestimonialCrousel';
6
-
7
- function App() {
8
- return (
9
- <>
10
- <section id="center">
11
- <div className="hero">
12
- <img src={heroImg} className="base" width="170" height="179" alt="" />
13
- <img src={reactLogo} className="framework" alt="React logo" />
14
- <img src={viteLogo} className="vite" alt="Vite logo" />
15
- </div>
16
- <div>
17
- <h1>CMS Library</h1>
18
- <h2>Preview Components</h2>
19
- </div>
20
- </section>
21
-
22
- <TestimonialCarrousel apiKey="cms-api-key:DRAG954HBGPTuML0KvR0_g:Wt1_pWvPMg22Y0x6r6poJcNygqyVUU9FDTVJ-F60XeqW2o9Nkuux4ND_1XvHah3m8OL93JRPyv1cHO0dreVWYFLPk-QhGQlTlIEQ1PAF8WgwdZnf6Km4vKQu_rcx_CpWqQ2vx4RJT9Rx-VqjNjunIQ" />
23
-
24
- <section id="spacer"></section>
25
- </>
26
- );
27
- }
28
-
29
- export default App;
package/dev/index.css DELETED
@@ -1,114 +0,0 @@
1
-
2
- /* index.css */
3
- @import "tailwindcss";
4
- :root {
5
- --text: #6b6375;
6
- --text-h: #08060d;
7
- --bg: #fff;
8
- --border: #e5e4e7;
9
- --code-bg: #f4f3ec;
10
- --accent: #aa3bff;
11
- --accent-bg: rgba(170, 59, 255, 0.1);
12
- --accent-border: rgba(170, 59, 255, 0.5);
13
- --social-bg: rgba(244, 243, 236, 0.5);
14
- --shadow:
15
- rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px;
16
-
17
- --sans: system-ui, 'Segoe UI', Roboto, sans-serif;
18
- --heading: system-ui, 'Segoe UI', Roboto, sans-serif;
19
- --mono: ui-monospace, Consolas, monospace;
20
-
21
- font: 18px/145% var(--sans);
22
- letter-spacing: 0.18px;
23
- color-scheme: light dark;
24
- color: var(--text);
25
- background: var(--bg);
26
- font-synthesis: none;
27
- text-rendering: optimizeLegibility;
28
- -webkit-font-smoothing: antialiased;
29
- -moz-osx-font-smoothing: grayscale;
30
-
31
- @media (max-width: 1024px) {
32
- font-size: 16px;
33
- }
34
- }
35
-
36
- @media (prefers-color-scheme: dark) {
37
- :root {
38
- --text: #9ca3af;
39
- --text-h: #f3f4f6;
40
- --bg: #16171d;
41
- --border: #2e303a;
42
- --code-bg: #1f2028;
43
- --accent: #c084fc;
44
- --accent-bg: rgba(192, 132, 252, 0.15);
45
- --accent-border: rgba(192, 132, 252, 0.5);
46
- --social-bg: rgba(47, 48, 58, 0.5);
47
- --shadow:
48
- rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
49
- }
50
-
51
- #social .button-icon {
52
- filter: invert(1) brightness(2);
53
- }
54
- }
55
-
56
- #root {
57
- width: 1126px;
58
- max-width: 100%;
59
- margin: 0 auto;
60
- text-align: center;
61
- border-inline: 1px solid var(--border);
62
- min-height: 100svh;
63
- display: flex;
64
- flex-direction: column;
65
- box-sizing: border-box;
66
- }
67
-
68
- body {
69
- margin: 0;
70
- }
71
-
72
- h1,
73
- h2 {
74
- font-family: var(--heading);
75
- font-weight: 500;
76
- color: var(--text-h);
77
- }
78
-
79
- h1 {
80
- font-size: 56px;
81
- letter-spacing: -1.68px;
82
- margin: 32px 0;
83
- @media (max-width: 1024px) {
84
- font-size: 36px;
85
- margin: 20px 0;
86
- }
87
- }
88
- h2 {
89
- font-size: 24px;
90
- line-height: 118%;
91
- letter-spacing: -0.24px;
92
- margin: 0 0 8px;
93
- @media (max-width: 1024px) {
94
- font-size: 20px;
95
- }
96
- }
97
- p {
98
- margin: 0;
99
- }
100
-
101
- code,
102
- .counter {
103
- font-family: var(--mono);
104
- display: inline-flex;
105
- border-radius: 4px;
106
- color: var(--text-h);
107
- }
108
-
109
- code {
110
- font-size: 15px;
111
- line-height: 135%;
112
- padding: 4px 8px;
113
- background: var(--code-bg);
114
- }
package/dev/index.html DELETED
@@ -1,13 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>cms-library</title>
8
- </head>
9
- <body>
10
- <div id="root"></div>
11
- <script type="module" src="./main.tsx"></script>
12
- </body>
13
- </html>
package/dev/main.tsx DELETED
@@ -1,10 +0,0 @@
1
- import { StrictMode } from 'react'
2
- import { createRoot } from 'react-dom/client'
3
- import './index.css'
4
- import App from './App.js'
5
-
6
- createRoot(document.getElementById('root')!).render(
7
- <StrictMode>
8
- <App />
9
- </StrictMode>,
10
- )
package/eslint.config.js DELETED
@@ -1,23 +0,0 @@
1
- import js from '@eslint/js'
2
- import globals from 'globals'
3
- import reactHooks from 'eslint-plugin-react-hooks'
4
- import reactRefresh from 'eslint-plugin-react-refresh'
5
- import tseslint from 'typescript-eslint'
6
- import { defineConfig, globalIgnores } from 'eslint/config'
7
-
8
- export default defineConfig([
9
- globalIgnores(['dist']),
10
- {
11
- files: ['**/*.{ts,tsx}'],
12
- extends: [
13
- js.configs.recommended,
14
- tseslint.configs.recommended,
15
- reactHooks.configs.flat.recommended,
16
- reactRefresh.configs.vite,
17
- ],
18
- languageOptions: {
19
- ecmaVersion: 2020,
20
- globals: globals.browser,
21
- },
22
- },
23
- ])
@@ -1,5 +0,0 @@
1
- export default {
2
- plugins: {
3
- "@tailwindcss/postcss": {},
4
- }
5
- }
@@ -1,115 +0,0 @@
1
- import type { ComponentProps, Testimonial } from '../../types/common';
2
- import useFetchTestimonials from '../../hooks/fetchTestimonials';
3
- import { useState } from 'react';
4
-
5
- import QuoteCard from '../UI/QuoteCard';
6
- import VideoCard from '../UI/VideoCard';
7
- import CaseCard from '../UI/CaseCard';
8
- import { AnimatePresence, motion } from 'framer-motion';
9
- import { cn } from '../../lib/index';
10
-
11
- const variants = {
12
- enter: (direction: number) => ({
13
- x: direction > 0 ? 300 : -300,
14
- opacity: 0,
15
- }),
16
- center: { x: 0, opacity: 1 },
17
- exit: (direction: number) => ({
18
- x: direction > 0 ? -300 : 300,
19
- opacity: 0,
20
- }),
21
- };
22
-
23
- const TestimonialCarrousel = ({ apiKey, length = 2, className }: ComponentProps) => {
24
- const { isLoading, testimonials } = useFetchTestimonials({ apiKey });
25
- const [currentIndex, setCurrentIndex] = useState(0);
26
- const [direction, setDirection] = useState(1);
27
-
28
- const data = testimonials?.slice(0, length) ?? [];
29
-
30
- const paginate = (newDirection: number) => {
31
- setDirection(newDirection);
32
- setCurrentIndex((prev) => (prev + newDirection + data.length) % data.length);
33
- };
34
-
35
- const renderCard = (testimonial: Testimonial) => {
36
- switch (testimonial.type) {
37
- case 'case':
38
- return <CaseCard data={testimonial} />;
39
- case 'video':
40
- return <VideoCard data={testimonial} />;
41
- default:
42
- return <QuoteCard data={testimonial} />;
43
- }
44
- };
45
-
46
- return (
47
- <div className={cn("w-full flex flex-col my-10", className)}>
48
- <div className="flex items-center justify-center px-4">
49
- {isLoading ? (
50
- <div className="text-muted-foreground">Cargando testimonios...</div>
51
- ) : (
52
- <div className="w-full max-w-3xl flex flex-col gap-8">
53
- {/* Card animada */}
54
- <div className="min-h-70 flex items-center">
55
- <AnimatePresence custom={direction} mode="wait">
56
- <motion.div
57
- key={currentIndex}
58
- custom={direction}
59
- variants={variants}
60
- initial="enter"
61
- animate="center"
62
- exit="exit"
63
- transition={{ duration: 0.5, ease: 'easeInOut' }}
64
- className="w-full"
65
- >
66
- {data[currentIndex] && renderCard(data[currentIndex])}
67
- </motion.div>
68
- </AnimatePresence>
69
- </div>
70
-
71
-
72
- <div className="flex items-center justify-center gap-8">
73
- <button
74
- onClick={() => paginate(-1)}
75
- className="w-11 h-11 flex items-center justify-center rounded-full border border-border bg-card hover:bg-accent hover:text-accent-foreground transition-colors shadow-sm"
76
- aria-label="Anterior"
77
- >
78
-
79
- </button>
80
-
81
- <div className="flex gap-3">
82
- {data.map((_, idx) => (
83
- <button
84
- key={idx}
85
- onClick={() => {
86
- setDirection(idx - currentIndex);
87
- setCurrentIndex(idx);
88
- }}
89
- className={cn(
90
- "w-3.5 h-3.5 rounded-full transition-all",
91
- idx === currentIndex
92
- ? "bg-primary scale-125"
93
- : "bg-muted-foreground/30 hover:bg-muted-foreground/50"
94
- )}
95
- aria-label={`Ir al testimonio ${idx + 1}`}
96
- />
97
- ))}
98
- </div>
99
-
100
- <button
101
- onClick={() => paginate(1)}
102
- className="w-11 h-11 flex items-center justify-center rounded-full border border-border bg-card hover:bg-accent hover:text-accent-foreground transition-colors shadow-sm"
103
- aria-label="Siguiente"
104
- >
105
-
106
- </button>
107
- </div>
108
- </div>
109
- )}
110
- </div>
111
- </div>
112
- );
113
- };
114
-
115
- export default TestimonialCarrousel;
@@ -1,44 +0,0 @@
1
- import type { Testimonial } from '../../types/common';
2
- import { cn } from '../../lib/index';
3
-
4
- interface CaseCardProps {
5
- data: Testimonial;
6
- className?: string;
7
- }
8
-
9
- const CaseCard = ({ data, className }: CaseCardProps) => {
10
- return (
11
- <div
12
- className={cn(
13
- 'border border-border bg-card text-card-foreground rounded-2xl p-8 shadow-sm',
14
- 'flex flex-col min-h-60',
15
- className,
16
- )}
17
- >
18
- <div className="flex-1 text-lg leading-relaxed text-foreground">
19
- “{data.content}”
20
- </div>
21
-
22
- <div className="mt-8 flex items-center gap-4">
23
- <div className="w-12 h-12 rounded-full bg-muted shrink-0 overflow-hidden border border-border">
24
- {data.author_photo ? (
25
- <img
26
- src={data.author_photo}
27
- alt={data.author}
28
- className="w-full h-full object-cover"
29
- />
30
- ) : (
31
- <div className="w-full h-full bg-primary/10" />
32
- )}
33
- </div>
34
-
35
- <div>
36
- <p className="font-semibold text-foreground">{data.author}</p>
37
- <p className="text-sm text-muted-foreground">{data.author_role}</p>
38
- </div>
39
- </div>
40
- </div>
41
- );
42
- };
43
-
44
- export default CaseCard;
@@ -1,11 +0,0 @@
1
- import type { Testimonial } from '../../types/common';
2
-
3
- interface QuoteCardProps {
4
- data: Testimonial;
5
- }
6
-
7
- const QuoteCard = ({}: QuoteCardProps) => {
8
- return <div>QuoteCard</div>;
9
- };
10
-
11
- export default QuoteCard;
@@ -1,11 +0,0 @@
1
- import type { Testimonial } from '../../types/common';
2
-
3
- interface VideoCardProps {
4
- data: Testimonial;
5
- }
6
-
7
- const VideoCard = ({}: VideoCardProps) => {
8
- return <div>VideoCard</div>;
9
- };
10
-
11
- export default VideoCard;
@@ -1,37 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import type { Testimonial } from '../types/common';
3
-
4
- interface useFetchTestimonialsProps {
5
- apiKey?: string;
6
- }
7
-
8
- const useFetchTestimonials = ({ apiKey }: useFetchTestimonialsProps) => {
9
- const [testimonials, setTestimonials] = useState<Testimonial[]>();
10
- const [isLoading, setIsLoading] = useState<boolean>(true);
11
-
12
- useEffect(() => {
13
- const fetchTestimonials = async () => {
14
- if (!apiKey) return;
15
- const result = await fetch(
16
- 'https://s03-26-equipo-14-web-app-development.onrender.com/embed',
17
- {
18
- method: 'Get',
19
- headers: {
20
- 'x-embed-key': apiKey,
21
- },
22
- },
23
- );
24
- const response = await result.json();
25
- if (response.success) setIsLoading(false);
26
- setTestimonials(response.data);
27
- };
28
-
29
- fetchTestimonials();
30
- }, []);
31
- return {
32
- testimonials,
33
- isLoading,
34
- };
35
- };
36
-
37
- export default useFetchTestimonials;
package/src/index.ts DELETED
@@ -1,4 +0,0 @@
1
- import TestimonialCarrousel from './components/TestimonialCrousel';
2
- import '../dev/index.css';
3
- export { TestimonialCarrousel };
4
-
package/src/lib/index.tsx DELETED
@@ -1,6 +0,0 @@
1
- import { type ClassValue, clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
6
- }
@@ -1,18 +0,0 @@
1
- export interface ComponentProps {
2
- apiKey: string;
3
- length?: number;
4
- className?: string;
5
- }
6
-
7
- export interface Testimonial {
8
- id: string;
9
- type: string;
10
- title: string;
11
- content: string;
12
- author: string;
13
- author_photo: string;
14
- author_role: string;
15
- media_url: string;
16
- media_description: string;
17
- rating: string;
18
- }
package/tsconfig.app.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
- "target": "es2023",
5
- "lib": ["ES2023", "DOM", "DOM.Iterable"],
6
- "module": "esnext",
7
- "types": ["vite/client"],
8
- "skipLibCheck": true,
9
-
10
- /* Bundler mode */
11
- "moduleResolution": "bundler",
12
- "allowImportingTsExtensions": true,
13
- "verbatimModuleSyntax": true,
14
- "moduleDetection": "force",
15
- "noEmit": true,
16
- "jsx": "react-jsx",
17
-
18
- /* Linting */
19
- "noUnusedLocals": true,
20
- "noUnusedParameters": true,
21
- "erasableSyntaxOnly": true,
22
- "noFallthroughCasesInSwitch": true
23
- },
24
- "include": ["src", "dev"]
25
- }
package/tsconfig.json DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "files": [],
3
- "references": [
4
- { "path": "./tsconfig.app.json" },
5
- { "path": "./tsconfig.node.json" }
6
- ]
7
- }