@nuraly/lumenjs 0.1.2 → 0.1.4
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 +76 -235
- package/dist/auth/config.d.ts +23 -0
- package/dist/auth/config.js +115 -0
- package/dist/auth/guard.d.ts +12 -0
- package/dist/auth/guard.js +28 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/middleware.d.ts +23 -0
- package/dist/auth/middleware.js +89 -0
- package/dist/auth/native-auth.d.ts +73 -0
- package/dist/auth/native-auth.js +293 -0
- package/dist/auth/oidc-client.d.ts +17 -0
- package/dist/auth/oidc-client.js +123 -0
- package/dist/auth/providers/google.d.ts +23 -0
- package/dist/auth/providers/google.js +25 -0
- package/dist/auth/providers/index.d.ts +2 -0
- package/dist/auth/providers/index.js +1 -0
- package/dist/auth/routes/login.d.ts +8 -0
- package/dist/auth/routes/login.js +98 -0
- package/dist/auth/routes/logout.d.ts +4 -0
- package/dist/auth/routes/logout.js +79 -0
- package/dist/auth/routes/oidc-callback.d.ts +3 -0
- package/dist/auth/routes/oidc-callback.js +70 -0
- package/dist/auth/routes/password.d.ts +5 -0
- package/dist/auth/routes/password.js +149 -0
- package/dist/auth/routes/signup.d.ts +3 -0
- package/dist/auth/routes/signup.js +81 -0
- package/dist/auth/routes/token.d.ts +4 -0
- package/dist/auth/routes/token.js +70 -0
- package/dist/auth/routes/utils.d.ts +7 -0
- package/dist/auth/routes/utils.js +35 -0
- package/dist/auth/routes/verify.d.ts +3 -0
- package/dist/auth/routes/verify.js +26 -0
- package/dist/auth/routes.d.ts +8 -0
- package/dist/auth/routes.js +110 -0
- package/dist/auth/session.d.ts +8 -0
- package/dist/auth/session.js +54 -0
- package/dist/auth/token.d.ts +33 -0
- package/dist/auth/token.js +90 -0
- package/dist/auth/types.d.ts +156 -0
- package/dist/auth/types.js +2 -0
- package/dist/build/build-client.d.ts +15 -0
- package/dist/build/build-client.js +45 -0
- package/dist/build/build-prerender.d.ts +11 -0
- package/dist/build/build-prerender.js +159 -0
- package/dist/build/build-server.d.ts +17 -0
- package/dist/build/build-server.js +98 -0
- package/dist/build/build.js +52 -120
- package/dist/build/scan.d.ts +19 -0
- package/dist/build/scan.js +77 -6
- package/dist/build/serve-api.js +8 -2
- package/dist/build/serve-loaders.d.ts +4 -2
- package/dist/build/serve-loaders.js +128 -10
- package/dist/build/serve-ssr.js +38 -11
- package/dist/build/serve-static.js +3 -3
- package/dist/build/serve.js +229 -14
- package/dist/cli.js +37 -6
- package/dist/communication/encryption.d.ts +35 -0
- package/dist/communication/encryption.js +90 -0
- package/dist/communication/handlers/context.d.ts +27 -0
- package/dist/communication/handlers/context.js +1 -0
- package/dist/communication/handlers/conversation.d.ts +24 -0
- package/dist/communication/handlers/conversation.js +113 -0
- package/dist/communication/handlers/file-upload.d.ts +17 -0
- package/dist/communication/handlers/file-upload.js +62 -0
- package/dist/communication/handlers/messaging.d.ts +30 -0
- package/dist/communication/handlers/messaging.js +237 -0
- package/dist/communication/handlers/presence.d.ts +15 -0
- package/dist/communication/handlers/presence.js +76 -0
- package/dist/communication/handlers.d.ts +5 -0
- package/dist/communication/handlers.js +5 -0
- package/dist/communication/index.d.ts +9 -0
- package/dist/communication/index.js +7 -0
- package/dist/communication/link-preview.d.ts +18 -0
- package/dist/communication/link-preview.js +115 -0
- package/dist/communication/schema.d.ts +10 -0
- package/dist/communication/schema.js +101 -0
- package/dist/communication/server.d.ts +86 -0
- package/dist/communication/server.js +212 -0
- package/dist/communication/signaling.d.ts +43 -0
- package/dist/communication/signaling.js +271 -0
- package/dist/communication/store.d.ts +71 -0
- package/dist/communication/store.js +289 -0
- package/dist/communication/types.d.ts +454 -0
- package/dist/communication/types.js +1 -0
- package/dist/create.d.ts +1 -0
- package/dist/create.js +55 -0
- package/dist/db/auto-migrate.d.ts +3 -0
- package/dist/db/auto-migrate.js +100 -0
- package/dist/db/client.d.ts +3 -0
- package/dist/db/client.js +18 -0
- package/dist/db/context.d.ts +2 -0
- package/dist/db/context.js +9 -0
- package/dist/db/index.d.ts +23 -0
- package/dist/db/index.js +258 -0
- package/dist/db/seed.d.ts +12 -0
- package/dist/db/seed.js +88 -0
- package/dist/db/table.d.ts +10 -0
- package/dist/db/table.js +12 -0
- package/dist/dev-server/config.d.ts +14 -0
- package/dist/dev-server/config.js +26 -9
- package/dist/dev-server/index-html.d.ts +3 -0
- package/dist/dev-server/index-html.js +18 -6
- package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
- package/dist/dev-server/nuralyui-aliases.js +115 -94
- package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
- package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
- package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
- package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
- package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
- package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
- package/dist/dev-server/plugins/vite-plugin-loaders.d.ts +0 -1
- package/dist/dev-server/plugins/vite-plugin-loaders.js +311 -42
- package/dist/dev-server/plugins/vite-plugin-routes.js +18 -6
- package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
- package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
- package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
- package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
- package/dist/dev-server/server.js +128 -12
- package/dist/dev-server/ssr-render.d.ts +2 -1
- package/dist/dev-server/ssr-render.js +107 -48
- package/dist/editor/ai/backend.d.ts +20 -0
- package/dist/editor/ai/backend.js +104 -0
- package/dist/editor/ai/claude-code-client.d.ts +20 -0
- package/dist/editor/ai/claude-code-client.js +145 -0
- package/dist/editor/ai/opencode-client.d.ts +14 -0
- package/dist/editor/ai/opencode-client.js +125 -0
- package/dist/editor/ai/snapshot-store.d.ts +22 -0
- package/dist/editor/ai/snapshot-store.js +35 -0
- package/dist/editor/ai/types.d.ts +30 -0
- package/dist/editor/ai/types.js +136 -0
- package/dist/editor/ai-chat-panel.d.ts +13 -0
- package/dist/editor/ai-chat-panel.js +587 -0
- package/dist/editor/ai-markdown.d.ts +10 -0
- package/dist/editor/ai-markdown.js +70 -0
- package/dist/editor/ai-project-panel.d.ts +11 -0
- package/dist/editor/ai-project-panel.js +332 -0
- package/dist/editor/ast-modification.d.ts +11 -0
- package/dist/editor/ast-modification.js +1 -0
- package/dist/editor/ast-service.d.ts +30 -0
- package/dist/editor/ast-service.js +180 -0
- package/dist/editor/css-rules.d.ts +54 -0
- package/dist/editor/css-rules.js +423 -0
- package/dist/editor/editor-api-client.d.ts +51 -0
- package/dist/editor/editor-api-client.js +162 -0
- package/dist/editor/editor-bridge.d.ts +1 -0
- package/dist/editor/editor-bridge.js +17 -8
- package/dist/editor/editor-toolbar.d.ts +14 -0
- package/dist/editor/editor-toolbar.js +115 -0
- package/dist/editor/file-editor.d.ts +9 -0
- package/dist/editor/file-editor.js +236 -0
- package/dist/editor/file-service.d.ts +16 -0
- package/dist/editor/file-service.js +52 -0
- package/dist/editor/i18n-key-gen.d.ts +1 -0
- package/dist/editor/i18n-key-gen.js +7 -0
- package/dist/editor/inline-text-edit.d.ts +5 -0
- package/dist/editor/inline-text-edit.js +173 -92
- package/dist/editor/overlay-events.d.ts +5 -0
- package/dist/editor/overlay-events.js +364 -0
- package/dist/editor/overlay-hmr.d.ts +2 -0
- package/dist/editor/overlay-hmr.js +75 -0
- package/dist/editor/overlay-selection.d.ts +29 -0
- package/dist/editor/overlay-selection.js +148 -0
- package/dist/editor/overlay-utils.d.ts +12 -0
- package/dist/editor/overlay-utils.js +59 -0
- package/dist/editor/properties-panel-persist.d.ts +14 -0
- package/dist/editor/properties-panel-persist.js +70 -0
- package/dist/editor/properties-panel-rows.d.ts +10 -0
- package/dist/editor/properties-panel-rows.js +349 -0
- package/dist/editor/properties-panel-styles.d.ts +4 -0
- package/dist/editor/properties-panel-styles.js +174 -0
- package/dist/editor/properties-panel.d.ts +4 -0
- package/dist/editor/properties-panel.js +148 -0
- package/dist/editor/property-registry.d.ts +16 -0
- package/dist/editor/property-registry.js +303 -0
- package/dist/editor/standalone-file-panel.d.ts +0 -0
- package/dist/editor/standalone-file-panel.js +1 -0
- package/dist/editor/standalone-overlay-dom.d.ts +0 -0
- package/dist/editor/standalone-overlay-dom.js +1 -0
- package/dist/editor/standalone-overlay-styles.d.ts +0 -0
- package/dist/editor/standalone-overlay-styles.js +1 -0
- package/dist/editor/standalone-overlay.d.ts +1 -0
- package/dist/editor/standalone-overlay.js +76 -0
- package/dist/editor/syntax-highlighter.d.ts +4 -0
- package/dist/editor/syntax-highlighter.js +81 -0
- package/dist/editor/text-toolbar.d.ts +11 -0
- package/dist/editor/text-toolbar.js +327 -0
- package/dist/editor/toolbar-styles.d.ts +4 -0
- package/dist/editor/toolbar-styles.js +198 -0
- package/dist/email/index.d.ts +32 -0
- package/dist/email/index.js +154 -0
- package/dist/email/providers/resend.d.ts +2 -0
- package/dist/email/providers/resend.js +24 -0
- package/dist/email/providers/sendgrid.d.ts +2 -0
- package/dist/email/providers/sendgrid.js +31 -0
- package/dist/email/providers/smtp.d.ts +13 -0
- package/dist/email/providers/smtp.js +125 -0
- package/dist/email/template-engine.d.ts +18 -0
- package/dist/email/template-engine.js +116 -0
- package/dist/email/templates/base.d.ts +9 -0
- package/dist/email/templates/base.js +65 -0
- package/dist/email/templates/password-reset.d.ts +5 -0
- package/dist/email/templates/password-reset.js +15 -0
- package/dist/email/templates/verify-email.d.ts +5 -0
- package/dist/email/templates/verify-email.js +15 -0
- package/dist/email/templates/welcome.d.ts +5 -0
- package/dist/email/templates/welcome.js +13 -0
- package/dist/email/types.d.ts +49 -0
- package/dist/email/types.js +1 -0
- package/dist/llms/generate.d.ts +46 -0
- package/dist/llms/generate.js +185 -0
- package/dist/permissions/guard.d.ts +28 -0
- package/dist/permissions/guard.js +30 -0
- package/dist/permissions/index.d.ts +6 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions/service.d.ts +80 -0
- package/dist/permissions/service.js +210 -0
- package/dist/permissions/tables.d.ts +5 -0
- package/dist/permissions/tables.js +68 -0
- package/dist/permissions/types.d.ts +33 -0
- package/dist/permissions/types.js +1 -0
- package/dist/runtime/app-shell.js +163 -0
- package/dist/runtime/auth.d.ts +10 -0
- package/dist/runtime/auth.js +30 -0
- package/dist/runtime/communication.d.ts +137 -0
- package/dist/runtime/communication.js +228 -0
- package/dist/runtime/error-boundary.d.ts +23 -0
- package/dist/runtime/error-boundary.js +120 -0
- package/dist/runtime/i18n.d.ts +6 -1
- package/dist/runtime/i18n.js +42 -21
- package/dist/runtime/router-data.d.ts +5 -0
- package/dist/runtime/router-data.js +121 -16
- package/dist/runtime/router-hydration.js +25 -0
- package/dist/runtime/router.d.ts +21 -1
- package/dist/runtime/router.js +221 -39
- package/dist/runtime/socket-client.d.ts +2 -0
- package/dist/runtime/socket-client.js +30 -0
- package/dist/runtime/webrtc.d.ts +47 -0
- package/dist/runtime/webrtc.js +178 -0
- package/dist/shared/graceful-shutdown.d.ts +8 -0
- package/dist/shared/graceful-shutdown.js +36 -0
- package/dist/shared/health.d.ts +8 -0
- package/dist/shared/health.js +25 -0
- package/dist/shared/llms-txt.d.ts +31 -0
- package/dist/shared/llms-txt.js +85 -0
- package/dist/shared/logger.d.ts +32 -0
- package/dist/shared/logger.js +93 -0
- package/dist/shared/meta.d.ts +27 -0
- package/dist/shared/meta.js +71 -0
- package/dist/shared/middleware-runner.d.ts +9 -0
- package/dist/shared/middleware-runner.js +29 -0
- package/dist/shared/rate-limit.d.ts +18 -0
- package/dist/shared/rate-limit.js +71 -0
- package/dist/shared/request-id.d.ts +5 -0
- package/dist/shared/request-id.js +18 -0
- package/dist/shared/route-matching.js +16 -1
- package/dist/shared/security-headers.d.ts +18 -0
- package/dist/shared/security-headers.js +38 -0
- package/dist/shared/socket-io-setup.d.ts +11 -0
- package/dist/shared/socket-io-setup.js +51 -0
- package/dist/shared/types.d.ts +16 -0
- package/dist/shared/utils.d.ts +37 -7
- package/dist/shared/utils.js +175 -26
- package/dist/storage/adapters/local.d.ts +44 -0
- package/dist/storage/adapters/local.js +85 -0
- package/dist/storage/adapters/s3.d.ts +32 -0
- package/dist/storage/adapters/s3.js +116 -0
- package/dist/storage/adapters/types.d.ts +53 -0
- package/dist/storage/adapters/types.js +1 -0
- package/dist/storage/index.d.ts +76 -0
- package/dist/storage/index.js +83 -0
- package/package.json +20 -1
- package/templates/blog/api/posts.ts +6 -0
- package/templates/blog/data/migrations/001_init.sql +13 -0
- package/templates/blog/lumenjs.config.ts +3 -0
- package/templates/blog/package.json +14 -0
- package/templates/blog/pages/_layout.ts +25 -0
- package/templates/blog/pages/index.ts +65 -0
- package/templates/blog/pages/posts/[slug].ts +60 -0
- package/templates/blog/pages/tag/[tag].ts +44 -0
- package/templates/dashboard/api/stats.ts +10 -0
- package/templates/dashboard/data/migrations/001_init.sql +13 -0
- package/templates/dashboard/lumenjs.config.ts +3 -0
- package/templates/dashboard/package.json +14 -0
- package/templates/dashboard/pages/_layout.ts +25 -0
- package/templates/dashboard/pages/index.ts +72 -0
- package/templates/dashboard/pages/settings/index.ts +29 -0
- package/templates/default/lumenjs.config.ts +3 -0
- package/templates/default/package.json +14 -0
- package/templates/default/pages/index.ts +24 -0
- package/templates/social/api/posts/[id].ts +14 -0
- package/templates/social/api/posts.ts +11 -0
- package/templates/social/api/profile/[username].ts +10 -0
- package/templates/social/api/upload.ts +19 -0
- package/templates/social/data/migrations/001_init.sql +78 -0
- package/templates/social/data/migrations/002_add_image_url.sql +1 -0
- package/templates/social/data/migrations/003_auth.sql +7 -0
- package/templates/social/docs/architecture.md +76 -0
- package/templates/social/docs/components.md +100 -0
- package/templates/social/docs/data.md +89 -0
- package/templates/social/docs/pages.md +96 -0
- package/templates/social/docs/theming.md +52 -0
- package/templates/social/lib/media.ts +130 -0
- package/templates/social/lumenjs.auth.ts +21 -0
- package/templates/social/lumenjs.config.ts +3 -0
- package/templates/social/package.json +5 -0
- package/templates/social/pages/_layout.ts +239 -0
- package/templates/social/pages/apps/[id].ts +173 -0
- package/templates/social/pages/apps/index.ts +116 -0
- package/templates/social/pages/auth/login.ts +92 -0
- package/templates/social/pages/bookmarks.ts +57 -0
- package/templates/social/pages/explore.ts +73 -0
- package/templates/social/pages/index.ts +351 -0
- package/templates/social/pages/messages.ts +298 -0
- package/templates/social/pages/new.ts +77 -0
- package/templates/social/pages/notifications.ts +73 -0
- package/templates/social/pages/post/[id].ts +124 -0
- package/templates/social/pages/profile/[username].ts +100 -0
- package/templates/social/pages/settings/accessibility.ts +153 -0
- package/templates/social/pages/settings/account.ts +260 -0
- package/templates/social/pages/settings/help.ts +141 -0
- package/templates/social/pages/settings/language.ts +103 -0
- package/templates/social/pages/settings/privacy.ts +183 -0
- package/templates/social/pages/settings/security.ts +133 -0
- package/templates/social/pages/settings.ts +185 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
|
+
|
|
3
|
+
const svg = {
|
|
4
|
+
comment: html`<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>`,
|
|
5
|
+
repost: html`<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 014-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 01-4 4H3"/></svg>`,
|
|
6
|
+
heart: html`<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"/></svg>`,
|
|
7
|
+
share: html`<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 12v8a2 2 0 002 2h12a2 2 0 002-2v-8"/><polyline points="16 6 12 2 8 6"/><line x1="12" y1="2" x2="12" y2="15"/></svg>`,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export async function loader() {
|
|
11
|
+
return {
|
|
12
|
+
stories: [
|
|
13
|
+
{ username: 'aymen', name: 'You', initials: 'AL', color: '#7c3aed', avatar: 'https://avatars.githubusercontent.com/u/3775924?v=4', isYou: true, image: 'https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=400&h=700&fit=crop', caption: 'Late night coding session' },
|
|
14
|
+
{ username: 'alex_design', name: 'Alex', initials: 'AR', color: '#e44d26', image: 'https://images.unsplash.com/photo-1561070791-2526d30994b5?w=400&h=700&fit=crop', caption: 'New design system preview' },
|
|
15
|
+
{ username: 'emma_data', name: 'Emma', initials: 'EW', color: '#3572a5', image: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=400&h=700&fit=crop', caption: 'Data viz experiments' },
|
|
16
|
+
{ username: 'mike_ops', name: 'Mike', initials: 'MJ', color: '#22c55e', image: 'https://images.unsplash.com/photo-1618401471353-b98afee0b2eb?w=400&h=700&fit=crop', caption: 'Deploying to prod' },
|
|
17
|
+
{ username: 'lisa_pm', name: 'Lisa', initials: 'LP', color: '#a855f7', image: 'https://images.unsplash.com/photo-1517245386807-bb43f82c33c4?w=400&h=700&fit=crop', caption: 'Team offsite recap' },
|
|
18
|
+
{ username: 'tom_arch', name: 'Tom', initials: 'TB', color: '#ef4444', image: 'https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?w=400&h=700&fit=crop', caption: 'Architecture deep dive' },
|
|
19
|
+
{ username: 'nina_sec', name: 'Nina', initials: 'NP', color: '#f59e0b', image: 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?w=400&h=700&fit=crop', caption: 'Security audit walkthrough' },
|
|
20
|
+
],
|
|
21
|
+
widgets: [
|
|
22
|
+
{ type: 'poll', position: 2, username: 'alex_design', display_name: 'Alex Rivera', initials: 'AR', color: '#e44d26', time: '3h', question: 'What framework do you use most in 2025?', options: [{ label: 'React', pct: 45 }, { label: 'LumenJS', pct: 35 }, { label: 'Vue', pct: 15 }, { label: 'Other', pct: 5 }], votes: 142 },
|
|
23
|
+
{ type: 'event', position: 4, username: 'mike_ops', display_name: 'Mike Johnson', initials: 'MJ', color: '#22c55e', time: '5h', title: 'DevOps Meetup 2025', date: 'Apr 5, 2025 · 6:00 PM', location: 'Online · Zoom', attendees: 48 },
|
|
24
|
+
{ type: 'job', position: 6, username: 'emma_data', display_name: 'Emma Williams', initials: 'EW', color: '#3572a5', time: '8h', company: 'DataFlow', role: 'Senior ML Engineer', loc: 'Remote', salary: '$150k - $200k' },
|
|
25
|
+
],
|
|
26
|
+
posts: [
|
|
27
|
+
{ id: 1, username: 'aymen', display_name: 'Aymen Labidi', initials: 'AL', color: '#7c3aed', avatar: 'https://avatars.githubusercontent.com/u/3775924?v=4', content: 'Just shipped a new feature using LumenJS! The file-based routing makes everything so clean. No more route config files. Every page is just a .ts file in the pages/ directory. Dynamic routes use [param] syntax. Layouts nest automatically with _layout.ts. Server loaders run before render and pass data as properties. SSR works out of the box with Lit SSR. This is the future of web development.', media: { type: 'image', url: 'https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=600&h=340&fit=crop' }, likes: 42, comments: 5, reposts: 12, time: '2h' },
|
|
28
|
+
{ id: 2, username: 'alex_design', display_name: 'Alex Rivera', initials: 'AR', color: '#e44d26', content: 'Working on a new design system. The key insight after 6 months: consistency beats creativity when building at scale. Every component should feel like it belongs. We started with 40 one-off components and consolidated down to 12 primitives that compose into everything we need. The trick is establishing clear constraints early — spacing scale, color tokens, typography ramp — then letting the system do the heavy lifting.', likes: 38, comments: 3, reposts: 8, time: '4h' },
|
|
29
|
+
{ id: 3, username: 'emma_data', display_name: 'Emma Williams', initials: 'EW', color: '#3572a5', content: 'Trained a new model on customer feedback data. Accuracy went from 78% to 94% just by cleaning the input data. No architecture changes needed. The biggest wins: removing duplicates, fixing encoding issues, normalizing date formats, and filtering out bot-generated entries. Spent 3 days on data prep vs 1 day on model tuning. Garbage in, garbage out is the most underrated lesson in ML.', media: { type: 'image', url: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=600&h=340&fit=crop' }, likes: 67, comments: 8, reposts: 21, time: '6h' },
|
|
30
|
+
{ id: 4, username: 'mike_ops', display_name: 'Mike Johnson', initials: 'MJ', color: '#22c55e', content: 'Migrated our entire CI/CD pipeline from Jenkins to GitHub Actions. Results: 40% faster builds, half the YAML config, and our team actually understands the pipeline now. The reusable workflow feature is a game changer — we have one workflow that all 12 services share.', media: { type: 'video', url: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm', poster: 'https://images.unsplash.com/photo-1618401471353-b98afee0b2eb?w=600&h=340&fit=crop' }, likes: 29, comments: 4, reposts: 6, time: '1d' },
|
|
31
|
+
{ id: 5, username: 'aymen', display_name: 'Aymen Labidi', initials: 'AL', color: '#7c3aed', avatar: 'https://avatars.githubusercontent.com/u/3775924?v=4', content: 'Hot take: TypeScript\'s type system is a programming language in itself. Conditional types, mapped types, template literal types, recursive types... you can implement a full type-level parser if you want to. And I love every bit of it. The DX improvement from strict types is worth every extra line of type annotation.', likes: 85, comments: 12, reposts: 15, time: '1d' },
|
|
32
|
+
{ id: 6, username: 'emma_data', display_name: 'Emma Williams', initials: 'EW', color: '#3572a5', content: 'PSA: If you\'re using pandas, try polars. I switched a production pipeline and it\'s not just faster — the lazy evaluation API is more intuitive, the error messages are clearer, and it handles larger-than-memory datasets natively. Here\'s a benchmark: 2GB CSV, pandas took 45s to groupby-aggregate, polars did it in 3s.', media: { type: 'image', url: 'https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?w=600&h=340&fit=crop' }, likes: 93, comments: 15, reposts: 34, time: '3d' },
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class PageIndex extends LitElement {
|
|
38
|
+
static properties = { loaderData: { type: Object }, _storyOpen: { state: true }, _storyIdx: { state: true }, _storyProgress: { state: true } };
|
|
39
|
+
loaderData: any = {};
|
|
40
|
+
_storyOpen: boolean = false;
|
|
41
|
+
_storyIdx: number = 0;
|
|
42
|
+
_storyProgress: number = 0;
|
|
43
|
+
_storyTimer: any = null;
|
|
44
|
+
private _shell?: HTMLElement;
|
|
45
|
+
|
|
46
|
+
connectedCallback() {
|
|
47
|
+
super.connectedCallback();
|
|
48
|
+
requestAnimationFrame(() => {
|
|
49
|
+
const shell = this.closest('layout-root')?.shadowRoot?.querySelector('.shell') as HTMLElement;
|
|
50
|
+
if (shell) { shell.classList.add('show-right'); this._shell = shell; }
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
disconnectedCallback() {
|
|
55
|
+
super.disconnectedCallback();
|
|
56
|
+
if (this._shell) { this._shell.classList.remove('show-right'); this._shell = undefined; }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
static styles = css`
|
|
61
|
+
:host { display: block; }
|
|
62
|
+
|
|
63
|
+
/* Stories bar */
|
|
64
|
+
.stories { display: flex; gap: 6px; padding: 12px 12px; border-bottom: 1px solid var(--border); overflow-x: auto; scrollbar-width: none; }
|
|
65
|
+
.stories::-webkit-scrollbar { display: none; }
|
|
66
|
+
.story { display: flex; flex-direction: column; align-items: center; gap: 6px; cursor: pointer; flex-shrink: 0; width: 64px; }
|
|
67
|
+
.story-ring { width: 56px; height: 80px; border-radius: 10px; overflow: visible; border: 1px solid var(--border); }
|
|
68
|
+
.story-ring.you { }
|
|
69
|
+
.story-avatar { width: 56px; height: 80px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 700; color: #fff; overflow: hidden; }
|
|
70
|
+
.story-avatar img { width: 100%; height: 100%; object-fit: cover; }
|
|
71
|
+
.story-name { font-size: 11px; color: var(--text-secondary); max-width: 60px; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
72
|
+
.story-plus { position: absolute; bottom: -4px; left: 50%; transform: translateX(-50%); width: 18px; height: 18px; border-radius: 50%; background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center; border: 2px solid #fff; }
|
|
73
|
+
.story-plus svg { width: 10px; height: 10px; }
|
|
74
|
+
.story-avatar-wrap { position: relative; }
|
|
75
|
+
@keyframes pulse-ring { 0%,100% { opacity: 1; } 50% { opacity: 0.6; } }
|
|
76
|
+
|
|
77
|
+
/* Story/Reel viewer */
|
|
78
|
+
.story-viewer { position: fixed; inset: 0; z-index: 200; background: #000; display: flex; align-items: center; justify-content: center; }
|
|
79
|
+
.story-viewer-inner { position: relative; width: 100%; max-width: 420px; height: 100%; max-height: 100vh; }
|
|
80
|
+
.story-image { width: 100%; height: 100%; object-fit: cover; }
|
|
81
|
+
.story-progress { position: absolute; top: 8px; left: 8px; right: 8px; display: flex; gap: 4px; z-index: 2; }
|
|
82
|
+
.story-bar { flex: 1; height: 3px; background: rgba(255,255,255,0.3); border-radius: 2px; overflow: hidden; }
|
|
83
|
+
.story-bar-fill { height: 100%; background: var(--bg); border-radius: 2px; transition: width 0.1s linear; }
|
|
84
|
+
.story-top { position: absolute; top: 18px; left: 12px; right: 12px; display: flex; align-items: center; gap: 8px; z-index: 2; }
|
|
85
|
+
.story-top-avatar { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: #fff; border: 2px solid #fff; overflow: hidden; }
|
|
86
|
+
.story-top-avatar img { width: 100%; height: 100%; object-fit: cover; }
|
|
87
|
+
.story-top-name { color: #fff; font-size: 14px; font-weight: 700; }
|
|
88
|
+
.story-top-time { color: rgba(255,255,255,0.7); font-size: 12px; }
|
|
89
|
+
.story-top-live { background: #e53935; color: #fff; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px; }
|
|
90
|
+
.story-close { margin-left: auto; width: 32px; height: 32px; border: none; background: none; color: #fff; cursor: pointer; display: flex; align-items: center; justify-content: center; }
|
|
91
|
+
.story-caption { position: absolute; bottom: 0; left: 0; right: 0; padding: 40px 16px 24px; background: linear-gradient(transparent, rgba(0,0,0,0.7)); z-index: 2; }
|
|
92
|
+
.story-caption-text { color: #fff; font-size: 15px; line-height: 1.4; }
|
|
93
|
+
.story-nav { position: absolute; inset: 0; display: flex; z-index: 1; }
|
|
94
|
+
.story-nav-prev, .story-nav-next { flex: 1; cursor: pointer; }
|
|
95
|
+
|
|
96
|
+
/* Widget cards */
|
|
97
|
+
.widget-card { border-bottom: 1px solid var(--border); padding: 12px 16px; }
|
|
98
|
+
.widget-header { display: flex; gap: 10px; margin-bottom: 10px; }
|
|
99
|
+
.widget-avatar { width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; color: #fff; flex-shrink: 0; }
|
|
100
|
+
.widget-meta { flex: 1; }
|
|
101
|
+
.widget-name { font-weight: 700; font-size: 15px; }
|
|
102
|
+
.widget-handle { color: var(--text-secondary); font-size: 14px; }
|
|
103
|
+
.widget-badge { font-size: 11px; color: var(--accent); background: rgba(124,58,237,0.1); padding: 2px 8px; border-radius: 4px; font-weight: 600; margin-left: 6px; }
|
|
104
|
+
|
|
105
|
+
/* Poll widget */
|
|
106
|
+
.poll-question { font-size: 15px; font-weight: 600; margin-bottom: 8px; }
|
|
107
|
+
.poll-option { margin-bottom: 6px; }
|
|
108
|
+
.poll-bar { height: 28px; border-radius: 6px; background: var(--input-bg); position: relative; overflow: hidden; display: flex; align-items: center; padding: 0 10px; }
|
|
109
|
+
.poll-fill { position: absolute; left: 0; top: 0; bottom: 0; background: rgba(124,58,237,0.15); border-radius: 6px; }
|
|
110
|
+
.poll-label { position: relative; font-size: 13px; flex: 1; }
|
|
111
|
+
.poll-pct { position: relative; font-size: 13px; font-weight: 700; }
|
|
112
|
+
.poll-total { font-size: 12px; color: var(--text-secondary); margin-top: 6px; }
|
|
113
|
+
|
|
114
|
+
/* Event widget */
|
|
115
|
+
.event-card { background: var(--bg-secondary); border-radius: 12px; padding: 14px; }
|
|
116
|
+
.event-title { font-size: 16px; font-weight: 700; }
|
|
117
|
+
.event-detail { font-size: 13px; color: var(--text-secondary); margin-top: 4px; display: flex; align-items: center; gap: 6px; }
|
|
118
|
+
.event-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; }
|
|
119
|
+
.event-attendees { font-size: 12px; color: var(--text-secondary); }
|
|
120
|
+
.event-btn { padding: 6px 16px; border-radius: 9999px; border: 1px solid var(--accent); color: var(--accent); background: var(--bg); font-size: 13px; font-weight: 600; cursor: pointer; }
|
|
121
|
+
.event-btn:hover { background: rgba(124,58,237,0.1); }
|
|
122
|
+
|
|
123
|
+
/* Job widget */
|
|
124
|
+
.job-card { background: var(--bg-secondary); border-radius: 12px; padding: 14px; }
|
|
125
|
+
.job-company { font-size: 13px; color: var(--text-secondary); }
|
|
126
|
+
.job-role { font-size: 16px; font-weight: 700; margin-top: 2px; }
|
|
127
|
+
.job-details { display: flex; gap: 12px; margin-top: 6px; font-size: 13px; color: var(--text-secondary); }
|
|
128
|
+
.job-btn { margin-top: 10px; padding: 6px 16px; border-radius: 9999px; background: var(--accent); color: #fff; border: none; font-size: 13px; font-weight: 600; cursor: pointer; }
|
|
129
|
+
.job-btn:hover { background: var(--accent-hover); }
|
|
130
|
+
|
|
131
|
+
.post { display: flex; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border); cursor: pointer; text-decoration: none; color: inherit; }
|
|
132
|
+
.post:hover { background: var(--bg-secondary); }
|
|
133
|
+
.post-avatar { width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; color: #fff; flex-shrink: 0; overflow: hidden; }
|
|
134
|
+
.post-avatar img { width: 100%; height: 100%; object-fit: cover; }
|
|
135
|
+
.post-media { margin-top: 8px; border-radius: 12px; overflow: hidden; aspect-ratio: 16/9; background: var(--input-bg); }
|
|
136
|
+
.post-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
137
|
+
.post-media video { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
138
|
+
.post-media .live-badge { position: absolute; top: 8px; left: 8px; background: #e53935; color: #fff; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px; }
|
|
139
|
+
.post-media-wrap { position: relative; height: 100%; }
|
|
140
|
+
.post-body { flex: 1; min-width: 0; }
|
|
141
|
+
.post-header { display: flex; align-items: baseline; gap: 4px; }
|
|
142
|
+
.post-name { font-weight: 700; font-size: 15px; }
|
|
143
|
+
.post-handle { color: var(--text-secondary); font-size: 14px; }
|
|
144
|
+
.post-dot { color: var(--text-secondary); font-size: 14px; }
|
|
145
|
+
.post-time { color: var(--text-secondary); font-size: 14px; }
|
|
146
|
+
.post-content { margin-top: 2px; line-height: 1.4; font-size: 15px; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
|
|
147
|
+
.post-content.expanded { -webkit-line-clamp: unset; }
|
|
148
|
+
.see-more { color: var(--accent); font-size: 14px; border: none; background: none; cursor: pointer; padding: 2px 0; font-weight: 500; }
|
|
149
|
+
.see-more:hover { text-decoration: underline; }
|
|
150
|
+
.post-actions { display: flex; gap: 0; margin-top: 8px; margin-left: -8px; }
|
|
151
|
+
.action { display: flex; align-items: center; gap: 4px; color: var(--text-secondary); font-size: 13px; border: none; background: none; cursor: pointer; padding: 4px 8px; border-radius: 9999px; min-width: 60px; }
|
|
152
|
+
.action:hover { color: var(--accent); background: rgba(29,155,240,0.1); }
|
|
153
|
+
.action.repost:hover { color: #00ba7c; background: rgba(0,186,124,0.1); }
|
|
154
|
+
.action.heart:hover { color: #f91880; background: rgba(249,24,128,0.1); }
|
|
155
|
+
`;
|
|
156
|
+
|
|
157
|
+
_openStory(idx: number) {
|
|
158
|
+
this._storyIdx = idx;
|
|
159
|
+
this._storyOpen = true;
|
|
160
|
+
this._storyProgress = 0;
|
|
161
|
+
this._startStoryTimer();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_closeStory() {
|
|
165
|
+
this._storyOpen = false;
|
|
166
|
+
if (this._storyTimer) { clearInterval(this._storyTimer); this._storyTimer = null; }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
_startStoryTimer() {
|
|
170
|
+
if (this._storyTimer) clearInterval(this._storyTimer);
|
|
171
|
+
this._storyProgress = 0;
|
|
172
|
+
this._storyTimer = setInterval(() => {
|
|
173
|
+
this._storyProgress += 2;
|
|
174
|
+
if (this._storyProgress >= 100) this._nextStory();
|
|
175
|
+
}, 100);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
_nextStory() {
|
|
179
|
+
const stories = this.loaderData.stories || [];
|
|
180
|
+
if (this._storyIdx < stories.length - 1) {
|
|
181
|
+
this._storyIdx++;
|
|
182
|
+
this._startStoryTimer();
|
|
183
|
+
} else {
|
|
184
|
+
this._closeStory();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
_prevStory() {
|
|
189
|
+
if (this._storyIdx > 0) {
|
|
190
|
+
this._storyIdx--;
|
|
191
|
+
this._startStoryTimer();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
_renderWidget(w: any) {
|
|
196
|
+
if (w.type === 'poll') return html`
|
|
197
|
+
<div class="widget-card">
|
|
198
|
+
<div class="widget-header">
|
|
199
|
+
<div class="widget-avatar" style="background:${w.color}">${w.initials}</div>
|
|
200
|
+
<div class="widget-meta">
|
|
201
|
+
<span class="widget-name">${w.display_name}</span>
|
|
202
|
+
<span class="widget-handle">· ${w.time}</span>
|
|
203
|
+
<span class="widget-badge">Poll</span>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
<div class="poll-question">${w.question}</div>
|
|
207
|
+
${w.options.map((o: any) => html`
|
|
208
|
+
<div class="poll-option">
|
|
209
|
+
<div class="poll-bar"><div class="poll-fill" style="width:${o.pct}%"></div><span class="poll-label">${o.label}</span><span class="poll-pct">${o.pct}%</span></div>
|
|
210
|
+
</div>
|
|
211
|
+
`)}
|
|
212
|
+
<div class="poll-total">${w.votes} votes</div>
|
|
213
|
+
</div>`;
|
|
214
|
+
if (w.type === 'event') return html`
|
|
215
|
+
<div class="widget-card">
|
|
216
|
+
<div class="widget-header">
|
|
217
|
+
<div class="widget-avatar" style="background:${w.color}">${w.initials}</div>
|
|
218
|
+
<div class="widget-meta">
|
|
219
|
+
<span class="widget-name">${w.display_name}</span>
|
|
220
|
+
<span class="widget-handle">· ${w.time}</span>
|
|
221
|
+
<span class="widget-badge">Event</span>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
<div class="event-card">
|
|
225
|
+
<div class="event-title">${w.title}</div>
|
|
226
|
+
<div class="event-detail">${w.date}</div>
|
|
227
|
+
<div class="event-detail">${w.location}</div>
|
|
228
|
+
<div class="event-footer">
|
|
229
|
+
<span class="event-attendees">${w.attendees} attending</span>
|
|
230
|
+
<button class="event-btn">Interested</button>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
</div>`;
|
|
234
|
+
if (w.type === 'job') return html`
|
|
235
|
+
<div class="widget-card">
|
|
236
|
+
<div class="widget-header">
|
|
237
|
+
<div class="widget-avatar" style="background:${w.color}">${w.initials}</div>
|
|
238
|
+
<div class="widget-meta">
|
|
239
|
+
<span class="widget-name">${w.display_name}</span>
|
|
240
|
+
<span class="widget-handle">· ${w.time}</span>
|
|
241
|
+
<span class="widget-badge">Job</span>
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
<div class="job-card">
|
|
245
|
+
<div class="job-company">${w.company}</div>
|
|
246
|
+
<div class="job-role">${w.role}</div>
|
|
247
|
+
<div class="job-details"><span>${w.loc}</span><span>${w.salary}</span></div>
|
|
248
|
+
<button class="job-btn">Apply</button>
|
|
249
|
+
</div>
|
|
250
|
+
</div>`;
|
|
251
|
+
return '';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
render() {
|
|
255
|
+
const posts = this.loaderData.posts || [];
|
|
256
|
+
const stories = this.loaderData.stories || [];
|
|
257
|
+
const widgets = this.loaderData.widgets || [];
|
|
258
|
+
|
|
259
|
+
// Merge posts and widgets by position
|
|
260
|
+
const feed: any[] = [];
|
|
261
|
+
let postIdx = 0;
|
|
262
|
+
for (let i = 0; postIdx < posts.length; i++) {
|
|
263
|
+
const w = widgets.find((w: any) => w.position === i);
|
|
264
|
+
if (w) { feed.push({ _widget: true, ...w }); }
|
|
265
|
+
if (postIdx < posts.length) { feed.push(posts[postIdx]); postIdx++; }
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return html`
|
|
269
|
+
<div class="stories">
|
|
270
|
+
${stories.map((s: any, i: number) => html`
|
|
271
|
+
<div class="story" @click=${() => this._openStory(i)}>
|
|
272
|
+
<div class="story-ring ${s.isYou ? 'you' : ''}">
|
|
273
|
+
<div class="story-avatar-wrap">
|
|
274
|
+
<div class="story-avatar">
|
|
275
|
+
<img src="${s.image}" alt="">
|
|
276
|
+
</div>
|
|
277
|
+
${s.isYou ? html`<div class="story-plus"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></div>` : ''}
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
<span class="story-name">${s.name}</span>
|
|
281
|
+
</div>
|
|
282
|
+
`)}
|
|
283
|
+
</div>
|
|
284
|
+
${feed.map((item: any) => item._widget
|
|
285
|
+
? this._renderWidget(item)
|
|
286
|
+
: html`
|
|
287
|
+
<a class="post" href="/post/${item.id}">
|
|
288
|
+
<div class="post-avatar" style="background:${item.color}">${item.avatar ? html`<img src="${item.avatar}" alt="">` : item.initials}</div>
|
|
289
|
+
<div class="post-body">
|
|
290
|
+
<div class="post-header">
|
|
291
|
+
<span class="post-name">${item.display_name}</span>
|
|
292
|
+
<span class="post-handle">@${item.username}</span>
|
|
293
|
+
<span class="post-dot">·</span>
|
|
294
|
+
<span class="post-time">${item.time}</span>
|
|
295
|
+
</div>
|
|
296
|
+
<div class="post-content ${item.id === 1 ? '' : 'expanded'}" id="content-${item.id}">${item.content}</div>
|
|
297
|
+
${item.id === 1 ? html`<button class="see-more" @click=${(e: Event) => { e.preventDefault(); e.stopPropagation(); const el = this.shadowRoot?.getElementById('content-1'); if (el) { el.classList.toggle('expanded'); (e.target as HTMLElement).textContent = el.classList.contains('expanded') ? 'Show less' : 'See more'; }}}>See more</button>` : ''}
|
|
298
|
+
${item.media ? html`
|
|
299
|
+
<div class="post-media">
|
|
300
|
+
<div class="post-media-wrap">
|
|
301
|
+
${item.media.type === 'video' ? html`
|
|
302
|
+
<video src="${item.media.url}" poster="${item.media.poster || ''}" controls preload="none"></video>
|
|
303
|
+
` : html`
|
|
304
|
+
<img src="${item.media.url}" alt="" loading="lazy">
|
|
305
|
+
`}
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
` : ''}
|
|
309
|
+
<div class="post-actions">
|
|
310
|
+
<button class="action">${svg.comment} ${item.comments}</button>
|
|
311
|
+
<button class="action repost">${svg.repost} ${item.reposts}</button>
|
|
312
|
+
<button class="action heart">${svg.heart} ${item.likes}</button>
|
|
313
|
+
<button class="action">${svg.share}</button>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
</a>
|
|
317
|
+
`)}
|
|
318
|
+
${this._storyOpen ? html`
|
|
319
|
+
<div class="story-viewer">
|
|
320
|
+
<div class="story-viewer-inner">
|
|
321
|
+
<img class="story-image" src="${stories[this._storyIdx]?.image}" alt="">
|
|
322
|
+
<div class="story-progress">
|
|
323
|
+
${stories.map((_: any, i: number) => html`
|
|
324
|
+
<div class="story-bar">
|
|
325
|
+
<div class="story-bar-fill" style="width:${i < this._storyIdx ? 100 : i === this._storyIdx ? this._storyProgress : 0}%"></div>
|
|
326
|
+
</div>
|
|
327
|
+
`)}
|
|
328
|
+
</div>
|
|
329
|
+
<div class="story-top">
|
|
330
|
+
<div class="story-top-avatar" style="background:${stories[this._storyIdx]?.color}">
|
|
331
|
+
${stories[this._storyIdx]?.avatar ? html`<img src="${stories[this._storyIdx]?.avatar}" alt="">` : stories[this._storyIdx]?.initials}
|
|
332
|
+
</div>
|
|
333
|
+
<span class="story-top-name">${stories[this._storyIdx]?.name}</span>
|
|
334
|
+
<span class="story-top-time">5h</span>
|
|
335
|
+
<button class="story-close" @click=${() => this._closeStory()}>
|
|
336
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
337
|
+
</button>
|
|
338
|
+
</div>
|
|
339
|
+
<div class="story-caption">
|
|
340
|
+
<div class="story-caption-text">${stories[this._storyIdx]?.caption}</div>
|
|
341
|
+
</div>
|
|
342
|
+
<div class="story-nav">
|
|
343
|
+
<div class="story-nav-prev" @click=${() => this._prevStory()}></div>
|
|
344
|
+
<div class="story-nav-next" @click=${() => this._nextStory()}></div>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
` : ''}
|
|
349
|
+
`;
|
|
350
|
+
}
|
|
351
|
+
}
|