spotify-now-playing-card 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -22,6 +22,22 @@ yarn add spotify-now-playing-card
22
22
  pnpm add spotify-now-playing-card
23
23
  ```
24
24
 
25
+ ## Quick Setup
26
+
27
+ The easiest way to get started is using the setup script:
28
+
29
+ ```bash
30
+ npx spotify-now-playing-card-setup
31
+ # or if installed locally
32
+ npm run setup
33
+ ```
34
+
35
+ This will:
36
+ - Detect your framework (Next.js Pages/App Router)
37
+ - Generate the API endpoint automatically
38
+ - Set up environment variables
39
+ - Guide you through the process
40
+
25
41
  ## Prerequisites
26
42
 
27
43
  You need to set up a Spotify API endpoint that returns the currently playing track data. The component expects the API to return JSON in this format:
@@ -44,7 +60,9 @@ When not playing, the API should return:
44
60
  }
45
61
  ```
46
62
 
47
- ### Setting up Spotify API
63
+ ### Setting up Spotify API (Manual)
64
+
65
+ If you prefer to set up manually or the setup script doesn't work for your framework:
48
66
 
49
67
  1. Go to [Spotify Developer Dashboard](https://developer.spotify.com/dashboard)
50
68
  2. Create a new app
@@ -124,14 +142,19 @@ export default async function handler(req, res) {
124
142
 
125
143
  ### Basic Usage
126
144
 
145
+ **Important:** You need to import the CSS file for default styles to work:
146
+
127
147
  ```jsx
128
148
  import { SpotifyCard } from 'spotify-now-playing-card'
149
+ import 'spotify-now-playing-card/dist/styles.css' // Required for default styles
129
150
 
130
151
  function App() {
131
152
  return <SpotifyCard apiUrl="/api/spotify" />
132
153
  }
133
154
  ```
134
155
 
156
+ The component works **without Tailwind CSS** - it includes its own CSS file with default styles. If you're using Tailwind, you can still override styles using the `styles` prop.
157
+
135
158
  ### TypeScript Usage
136
159
 
137
160
  The package includes full TypeScript definitions:
@@ -184,9 +207,36 @@ function App() {
184
207
 
185
208
  ### Styling
186
209
 
187
- The component uses Tailwind CSS classes by default. Make sure you have Tailwind CSS installed and configured in your project.
210
+ The component includes its own CSS file with default styles, so **it works without Tailwind CSS**. Simply import the CSS:
188
211
 
189
- If you're not using Tailwind, you can override all styles using the `styles` prop or `className` prop.
212
+ ```jsx
213
+ import 'spotify-now-playing-card/dist/styles.css'
214
+ ```
215
+
216
+ ### Using with Tailwind CSS
217
+
218
+ If you're using Tailwind CSS, you can override the default styles using the `styles` prop:
219
+
220
+ ```jsx
221
+ <SpotifyCard
222
+ apiUrl="/api/spotify"
223
+ styles={{
224
+ container: "bg-gray-900 rounded-xl", // Tailwind classes
225
+ title: "text-white text-lg"
226
+ }}
227
+ />
228
+ ```
229
+
230
+ ### Custom CSS
231
+
232
+ You can also override styles using your own CSS by targeting the component classes:
233
+
234
+ ```css
235
+ .spotify-card-container {
236
+ background: #1a1a1a;
237
+ border-radius: 12px;
238
+ }
239
+ ```
190
240
 
191
241
  ## Dependencies
192
242
 
package/bin/setup.js ADDED
@@ -0,0 +1,298 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Spotify Card Setup Script
5
+ * Automatically generates API endpoint for Next.js or other frameworks
6
+ */
7
+
8
+ const fs = require('fs')
9
+ const path = require('path')
10
+ const readline = require('readline')
11
+
12
+ const rl = readline.createInterface({
13
+ input: process.stdin,
14
+ output: process.stdout
15
+ })
16
+
17
+ function question(query) {
18
+ return new Promise(resolve => rl.question(query, resolve))
19
+ }
20
+
21
+ async function setup() {
22
+ console.log('\nšŸŽµ Spotify Now Playing Card - Setup\n')
23
+ console.log('This script will help you set up the API endpoint for the Spotify card component.\n')
24
+
25
+ // Detect framework
26
+ const hasNextApp = fs.existsSync('app') || fs.existsSync('pages')
27
+ const hasPages = fs.existsSync('pages')
28
+ const hasApp = fs.existsSync('app')
29
+
30
+ let framework = 'nextjs'
31
+ let apiPath = 'pages/api/spotify'
32
+
33
+ if (hasApp && !hasPages) {
34
+ framework = 'nextjs-app'
35
+ apiPath = 'app/api/spotify/route'
36
+ } else if (hasPages) {
37
+ framework = 'nextjs'
38
+ apiPath = 'pages/api/spotify'
39
+ } else {
40
+ console.log('āš ļø Could not detect Next.js. Please specify:')
41
+ const frameworkChoice = await question('Framework (nextjs/nextjs-app/other): ')
42
+ if (frameworkChoice === 'nextjs-app') {
43
+ framework = 'nextjs-app'
44
+ apiPath = 'app/api/spotify/route'
45
+ } else if (frameworkChoice === 'nextjs') {
46
+ framework = 'nextjs'
47
+ apiPath = 'pages/api/spotify'
48
+ } else {
49
+ console.log('āš ļø For other frameworks, you\'ll need to create the API endpoint manually.')
50
+ console.log(' Check the README.md for the API endpoint code.')
51
+ rl.close()
52
+ return
53
+ }
54
+ }
55
+
56
+ console.log(`\nšŸ“ Detected framework: ${framework}`)
57
+ console.log(`šŸ“ API path: ${apiPath}\n`)
58
+
59
+ // Get credentials
60
+ console.log('Please provide your Spotify API credentials:')
61
+ console.log('(You can get these from https://developer.spotify.com/dashboard)\n')
62
+
63
+ const clientId = await question('Spotify Client ID: ')
64
+ const clientSecret = await question('Spotify Client Secret: ')
65
+ const refreshToken = await question('Spotify Refresh Token: ')
66
+
67
+ if (!clientId || !clientSecret || !refreshToken) {
68
+ console.log('\nāŒ All credentials are required!')
69
+ rl.close()
70
+ return
71
+ }
72
+
73
+ // Create directory if it doesn't exist
74
+ const apiDir = path.dirname(apiPath)
75
+ if (!fs.existsSync(apiDir)) {
76
+ fs.mkdirSync(apiDir, { recursive: true })
77
+ console.log(`āœ… Created directory: ${apiDir}`)
78
+ }
79
+
80
+ // Generate API endpoint code
81
+ let apiCode = ''
82
+
83
+ if (framework === 'nextjs-app') {
84
+ // Next.js App Router
85
+ apiCode = `import { NextResponse } from 'next/server';
86
+
87
+ const SPOTIFY_CLIENT_ID = process.env.SPOTIFY_CLIENT_ID;
88
+ const SPOTIFY_CLIENT_SECRET = process.env.SPOTIFY_CLIENT_SECRET;
89
+ const SPOTIFY_REFRESH_TOKEN = process.env.SPOTIFY_REFRESH_TOKEN;
90
+
91
+ // Cache for access token
92
+ let accessToken: string | null = null;
93
+ let tokenExpiry: number = 0;
94
+
95
+ async function getAccessToken(): Promise<string> {
96
+ // Return cached token if still valid
97
+ if (accessToken && Date.now() < tokenExpiry) {
98
+ return accessToken;
99
+ }
100
+
101
+ if (!SPOTIFY_CLIENT_ID || !SPOTIFY_CLIENT_SECRET || !SPOTIFY_REFRESH_TOKEN) {
102
+ throw new Error('Spotify credentials not configured');
103
+ }
104
+
105
+ // Get new access token using refresh token
106
+ const response = await fetch('https://accounts.spotify.com/api/token', {
107
+ method: 'POST',
108
+ headers: {
109
+ 'Content-Type': 'application/x-www-form-urlencoded',
110
+ Authorization: \`Basic \${Buffer.from(
111
+ \`\${SPOTIFY_CLIENT_ID}:\${SPOTIFY_CLIENT_SECRET}\`
112
+ ).toString('base64')}\`,
113
+ },
114
+ body: new URLSearchParams({
115
+ grant_type: 'refresh_token',
116
+ refresh_token: SPOTIFY_REFRESH_TOKEN,
117
+ }),
118
+ });
119
+
120
+ if (!response.ok) {
121
+ const error = await response.text();
122
+ throw new Error(\`Failed to get access token: \${error}\`);
123
+ }
124
+
125
+ const data = await response.json();
126
+ accessToken = data.access_token;
127
+ // Set expiry to 55 minutes (tokens last 1 hour)
128
+ tokenExpiry = Date.now() + 55 * 60 * 1000;
129
+
130
+ if (!accessToken) {
131
+ throw new Error('Failed to get access token');
132
+ }
133
+
134
+ return accessToken;
135
+ }
136
+
137
+ export async function GET() {
138
+ try {
139
+ const token = await getAccessToken();
140
+
141
+ // Get currently playing track
142
+ const response = await fetch(
143
+ 'https://api.spotify.com/v1/me/player/currently-playing',
144
+ {
145
+ headers: {
146
+ Authorization: \`Bearer \${token}\`,
147
+ },
148
+ }
149
+ );
150
+
151
+ if (response.status === 204) {
152
+ // No content - not playing anything
153
+ return NextResponse.json({ isPlaying: false });
154
+ }
155
+
156
+ if (!response.ok) {
157
+ return NextResponse.json({ isPlaying: false });
158
+ }
159
+
160
+ const data = await response.json();
161
+
162
+ if (!data.item) {
163
+ return NextResponse.json({ isPlaying: false });
164
+ }
165
+
166
+ // Return format expected by spotify-now-playing-card package
167
+ return NextResponse.json({
168
+ isPlaying: data.is_playing,
169
+ title: data.item.name,
170
+ artist: data.item.artists.map((a: any) => a.name).join(', '),
171
+ album: data.item.album.name,
172
+ albumImageUrl: data.item.album.images[0]?.url || data.item.album.images[1]?.url,
173
+ songUrl: data.item.external_urls.spotify,
174
+ });
175
+ } catch (error: any) {
176
+ console.error('Spotify API error:', error);
177
+ return NextResponse.json(
178
+ { error: error.message || 'Failed to fetch Spotify data' },
179
+ { status: 500 }
180
+ );
181
+ }
182
+ }
183
+ `
184
+ } else {
185
+ // Next.js Pages Router
186
+ apiCode = `import querystring from 'querystring'
187
+ import axios from 'axios'
188
+
189
+ const {
190
+ SPOTIFY_CLIENT_ID: client_id,
191
+ SPOTIFY_CLIENT_SECRET: client_secret,
192
+ SPOTIFY_REFRESH_TOKEN: refresh_token
193
+ } = process.env
194
+
195
+ const basic = Buffer.from(\`\${client_id}:\${client_secret}\`).toString('base64')
196
+ const NOW_PLAYING_ENDPOINT = 'https://api.spotify.com/v1/me/player/currently-playing'
197
+ const TOKEN_ENDPOINT = 'https://accounts.spotify.com/api/token'
198
+
199
+ const getAccessToken = async () => {
200
+ const response = await axios.post(
201
+ TOKEN_ENDPOINT,
202
+ querystring.stringify({
203
+ grant_type: 'refresh_token',
204
+ refresh_token
205
+ }),
206
+ {
207
+ headers: {
208
+ Authorization: \`Basic \${basic}\`,
209
+ 'Content-Type': 'application/x-www-form-urlencoded'
210
+ }
211
+ }
212
+ )
213
+
214
+ return response.data
215
+ }
216
+
217
+ const spotifyApi = async (req, res) => {
218
+ try {
219
+ const { access_token } = await getAccessToken()
220
+ const response = await axios.get(NOW_PLAYING_ENDPOINT, {
221
+ headers: {
222
+ Authorization: \`Bearer \${access_token}\`
223
+ }
224
+ })
225
+
226
+ if (
227
+ response.status === 204 ||
228
+ response.status > 400 ||
229
+ (response.data && response.data.currently_playing_type !== 'track')
230
+ ) {
231
+ return res.status(200).json({ isPlaying: false })
232
+ }
233
+
234
+ const data = {
235
+ isPlaying: response.data.is_playing,
236
+ title: response.data.item.name,
237
+ album: response.data.item.album.name,
238
+ artist: response.data.item.album.artists.map((artist) => artist.name).join(', '),
239
+ albumImageUrl: response.data.item.album.images[0].url,
240
+ songUrl: response.data.item.external_urls.spotify
241
+ }
242
+
243
+ res.status(200).json(data)
244
+ } catch (error) {
245
+ console.error('Spotify API error:', error)
246
+ res.status(200).json({ isPlaying: false })
247
+ }
248
+ }
249
+
250
+ export default spotifyApi
251
+ `
252
+ }
253
+
254
+ // Write API file
255
+ const fileExtension = framework === 'nextjs-app' ? 'ts' : 'js'
256
+ const apiFilePath = framework === 'nextjs-app' ? `${apiPath}.ts` : `${apiPath}.${fileExtension}`
257
+
258
+ fs.writeFileSync(apiFilePath, apiCode)
259
+ console.log(`āœ… Created API endpoint: ${apiFilePath}`)
260
+
261
+ // Update or create .env file
262
+ const envPath = '.env.local'
263
+ let envContent = ''
264
+
265
+ if (fs.existsSync(envPath)) {
266
+ envContent = fs.readFileSync(envPath, 'utf8')
267
+ }
268
+
269
+ // Check if variables already exist
270
+ if (!envContent.includes('SPOTIFY_CLIENT_ID')) {
271
+ envContent += `\n# Spotify API Credentials\n`
272
+ envContent += `SPOTIFY_CLIENT_ID=${clientId}\n`
273
+ envContent += `SPOTIFY_CLIENT_SECRET=${clientSecret}\n`
274
+ envContent += `SPOTIFY_REFRESH_TOKEN=${refreshToken}\n`
275
+ fs.writeFileSync(envPath, envContent)
276
+ console.log(`āœ… Updated ${envPath} with Spotify credentials`)
277
+ } else {
278
+ console.log(`āš ļø ${envPath} already contains Spotify credentials. Please update manually if needed.`)
279
+ }
280
+
281
+ console.log('\n✨ Setup complete!')
282
+ console.log('\nNext steps:')
283
+ console.log('1. Make sure your .env.local file is in .gitignore')
284
+ console.log('2. Import and use the component in your app:')
285
+ console.log(' import { SpotifyCard } from "spotify-now-playing-card"')
286
+ console.log(' import "spotify-now-playing-card/dist/styles.css"')
287
+ console.log('3. Use it: <SpotifyCard apiUrl="/api/spotify" />')
288
+ console.log('\n')
289
+
290
+ rl.close()
291
+ }
292
+
293
+ setup().catch(err => {
294
+ console.error('Error:', err)
295
+ rl.close()
296
+ process.exit(1)
297
+ })
298
+
@@ -1 +1 @@
1
- {"version":3,"file":"SpotifyCard.d.ts","sourceRoot":"","sources":["../src/SpotifyCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,oDAAoD;IACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED;;GAEG;AACH,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAsF3C,CAAA;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"SpotifyCard.d.ts","sourceRoot":"","sources":["../src/SpotifyCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oDAAoD;IACpD,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,oDAAoD;IACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED;;GAEG;AACH,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAsF3C,CAAA;AAED,eAAe,WAAW,CAAA"}
package/dist/index.esm.js CHANGED
@@ -3,11 +3,12 @@ import axios from 'axios';
3
3
  import { SiSpotify } from 'react-icons/si';
4
4
  import useSWR from 'swr';
5
5
 
6
+ // CSS will be imported by users: import 'spotify-now-playing-card/dist/styles.css'
6
7
  const fetcher = (url) => axios.get(url).then(res => res.data);
7
8
  /**
8
9
  * SpotifyCard - A React component to display currently playing Spotify track
9
10
  */
10
- const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spotify.com', className = '', styles = {}, showAlbum = true, notPlayingText = 'Currently not listening', refreshInterval = 30000, ...props }) => {
11
+ const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spotify.com', className = '', styles = {}, showAlbum = true, notPlayingText = 'Currently not listening', refreshInterval = 10000, ...props }) => {
11
12
  const { data, error } = useSWR(apiUrl, fetcher, {
12
13
  refreshInterval: refreshInterval,
13
14
  revalidateOnFocus: true
@@ -15,29 +16,29 @@ const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spot
15
16
  if (error) {
16
17
  console.error('SpotifyCard error:', error);
17
18
  }
19
+ // Use CSS classes by default (works without Tailwind)
20
+ // Users can override with Tailwind classes via styles prop if they want
18
21
  const defaultStyles = {
19
- container: 'text-slate-400 border border-neutral-800 rounded-lg w-full mx-5 my-2',
20
- link: 'relative flex items-center space-x-2 py-4 pl-2 transition-shadow hover:shadow-md',
21
- image: 'w-14 shadow-sm',
22
- title: 'font-bold text-md w-48 lg:w-72 truncate',
23
- artist: 'text-sm font-semibold',
24
- album: 'text-xs font-semibold w-48 lg:w-72 truncate',
25
- icon: 'absolute right-1.5 top-1.5'
22
+ container: 'spotify-card-container',
23
+ link: 'spotify-card-link',
24
+ image: 'spotify-card-image',
25
+ title: 'spotify-card-title',
26
+ artist: 'spotify-card-artist',
27
+ album: 'spotify-card-album',
28
+ icon: 'spotify-card-icon'
26
29
  };
27
30
  const mergedStyles = {
28
- container: `${defaultStyles.container} ${styles.container || ''} ${className}`,
29
- link: `${defaultStyles.link} ${styles.link || ''}`,
30
- image: `${defaultStyles.image} ${styles.image || ''}`,
31
- title: `${defaultStyles.title} ${styles.title || ''}`,
32
- artist: `${defaultStyles.artist} ${styles.artist || ''}`,
33
- album: `${defaultStyles.album} ${styles.album || ''}`,
34
- icon: `${defaultStyles.icon} ${styles.icon || ''}`
31
+ container: `${defaultStyles.container} ${styles.container || ''} ${className}`.trim(),
32
+ link: `${defaultStyles.link} ${styles.link || ''}`.trim(),
33
+ image: `${defaultStyles.image} ${styles.image || ''}`.trim(),
34
+ title: `${defaultStyles.title} ${styles.title || ''}`.trim(),
35
+ artist: `${defaultStyles.artist} ${styles.artist || ''}`.trim(),
36
+ album: `${defaultStyles.album} ${styles.album || ''}`.trim(),
37
+ icon: `${defaultStyles.icon} ${styles.icon || ''}`.trim()
35
38
  };
36
39
  const isPlaying = data?.isPlaying;
37
- const titleColor = isPlaying
38
- ? 'text-transparent bg-clip-text bg-gradient-to-r from-violet-500 via-blue-500 to-emerald-500'
39
- : '';
40
- return (jsx("div", { className: mergedStyles.container, ...props, children: jsxs("a", { target: '_blank', rel: 'noreferrer', href: isPlaying ? data?.songUrl : fallbackUrl, className: mergedStyles.link, children: [jsx("div", { className: 'w-15', children: isPlaying ? (jsx("img", { className: mergedStyles.image, src: data?.albumImageUrl, alt: data?.album || 'Album cover' })) : (jsx(SiSpotify, { size: 30, color: '#1ED760' })) }), jsxs("div", { className: 'flex-1', children: [jsx("p", { className: `${mergedStyles.title} ${titleColor}`, children: isPlaying ? data?.title : notPlayingText }), jsx("p", { className: mergedStyles.artist, children: isPlaying ? `Artist: ${data?.artist}` : 'Spotify' }), showAlbum && isPlaying && (jsxs("p", { className: mergedStyles.album, children: ["Album: ", data?.album] }))] }), isPlaying && (jsx("div", { className: mergedStyles.icon, children: jsx(SiSpotify, { size: 20, color: '#1ED760' }) }))] }) }));
40
+ const titleClass = isPlaying ? 'spotify-card-title-gradient' : '';
41
+ return (jsx("div", { className: mergedStyles.container, ...props, children: jsxs("a", { target: '_blank', rel: 'noreferrer', href: isPlaying ? data?.songUrl : fallbackUrl, className: mergedStyles.link, children: [jsx("div", { className: "spotify-card-image-container", children: isPlaying ? (jsx("img", { className: mergedStyles.image, src: data?.albumImageUrl, alt: data?.album || 'Album cover' })) : (jsx(SiSpotify, { size: 30, color: '#1ED760' })) }), jsxs("div", { className: "spotify-card-content", children: [jsx("p", { className: `${mergedStyles.title} ${titleClass}`.trim(), children: isPlaying ? data?.title : notPlayingText }), jsx("p", { className: mergedStyles.artist, children: isPlaying ? `Artist: ${data?.artist}` : 'Spotify' }), showAlbum && isPlaying && (jsxs("p", { className: mergedStyles.album, children: ["Album: ", data?.album] }))] }), isPlaying && (jsx("div", { className: mergedStyles.icon, children: jsx(SiSpotify, { size: 20, color: '#1ED760' }) }))] }) }));
41
42
  };
42
43
 
43
44
  export { SpotifyCard, SpotifyCard as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/SpotifyCard.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/SpotifyCard.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,11 +7,12 @@ var axios = require('axios');
7
7
  var si = require('react-icons/si');
8
8
  var useSWR = require('swr');
9
9
 
10
+ // CSS will be imported by users: import 'spotify-now-playing-card/dist/styles.css'
10
11
  const fetcher = (url) => axios.get(url).then(res => res.data);
11
12
  /**
12
13
  * SpotifyCard - A React component to display currently playing Spotify track
13
14
  */
14
- const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spotify.com', className = '', styles = {}, showAlbum = true, notPlayingText = 'Currently not listening', refreshInterval = 30000, ...props }) => {
15
+ const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spotify.com', className = '', styles = {}, showAlbum = true, notPlayingText = 'Currently not listening', refreshInterval = 10000, ...props }) => {
15
16
  const { data, error } = useSWR(apiUrl, fetcher, {
16
17
  refreshInterval: refreshInterval,
17
18
  revalidateOnFocus: true
@@ -19,29 +20,29 @@ const SpotifyCard = ({ apiUrl = '/api/spotify', fallbackUrl = 'https://open.spot
19
20
  if (error) {
20
21
  console.error('SpotifyCard error:', error);
21
22
  }
23
+ // Use CSS classes by default (works without Tailwind)
24
+ // Users can override with Tailwind classes via styles prop if they want
22
25
  const defaultStyles = {
23
- container: 'text-slate-400 border border-neutral-800 rounded-lg w-full mx-5 my-2',
24
- link: 'relative flex items-center space-x-2 py-4 pl-2 transition-shadow hover:shadow-md',
25
- image: 'w-14 shadow-sm',
26
- title: 'font-bold text-md w-48 lg:w-72 truncate',
27
- artist: 'text-sm font-semibold',
28
- album: 'text-xs font-semibold w-48 lg:w-72 truncate',
29
- icon: 'absolute right-1.5 top-1.5'
26
+ container: 'spotify-card-container',
27
+ link: 'spotify-card-link',
28
+ image: 'spotify-card-image',
29
+ title: 'spotify-card-title',
30
+ artist: 'spotify-card-artist',
31
+ album: 'spotify-card-album',
32
+ icon: 'spotify-card-icon'
30
33
  };
31
34
  const mergedStyles = {
32
- container: `${defaultStyles.container} ${styles.container || ''} ${className}`,
33
- link: `${defaultStyles.link} ${styles.link || ''}`,
34
- image: `${defaultStyles.image} ${styles.image || ''}`,
35
- title: `${defaultStyles.title} ${styles.title || ''}`,
36
- artist: `${defaultStyles.artist} ${styles.artist || ''}`,
37
- album: `${defaultStyles.album} ${styles.album || ''}`,
38
- icon: `${defaultStyles.icon} ${styles.icon || ''}`
35
+ container: `${defaultStyles.container} ${styles.container || ''} ${className}`.trim(),
36
+ link: `${defaultStyles.link} ${styles.link || ''}`.trim(),
37
+ image: `${defaultStyles.image} ${styles.image || ''}`.trim(),
38
+ title: `${defaultStyles.title} ${styles.title || ''}`.trim(),
39
+ artist: `${defaultStyles.artist} ${styles.artist || ''}`.trim(),
40
+ album: `${defaultStyles.album} ${styles.album || ''}`.trim(),
41
+ icon: `${defaultStyles.icon} ${styles.icon || ''}`.trim()
39
42
  };
40
43
  const isPlaying = data?.isPlaying;
41
- const titleColor = isPlaying
42
- ? 'text-transparent bg-clip-text bg-gradient-to-r from-violet-500 via-blue-500 to-emerald-500'
43
- : '';
44
- return (jsxRuntime.jsx("div", { className: mergedStyles.container, ...props, children: jsxRuntime.jsxs("a", { target: '_blank', rel: 'noreferrer', href: isPlaying ? data?.songUrl : fallbackUrl, className: mergedStyles.link, children: [jsxRuntime.jsx("div", { className: 'w-15', children: isPlaying ? (jsxRuntime.jsx("img", { className: mergedStyles.image, src: data?.albumImageUrl, alt: data?.album || 'Album cover' })) : (jsxRuntime.jsx(si.SiSpotify, { size: 30, color: '#1ED760' })) }), jsxRuntime.jsxs("div", { className: 'flex-1', children: [jsxRuntime.jsx("p", { className: `${mergedStyles.title} ${titleColor}`, children: isPlaying ? data?.title : notPlayingText }), jsxRuntime.jsx("p", { className: mergedStyles.artist, children: isPlaying ? `Artist: ${data?.artist}` : 'Spotify' }), showAlbum && isPlaying && (jsxRuntime.jsxs("p", { className: mergedStyles.album, children: ["Album: ", data?.album] }))] }), isPlaying && (jsxRuntime.jsx("div", { className: mergedStyles.icon, children: jsxRuntime.jsx(si.SiSpotify, { size: 20, color: '#1ED760' }) }))] }) }));
44
+ const titleClass = isPlaying ? 'spotify-card-title-gradient' : '';
45
+ return (jsxRuntime.jsx("div", { className: mergedStyles.container, ...props, children: jsxRuntime.jsxs("a", { target: '_blank', rel: 'noreferrer', href: isPlaying ? data?.songUrl : fallbackUrl, className: mergedStyles.link, children: [jsxRuntime.jsx("div", { className: "spotify-card-image-container", children: isPlaying ? (jsxRuntime.jsx("img", { className: mergedStyles.image, src: data?.albumImageUrl, alt: data?.album || 'Album cover' })) : (jsxRuntime.jsx(si.SiSpotify, { size: 30, color: '#1ED760' })) }), jsxRuntime.jsxs("div", { className: "spotify-card-content", children: [jsxRuntime.jsx("p", { className: `${mergedStyles.title} ${titleClass}`.trim(), children: isPlaying ? data?.title : notPlayingText }), jsxRuntime.jsx("p", { className: mergedStyles.artist, children: isPlaying ? `Artist: ${data?.artist}` : 'Spotify' }), showAlbum && isPlaying && (jsxRuntime.jsxs("p", { className: mergedStyles.album, children: ["Album: ", data?.album] }))] }), isPlaying && (jsxRuntime.jsx("div", { className: mergedStyles.icon, children: jsxRuntime.jsx(si.SiSpotify, { size: 20, color: '#1ED760' }) }))] }) }));
45
46
  };
46
47
 
47
48
  exports.SpotifyCard = SpotifyCard;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/SpotifyCard.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs","SiSpotify"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/SpotifyCard.tsx"],"sourcesContent":[null],"names":["_jsx","_jsxs","SiSpotify"],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /* Default styles for spotify-now-playing-card */
2
+ .spotify-card-container {
3
+ color: #94a3b8; /* slate-400 */
4
+ border: 1px solid #262626; /* neutral-800 */
5
+ border-radius: 0.5rem;
6
+ width: 100%;
7
+ margin: 0.5rem 1.25rem;
8
+ }
9
+
10
+ .spotify-card-link {
11
+ position: relative;
12
+ display: flex;
13
+ align-items: center;
14
+ gap: 0.5rem;
15
+ padding: 1rem 0.5rem;
16
+ transition: box-shadow 0.2s;
17
+ text-decoration: none;
18
+ color: inherit;
19
+ }
20
+
21
+ .spotify-card-link:hover {
22
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
23
+ }
24
+
25
+ .spotify-card-image-container {
26
+ width: 3.5rem;
27
+ flex-shrink: 0;
28
+ }
29
+
30
+ .spotify-card-image {
31
+ width: 3.5rem;
32
+ height: 3.5rem;
33
+ object-fit: cover;
34
+ border-radius: 0.25rem;
35
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
36
+ }
37
+
38
+ .spotify-card-content {
39
+ flex: 1;
40
+ min-width: 0;
41
+ }
42
+
43
+ .spotify-card-title {
44
+ font-weight: 700;
45
+ font-size: 1rem;
46
+ width: 12rem;
47
+ overflow: hidden;
48
+ text-overflow: ellipsis;
49
+ white-space: nowrap;
50
+ margin: 0;
51
+ line-height: 1.5;
52
+ }
53
+
54
+ @media (min-width: 1024px) {
55
+ .spotify-card-title {
56
+ width: 18rem;
57
+ }
58
+ }
59
+
60
+ .spotify-card-title-gradient {
61
+ background: linear-gradient(to right, #8b5cf6, #3b82f6, #10b981);
62
+ -webkit-background-clip: text;
63
+ background-clip: text;
64
+ -webkit-text-fill-color: transparent;
65
+ color: transparent;
66
+ }
67
+
68
+ .spotify-card-artist {
69
+ font-size: 0.875rem;
70
+ font-weight: 600;
71
+ margin: 0.25rem 0 0 0;
72
+ line-height: 1.5;
73
+ color: #94a3b8;
74
+ }
75
+
76
+ .spotify-card-album {
77
+ font-size: 0.75rem;
78
+ font-weight: 600;
79
+ width: 12rem;
80
+ overflow: hidden;
81
+ text-overflow: ellipsis;
82
+ white-space: nowrap;
83
+ margin: 0.25rem 0 0 0;
84
+ line-height: 1.5;
85
+ color: #94a3b8;
86
+ }
87
+
88
+ @media (min-width: 1024px) {
89
+ .spotify-card-album {
90
+ width: 18rem;
91
+ }
92
+ }
93
+
94
+ .spotify-card-icon {
95
+ position: absolute;
96
+ right: 0.375rem;
97
+ top: 0.375rem;
98
+ }
99
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spotify-now-playing-card",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "description": "A beautiful React component to display your currently playing Spotify track",
6
6
  "main": "dist/index.js",
@@ -8,12 +8,11 @@
8
8
  "types": "dist/index.d.ts",
9
9
  "files": [
10
10
  "dist",
11
+ "bin",
11
12
  "README.md"
12
13
  ],
13
- "scripts": {
14
- "build": "rollup -c",
15
- "dev": "rollup -c -w",
16
- "prepublishOnly": "npm run build"
14
+ "bin": {
15
+ "spotify-card-setup": "bin/setup.js"
17
16
  },
18
17
  "keywords": [
19
18
  "spotify",
@@ -28,7 +27,7 @@
28
27
  "license": "MIT",
29
28
  "repository": {
30
29
  "type": "git",
31
- "url": "https://github.com/yourusername/spotify-now-playing-card.git"
30
+ "url": "git+https://github.com/basskibo/spotify-now-playing-card.git"
32
31
  },
33
32
  "peerDependencies": {
34
33
  "react": ">=16.8.0",
@@ -48,7 +47,13 @@
48
47
  "react": "^18.2.0",
49
48
  "react-dom": "^18.2.0",
50
49
  "rollup": "^4.6.1",
50
+ "rollup-plugin-copy": "^3.5.0",
51
51
  "tslib": "^2.8.1",
52
52
  "typescript": "^5.3.3"
53
+ },
54
+ "scripts": {
55
+ "build": "rollup -c",
56
+ "dev": "rollup -c -w",
57
+ "setup": "node bin/setup.js"
53
58
  }
54
- }
59
+ }