보조바퀴(크랙 기억력 보조)

크랙 기억력 보조용 메모장

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         보조바퀴(크랙 기억력 보조)
// @namespace    https://crack.wrtn.ai
// @version      1.9
// @description  크랙 기억력 보조용 메모장
// @author       바보륍부이
// @license      MIT
// @match        https://crack.wrtn.ai/u/*/c/*
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  let textKey = `wrtn_custom_text_${location.pathname}`;
  const panelKey = 'wrtn_custom_panel';

  const savedPanelState = JSON.parse(localStorage.getItem(panelKey) || '{}');
  let isMinimized = savedPanelState.minimized || false;

  const panel = document.createElement('div');
  panel.style.position = 'fixed';
  panel.style.top = savedPanelState.top || '100px';
  panel.style.left = savedPanelState.left || '10px';
  panel.style.width = savedPanelState.width || '600px';
  panel.style.height = savedPanelState.height || '500px';
  panel.style.backgroundColor = '#1a1a1a';
  panel.style.padding = '0';
  panel.style.borderRadius = '10px';
  panel.style.zIndex = '9999';
  panel.style.color = '#fff';
  panel.style.fontFamily = 'sans-serif';
  panel.style.boxShadow = '0 4px 10px rgba(0,0,0,0.3)';
  panel.style.resize = 'both';
  panel.style.overflow = 'hidden';
  panel.style.display = 'flex';
  panel.style.flexDirection = 'column';

  const dragHeader = document.createElement('div');
  dragHeader.style.backgroundColor = '#333';
  dragHeader.style.padding = '8px 10px';
  dragHeader.style.borderRadius = '10px 10px 0 0';
  dragHeader.style.cursor = 'move';
  dragHeader.style.userSelect = 'none';
  dragHeader.style.fontSize = '12px';
  dragHeader.style.fontWeight = 'bold';
  dragHeader.style.borderBottom = '1px solid #444';
  dragHeader.style.flexShrink = '0';
  dragHeader.textContent = '📝 보조바퀴-캐챗 기억력 보조 메모장 (Ctrl+엔터로 빠른 입력 가능)';

  const helpIcon = document.createElement('div');
  helpIcon.textContent = '❓';
  helpIcon.title = '요약은 캐즘 등 다른 프로그램을 활용해주세요\n직접 메모해도 됩니다\n다른 방으로 이동하는 등 URL이 바뀌면 갱신 버튼을 눌러주세요\n최상단을 더블클릭하면 최소화 됩니다';
  helpIcon.style.position = 'absolute';
  helpIcon.style.top = '5px';
  helpIcon.style.right = '10px';
  helpIcon.style.cursor = 'help';
  helpIcon.style.fontSize = '14px';
  dragHeader.appendChild(helpIcon);

  const content = document.createElement('div');
  content.style.padding = '10px';
  content.style.flex = '1';
  content.style.overflow = 'auto';
  content.style.display = 'flex';
  content.style.flexDirection = 'column';

  const input = document.createElement('textarea');
  input.rows = 50;
  input.placeholder = '추가할 내용 입력';
  input.style.width = '100%';
  input.style.flex = '1';
  input.style.padding = '8px';
  input.style.borderRadius = '5px';
  input.style.border = '1px solid #444';
  input.style.backgroundColor = '#2a2a2a';
  input.style.color = '#fff';
  input.style.resize = 'none';
  input.style.minHeight = '200px';

  const controlRow = document.createElement('div');
  controlRow.style.display = 'flex';
  controlRow.style.alignItems = 'center';
  controlRow.style.gap = '8px';
  controlRow.style.padding = '10px';
  controlRow.style.backgroundColor = '#222';
  controlRow.style.borderTop = '1px solid #444';
  controlRow.style.borderRadius = '0 0 10px 10px';
  controlRow.style.flexShrink = '0';

  const button = document.createElement('button');
  button.textContent = '텍스트 추가';
  button.style.flex = '1';
  button.style.padding = '8px';
  button.style.border = 'none';
  button.style.borderRadius = '5px';
  button.style.backgroundColor = '#4caf50';
  button.style.color = '#fff';
  button.style.cursor = 'pointer';

  const refreshButton = document.createElement('button');
  refreshButton.textContent = '🔄 갱신';
  refreshButton.style.flex = '1';
  refreshButton.style.padding = '8px';
  refreshButton.style.border = 'none';
  refreshButton.style.borderRadius = '5px';
  refreshButton.style.backgroundColor = '#555';
  refreshButton.style.color = '#fff';
  refreshButton.style.cursor = 'pointer';

  const countDisplay = document.createElement('div');
  countDisplay.style.marginLeft = 'auto';
  countDisplay.style.fontSize = '12px';

  const loadTextFromStorage = () => {
    textKey = `wrtn_custom_text_${location.pathname}`;
    const savedText = localStorage.getItem(textKey);
    input.value = savedText || '';
    countDisplay.textContent = `총 ${input.value.length}글자`;
  };

  loadTextFromStorage();

  refreshButton.addEventListener('click', loadTextFromStorage);

  const toggleMinimize = () => {
    isMinimized = !isMinimized;
    if (isMinimized) {
      content.style.display = 'none';
      controlRow.style.display = 'none';
      panel.style.height = 'auto';
      dragHeader.style.borderRadius = '10px';
      dragHeader.style.borderBottom = 'none';
    } else {
      content.style.display = 'flex';
      controlRow.style.display = 'flex';
      panel.style.height = savedPanelState.height || '500px';
      dragHeader.style.borderRadius = '10px 10px 0 0';
      dragHeader.style.borderBottom = '1px solid #444';
    }
    const currentState = JSON.parse(localStorage.getItem(panelKey) || '{}');
    currentState.minimized = isMinimized;
    localStorage.setItem(panelKey, JSON.stringify(currentState));
  };

  if (isMinimized) toggleMinimize();
  dragHeader.addEventListener('dblclick', toggleMinimize);

  const appendToTextarea = () => {
    const newText = input.value.trim();
    if (!newText) return;
    const textarea = document.querySelector('textarea[placeholder*="메시지 보내기"]');
    if (!textarea) {
      alert("textarea를 찾을 수 없습니다.");
      return;
    }
    const setter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
    setter?.call(textarea, textarea.value + '\n' + newText);
    textarea.dispatchEvent(new Event('input', { bubbles: true }));
    localStorage.setItem(textKey, input.value);
  };

  window.addEventListener('keydown', (e) => {
    if (e.key === 'Enter' && e.ctrlKey) appendToTextarea();
  });

  button.addEventListener('click', appendToTextarea);
  input.addEventListener('input', () => {
    localStorage.setItem(textKey, input.value);
    countDisplay.textContent = `총 ${input.value.length}글자`;
  });

  let offsetX, offsetY, dragging = false;
  dragHeader.addEventListener('mousedown', (e) => {
    dragging = true;
    offsetX = e.clientX - panel.offsetLeft;
    offsetY = e.clientY - panel.offsetTop;
    document.body.style.userSelect = 'none';
    e.preventDefault();
  });

  document.addEventListener('mousemove', (e) => {
    if (!dragging) return;
    panel.style.left = `${e.clientX - offsetX}px`;
    panel.style.top = `${e.clientY - offsetY}px`;
  });

  document.addEventListener('mouseup', () => {
    if (!dragging) return;
    dragging = false;
    document.body.style.userSelect = '';
    const currentState = JSON.parse(localStorage.getItem(panelKey) || '{}');
    currentState.top = panel.style.top;
    currentState.left = panel.style.left;
    currentState.width = panel.style.width;
    currentState.height = panel.style.height;
    localStorage.setItem(panelKey, JSON.stringify(currentState));
  });

  new ResizeObserver(() => {
    const rect = panel.getBoundingClientRect();
    const currentState = JSON.parse(localStorage.getItem(panelKey) || '{}');
    currentState.top = `${rect.top}px`;
    currentState.left = `${rect.left}px`;
    currentState.width = `${rect.width}px`;
    currentState.height = `${rect.height}px`;
    localStorage.setItem(panelKey, JSON.stringify(currentState));
  }).observe(panel);

  controlRow.appendChild(button);
  controlRow.appendChild(refreshButton);
  controlRow.appendChild(countDisplay);
  content.appendChild(input);
  panel.appendChild(dragHeader);
  panel.appendChild(content);
  panel.appendChild(controlRow);
  document.body.appendChild(panel);
})();