为什么我的铬扩展是在最大化镀铬时在上载图像时崩溃的?

问题描述 投票:0回答:1
├── .git/ ├── .gitignore ├── .npmrc ├── README.md ├── package.json ├── src/ │ ├── app.d.ts │ ├── app.html │ ├── lib/ │ │ ├── components/ │ │ │ ├── Button.svelte │ │ │ ├── CaptionEditor.svelte │ │ │ ├── HashTagsEditor.svelte │ │ │ ├── ImagePreview.svelte │ │ │ ├── ImageUploader.svelte │ │ │ ├── PostsTab.svelte │ │ │ ├── ScheduledTab.svelte │ │ │ ├── StatsTab.svelte │ │ │ └── Tabs.svelte │ │ └── index.ts │ └── routes/ │ ├── +layout.ts │ └── +page.svelte ├── static/ │ ├── favicon.png │ ├── manifest.json │ └── popup.css ├── svelte.config.js ├── tsconfig.json └── vite.config.ts
我正在使用
pnpm

。当我拖放图像时,还要涉及显示预览时,即使在我单击扩展名并右键单击检查该情况时,也能够上传文件并向我展示预览时,也可以显示预览。文件大小不是拖放的问题,我已经上传了一个

1KB
文件,这是我的
1.2MB

文件。{

manifest.json
这是我的
    "manifest_version":3,
    "name":"instoma",
    "version":"0.0.1",
    "description": "A simple instagram automation tool",
    "action":{
        "default_popup":"index.html"
    },
    "permissions":[
        "storage",
        "unlimitedStorage"
    ],
    "web_accessible_resources": [
        {
            "resources": [
                "*.png",
                "*.jpg",
                "*.jpeg"
            ],
            "matches": [
                "<all_urls>"
            ]
        }
    ],
    "content_security_policy": {
        "extension_pages": "script-src 'self'; object-src 'self'"
    }
}
文件。
popup.css

这是我的
body {
    width: 450px;
    height: 600px;
    margin: 0;
    padding: 0;
    overflow: auto;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* Add this to ensure the extension doesn't collapse */
html, body {
    min-height: 400px;
    max-height: 600px;
}

/* Fix for Chrome fullscreen mode */
@media (min-height: 800px) {
    body {
        height: 600px;
        overflow: hidden;
    }
}

/* Add these styles to improve stability */
.plugin-container {
    height: 100%;
    max-height: 580px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.tab-content {
    overflow: auto;
    max-height: calc(100% - 100px);
    flex: 1;
}

/* Add this to prevent memory issues with images */
img {
    max-width: 100%;
    height: auto;
    object-fit: contain;
}
文件。

+page.svelte

这是我的

<svelte:head> <link rel="stylesheet" href="popup.css"/> </svelte:head> <script> import { onMount } from 'svelte'; import Tabs from '$lib/components/Tabs.svelte'; import PostsTab from '$lib/components/PostsTab.svelte'; import ScheduledTab from '$lib/components/ScheduledTab.svelte'; import StatsTab from '$lib/components/StatsTab.svelte'; let activeTab = $state('POSTS'); let error = $state(null); const tabs = [ { id: 'POSTS', label: 'POSTS' }, { id: 'SCHEDULED', label: 'SCHEDULED' }, { id: 'STATS', label: 'STATS' } ]; // Add global error handler onMount(() => { window.addEventListener('error', (event) => { console.error('Global error:', event.error); error = event.error?.message || 'Unknown error occurred'; return false; }); window.addEventListener('unhandledrejection', (event) => { console.error('Unhandled promise rejection:', event.reason); error = event.reason?.message || 'Promise rejection occurred'; return false; }); }); </script> <main> <div class="plugin-container"> {#if error} <div class="error-container"> <h3>Something went wrong</h3> <p>{error}</p> <button on:click={() => error = null}>Dismiss</button> </div> {:else} <Tabs {tabs} bind:activeTab /> <p class="active-tab-display">The active tab is {activeTab}</p> <div class="tab-content"> {#if activeTab === 'POSTS'} <PostsTab /> {:else if activeTab === 'SCHEDULED'} <ScheduledTab /> {:else if activeTab === 'STATS'} <StatsTab /> {/if} </div> {/if} </div> </main> <style> main { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 1rem; max-width: 100%; margin: 0 auto; box-sizing: border-box; height: 100%; } .plugin-container { background-color: #fff; border-radius: 16px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); overflow: hidden; height: 100%; display: flex; flex-direction: column; } .tab-content { flex: 1; overflow: auto; padding: 1rem; } .active-tab-display { color: peru; font-size: 1.5rem; margin: 0.5rem 0; text-align: center; background-color: #f0f0f0; padding: 0.5rem; border-radius: 8px; } .error-container { padding: 2rem; text-align: center; color: #d32f2f; } .error-container button { margin-top: 1rem; padding: 0.5rem 1rem; background-color: #f0f0f0; border: none; border-radius: 4px; cursor: pointer; } </style>
文件。
ImageUploader.svelte

这是我的
<script lang="ts"> import { createEventDispatcher } from "svelte"; let isDragging = $state(false); let fileInput: HTMLInputElement; const dispatch = createEventDispatcher<{ upload: { url: string }; }>(); function processFile(file: File) { // Check file type if (!file.type.match('image.*')) return; // Check file size (5MB limit) if (file.size > 5 * 1024 * 1024) { alert(`File ${file.name} is too large. Maximum size is 5MB.`); return; } // Use a simple approach that's less likely to cause issues const reader = new FileReader(); reader.onload = (e) => { if (typeof e.target?.result !== 'string') return; dispatch("upload", { url: e.target.result }); }; reader.onerror = () => { console.error("Error reading file"); }; reader.readAsDataURL(file); } function handleFileUpload(event: Event) { try { const input = event.target as HTMLInputElement; const files = input.files; if (!files || files.length === 0) return; if (files.length > 3) { alert("You can only upload up to 3 images at a time."); return; } for (const file of files) { processFile(file); } // Reset the input to allow selecting the same file again input.value = ''; } catch (error) { console.error("Error in file upload:", error); } } function handleDragOver(event: DragEvent) { event.preventDefault(); isDragging = true; } function handleDragLeave() { isDragging = false; } function handleDrop(event: DragEvent) { event.preventDefault(); isDragging = false; try { const files = event.dataTransfer?.files; if(!files || files.length === 0) return; if (files.length > 3) { alert("You can only upload up to 3 images at a time."); return; } for (const file of files) { processFile(file); } } catch (error) { console.error("Error in drop handling:", error); } } function handleClick() { if (fileInput) { fileInput.click(); } } </script> <div class="uploader {isDragging ? 'dragging' : ''}" role="button" aria-label="Upload images" on:click={handleClick} on:dragover={handleDragOver} on:dragleave={handleDragLeave} on:drop={handleDrop} > <input type="file" hidden bind:this={fileInput} on:change={handleFileUpload} accept=".jpg, .jpeg, .png" multiple /> <div class="upload-content"> <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> <polyline points="17 8 12 3 7 8"></polyline> <line x1="12" y1="3" x2="12" y2="15"></line> </svg> <p>Drag & drop images here or <span>browse</span></p> <small>Supports JPG, JPEG, PNG (max 3 images)</small> </div> </div> <style> .uploader { border: 2px dashed #ccc; border-radius: 12px; padding: 2rem; text-align: center; cursor: pointer; transition: all 0.2s ease; } .uploader:hover { border-color: #007bff; } .uploader.dragging { border-color: #007bff; background-color: rgba(0, 123, 255, 0.05); transform: scale(1.01); } .upload-content { display: flex; flex-direction: column; align-items: center; gap: 1rem; color: #666; } span { color: #007bff; font-weight: 500; } </style>

文件。
ImagePreview.svelte
我已经禁用了所有其他扩展。我在这里缺少什么样的样式引起冲突或问题?

将扩展程序作为独立选项卡或侧边栏操作而不是弹出窗口运行:

<script lang="ts">
  import CaptionEditor from "./CaptionEditor.svelte";
  import HashTagsEditor from "./HashTagsEditor.svelte";
  import Button from "./Button.svelte";
  import { CircleX } from '@lucide/svelte';
  import { createEventDispatcher } from 'svelte';

  interface PostResult {
    success: boolean | null;
    message: string;
  }
  const { image, index } = $props();
  const dispatch = createEventDispatcher();

  let showCaption = $state(false);
  let showHashtags = $state(false);
  let isPosting = $state(false);
  let postResult = $state<PostResult>({ success: null, message: '' });

  async function shareImage() {
    try {
      isPosting = true;
      postResult = { success: null, message: 'Posting to Instagram...' };
      
      const response = await fetch('http://localhost:8188/api/instagram/post', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          imageUrl: image.url,
          caption: image.caption,
          hashtags: image.hashtags
        })
      });
      
      const result = await response.json();
      
      if (result.success) {
        postResult = { success: true, message: 'Posted successfully to Instagram!' };
      } else {
        postResult = { success: false, message: `Error: ${result.message}` };
        console.error('Error posting to Instagram:', result.message);
        console.log("-----");
        console.log(postResult);
      }
    } catch (error) {
      console.error('Error sharing image:', error);
      postResult = { success: false, message: `Error: ${error.message}` };
      console.log("*********");
      console.log(postResult);
    } finally {
      isPosting = false;
      // Clear result message after 5 seconds
      setTimeout(() => {
        postResult = { success: null, message: '' };
      }, 60000);
    }
  }
  function handleRemove() {
    dispatch('remove', index);
  }
</script>

<div class="image-preview">
  <div class="image-container">
    <img src={image.url} alt="Demo post preview" />
    <button class="close-button" on:click|stopPropagation={handleRemove} aria-label="Remove image">
      <CircleX size={24} />
    </button>
  </div>

  <div class="content">
    <h3>Image {index + 1}</h3>
    <div class="actions">
      <button on:click={shareImage} class="action-button" disabled={isPosting}>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="24"
          height="24"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path>
          <polyline points="16 6 12 2 8 6"></polyline>
          <line x1="12" y1="2" x2="12" y2="15"></line>
        </svg>
      </button>
      <button
        on:click={() => (showCaption = !showCaption)}
        class="action-button"
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="24"
          height="24"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M12 20h9"></path>
          <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"
          ></path>
        </svg>
      </button>
      <button
        on:click={() => (showHashtags = !showHashtags)}
        class="action-button"
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="24"
          height="24"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"
          ></path>
          <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
          ></path>
        </svg>
      </button>
    </div>
    
    {#if postResult.message}
      <div class="post-result {postResult.success ? 'success' : postResult.success === false ? 'error' : 'info'}">
        {postResult.message}
      </div>
    {/if}
    
    {#if showCaption}
      <CaptionEditor {image} />
    {/if}

    {#if showHashtags}
      <HashTagsEditor {image} />
    {/if}
  </div>
</div>

<style>
  .image-preview {
    background-color: white;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
    display: flex;
    flex-direction: column;
    padding: 1rem;
  }
  
  .image-container {
    position: relative;
    width: 100%;
    padding-top: 100%; /* 1:1 Aspect Ratio */
    overflow: hidden;
  }
  
  img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  
  .close-button {
    position: absolute;
    top: 8px;
    right: 8px;
    background: rgba(255, 255, 255, 0.7);
    border: none;
    border-radius: 50%;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;
    padding: 0;
    z-index: 10;
  }
  
  .close-button:hover {
    background: rgba(255, 255, 255, 0.9);
    transform: scale(1.1);
  }
  
  .close-button:hover :global(svg) {
    color: #ff3333;
  }
  
  .content {
    padding: 1rem;
  }
  
  h3 {
    margin: 0 0 1rem 0;
    font-size: 1.2rem;
    color: #262626;
  }
  
  .actions {
    display: flex;
    gap: 0.75rem;
    margin-bottom: 1rem;
  }
  
  .action-button {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.5rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s;
  }
  
  .action-button:hover {
    background-color: #f0f0f0;
  }
  
  .action-button[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
  }
  
  .post-result {
    padding: 0.75rem;
    border-radius: 8px;
    margin-bottom: 1rem;
    font-size: 0.9rem;
  }
  
  .post-result.success {
    background-color: #e3f7e8;
    color: #2e7d32;
  }
  
  .post-result.error {
    background-color: #fdecea;
    color: #d32f2f;
  }
  
  .post-result.info {
    background-color: #e8f4fd;
    color: #0277bd;
  }
</style>

使用背景脚本在弹出窗口关闭之前持续存在图像:

"action": {
  "default_popup": "index.html"
},
"sidebar_action": {
  "default_page": "index.html"
}

aadd逻辑以保存并从
"background": {
  "service_worker": "background.js"
}
.

中获取图像。

chrome.storage.local
google-chrome-extension svelte sveltekit svelte-component
1个回答
0
投票
确保您有存储许可:

<script> import { onMount } from "svelte"; let imageUrl = ""; // Handle file selection function handleFileUpload(event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = () => { imageUrl = reader.result; chrome.storage.local.set({ uploadedImage: imageUrl }); }; reader.readAsDataURL(file); } } // Retrieve image on mount onMount(() => { chrome.storage.local.get("uploadedImage", (data) => { if (data.uploadedImage) { imageUrl = data.uploadedImage; } }); }); </script> <input type="file" accept="image/*" on:change={handleFileUpload} /> {#if imageUrl} <img src={imageUrl} alt="Uploaded Preview" style="max-width: 100%;" /> {/if}

manifest.json


最新问题
© www.soinside.com 2019 - 2025. All rights reserved.