junkerstock
 画像アイデア (10個版)04 

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Random Mix Generator v2.1</title>
<style>
/* ベーススタイル */
body {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Kaku Gothic ProN", "Hiragino Sans", Arial, sans-serif;
padding: 20px;
background-color: #f4f6f9;
color: #333;
height: 100vh;
box-sizing: border-box;
overflow: hidden;
}

/* メインコンテナ(左右均等分割) */
.dashboard-container {
display: grid;
grid-template-columns: 1fr 1fr; /* 1:1 分割 */
gap: 20px;
max-width: 1400px;
margin: 0 auto;
height: calc(100vh - 40px);
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
overflow: hidden;
}

/* 共通パネルスタイル */
.panel {
padding: 20px;
display: flex;
flex-direction: column;
overflow: hidden;
}

/* 左パネル(設定エリア) */
.left-panel {
background-color: #fafbfc;
border-right: 1px solid #e1e4e8;
gap: 10px;
}

/* 3列レイアウト用のヘッダーとエリア */
.columns-header {
display: flex;
gap: 10px;
font-weight: bold;
color: #555;
text-align: center;
}
.columns-header div {
flex: 1;
padding: 5px;
background: #eef2f7;
border-radius: 4px;
font-size: 0.9em;
}

.columns-container {
display: flex;
gap: 10px;
flex-grow: 1;
min-height: 0;
}

.text-column {
flex: 1;
display: flex;
flex-direction: column;
}

/* テキストエリア */
textarea.word-list {
flex-grow: 1;
width: 100%;
resize: none;
border: 1px solid #ddd;
border-radius: 6px;
padding: 8px;
font-size: 0.9em;
line-height: 1.4;
box-sizing: border-box;
background-color: #fff;
}
textarea.word-list:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 2px rgba(102,126,234,0.1);
}

/* 保存ボタン */
.save-btn {
width: 100%;
padding: 10px;
font-size: 0.95em;
font-weight: bold;
color: #fff;
background-color: #6c757d;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background 0.2s;
}
.save-btn:hover { background-color: #5a6268; }
.save-btn.saved { background-color: #28a745; }

/* 右パネル(結果エリア) */
.right-panel {
background-color: #fff;
gap: 10px;
}

/* 共通指示入力欄 */
.common-input {
width: 100%;
padding: 10px;
font-size: 1em;
border: 1px solid #007bff;
border-radius: 6px;
box-sizing: border-box;
background-color: #f0f7ff;
color: #333;
}
.common-input:focus {
outline: none;
border-color: #0056b3;
box-shadow: 0 0 0 2px rgba(0,123,255,0.2);
}

/* コントロールバー(数値入力と生成ボタン) */
.control-bar {
display: flex;
gap: 10px;
align-items: center;
}

.count-input {
width: 80px;
padding: 8px;
font-size: 1em;
border: 1px solid #ddd;
border-radius: 6px;
text-align: center;
}

/* 生成ボタン */
.generate-btn {
flex-grow: 1;
padding: 8px;
font-size: 1em;
font-weight: bold;
color: #fff;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
box-shadow: 0 2px 5px rgba(118, 75, 162, 0.3);
border: none;
border-radius: 6px;
cursor: pointer;
transition: opacity 0.2s, transform 0.1s;
}
.generate-btn:hover { opacity: 0.95; }
.generate-btn:active { transform: translateY(1px); }

/* 結果リストエリア */
.results-container {
flex-grow: 1;
display: flex;
flex-direction: column;
gap: 6px;
overflow-y: auto;
padding-bottom: 5px;
padding-right: 5px;
border-top: 1px solid #eee; /* 区切り線 */
padding-top: 10px;
}

/* 1行ごとの結果行 */
.result-row {
display: flex;
gap: 8px;
align-items: center;
}
.result-number {
font-size: 0.8em;
color: #999;
width: 30px; /* 桁数増えたとき用に少し拡大 */
text-align: right;
flex-shrink: 0;
}
.result-input {
flex-grow: 1;
padding: 6px 10px;
font-size: 0.95em;
border: 1px solid #eee;
border-radius: 4px;
color: #333;
background-color: #fdfdfd;
}
.result-input:focus {
outline: none; border-color: #667eea;
}

.copy-btn {
padding: 0 10px;
height: 32px;
font-size: 0.8em;
font-weight: bold;
color: #fff;
background-color: #28a745;
border: none;
border-radius: 4px;
cursor: pointer;
white-space: nowrap;
transition: background-color 0.2s;
width: 70px;
flex-shrink: 0;
}
.copy-btn:hover { background-color: #218838; }
.copy-btn.copied { background-color: #6c757d; }

/* ダウンロードエリア */
.download-area {
border-top: 1px solid #e1e4e8;
padding-top: 10px;
margin-top: auto;
}
.download-btn {
width: 100%;
padding: 12px;
font-size: 1em;
font-weight: bold;
color: #007bff;
background-color: #fff;
border: 2px solid #007bff;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
}
.download-btn:hover {
background-color: #007bff;
color: #fff;
}

</style>
</head>
<body>

<div class="dashboard-container">
<div class="panel left-panel">
<div class="columns-header">
<div>修飾語</div>
<div>主語</div>
<div>時間</div>
</div>
<div class="columns-container">
<div class="text-column">
<textarea id="input_mod" class="word-list" placeholder="例:
霧の深い
渓谷に囲まれた"></textarea>
</div>
<div class="text-column">
<textarea id="input_subj" class="word-list" placeholder="例:
近未来都市
古代都市"></textarea>
</div>
<div class="text-column">
<textarea id="input_time" class="word-list" placeholder="例:
夕方
朝方"></textarea>
</div>
</div>
<button id="saveBtn" class="save-btn" onclick="saveSettings()">設定を保存</button>
</div>

<div class="panel right-panel">
<input type="text" id="common_inst" class="common-input" placeholder="共通の指示を入力...">

<div class="control-bar">
<input type="number" id="gen_count" class="count-input" value="10" min="1" max="500">
<span style="font-size:0.9em; color:#666;">個</span>
<button class="generate-btn" onclick="generateBatch()">✨ 一括生成</button>
</div>

<div class="results-container" id="resultsList">
</div>

<div class="download-area">
<button class="download-btn" onclick="downloadFile()">⬇️ リストをテキスト保存 (gemini-360data-list.txt)</button>
</div>
</div>
</div>

<script>
// ---------------------------------------------------------
// ■ 初期設定とデータ管理
// ---------------------------------------------------------

// デフォルト値
const defaultData = {
common: "360度パノラマ画像を作って。 Deep focus, 高精細で頼む。",
mod: "霧の深い\n霧のある\n霧のたなびく\n渓谷に囲まれた\n滝に囲まれた\n廃墟となった\n水没した\n空中に浮かぶ\n氷に覆われた\n砂嵐が吹き荒れる\n静寂に包まれた\nディストピアな\n古代の神話のような\n清涼感のある爽やかな風が吹く\n神秘的な",
subj: "近未来都市\n古代都市\n宇宙ステーション\n神殿\n巨大樹の村\n海底神殿\nサイバーパンクな路地裏\n要塞\n空中庭園\n神殿\nスペースコロニー\n中世の城のある町\n工業地帯\n渓谷\nユグドラシルの根本\n雲海\n大都市\n高層建築の谷間\n巨大地下空洞\n浮遊島\n海岸\nエネルギーシールドに守られたドーム\n巨大ステーション\n大迷宮の巨大空間\n化石化した超巨大生物の肋骨の町\n高層ビル群\n海上都市\n魔王城\n巨大クジラの背の上\n巨大亀の背の上\n城下町\n浮遊大陸\n岩礁地帯\n草原\n大量の古代の塔\n祭壇\n雲海に浮かぶ城",
time: "夕方\n朝方\n真夜中\n正午\n黄昏時\n夜明け前"
};

// ページ読み込み時
window.onload = function() {
loadSettings();
// 初回は10個生成しておく
document.getElementById('gen_count').value = 10;
generateBatch();
};

// 設定を読み込んで各エリアにセット
function loadSettings() {
const savedCommon = localStorage.getItem('prompt_common');
const savedMod = localStorage.getItem('prompt_mod');
const savedSubj = localStorage.getItem('prompt_subj');
const savedTime = localStorage.getItem('prompt_time');

document.getElementById('common_inst').value = savedCommon !== null ? savedCommon : defaultData.common;
document.getElementById('input_mod').value = savedMod !== null ? savedMod : defaultData.mod;
document.getElementById('input_subj').value = savedSubj !== null ? savedSubj : defaultData.subj;
document.getElementById('input_time').value = savedTime !== null ? savedTime : defaultData.time;
}

function saveSettings() {
const commonVal = document.getElementById('common_inst').value;
const modVal = document.getElementById('input_mod').value;
const subjVal = document.getElementById('input_subj').value;
const timeVal = document.getElementById('input_time').value;

localStorage.setItem('prompt_common', commonVal);
localStorage.setItem('prompt_mod', modVal);
localStorage.setItem('prompt_subj', subjVal);
localStorage.setItem('prompt_time', timeVal);

const btn = document.getElementById('saveBtn');
const originalText = btn.innerText;
btn.innerText = "全設定を保存しました!";
btn.classList.add("saved");
setTimeout(() => {
btn.innerText = originalText;
btn.classList.remove("saved");
}, 1500);
}

// ---------------------------------------------------------
// ■ 生成ロジック
// ---------------------------------------------------------
function generateBatch() {
const container = document.getElementById('resultsList');
const countInput = document.getElementById('gen_count');
let count = parseInt(countInput.value, 10);

// バリデーション(1〜1000程度の範囲に制限)
if (isNaN(count) || count < 1) count = 1;
if (count > 1000) count = 1000;
countInput.value = count; // 補正値を反映

// リストをクリア
container.innerHTML = '';

const getList = (id) => {
const val = document.getElementById(id).value;
return val.split('\n').map(s => s.trim()).filter(s => s !== "");
};

const modList = getList('input_mod');
const subjList = getList('input_subj');
const timeList = getList('input_time');

const pick = (arr) => {
if (arr.length === 0) return "";
return arr[Math.floor(Math.random() * arr.length)];
};

// 指定回数ループして要素を作成
for (let i = 0; i < count; i++) {
const m = pick(modList);
const s = pick(subjList);
const t = pick(timeList);

let text = m + s;
if (t) {
if (text) text += ", " + t;
else text = t;
}

// 行要素の作成
const row = document.createElement('div');
row.className = 'result-row';
row.innerHTML = `
<span class="result-number">${i+1}.</span>
<input type="text" id="result_${i}" class="result-input" value="${text}">
<button class="copy-btn" id="btn_${i}" onclick="copyText(${i})">コピー</button>
`;
container.appendChild(row);
}
}

// ---------------------------------------------------------
// ■ コピー機能
// ---------------------------------------------------------
function copyText(index) {
const commonText = document.getElementById('common_inst').value.trim();
const inputEl = document.getElementById(`result_${index}`);
if (!inputEl) return;
const resultText = inputEl.value.trim();

if (!resultText) return;

let finalText = "";
if (commonText) {
finalText = commonText + " " + resultText;
} else {
finalText = resultText;
}

navigator.clipboard.writeText(finalText).then(() => {
const btnEl = document.getElementById(`btn_${index}`);
btnEl.innerText = "OK!";
btnEl.classList.add("copied");
setTimeout(() => {
btnEl.innerText = "コピー";
btnEl.classList.remove("copied");
}, 1500);
});
}

// ---------------------------------------------------------
// ■ ファイル保存機能 (ダウンロード)
// ---------------------------------------------------------
function downloadFile() {
const commonText = document.getElementById('common_inst').value.trim();
const inputs = document.querySelectorAll('.result-input');

let fileContent = "";

inputs.forEach((input) => {
const val = input.value.trim();
if (val) {
if (commonText) {
fileContent += commonText + " " + val + "\n";
} else {
fileContent += val + "\n";
}
}
});

if (!fileContent) {
alert("保存するデータがありません。");
return;
}

// Blobを作成してダウンロードリンクをトリガー
const blob = new Blob([fileContent], { type: "text/plain" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "gemini-360data-list.txt";
link.click();

// メモリ開放
URL.revokeObjectURL(link.href);
}

</script>
</body>
</html>


使用変数

blob
btn
btnEl
charset
class
className
commonText
commonVal
container
copyText -------( Function )
count
countInput
defaultData
download
downloadFile -------( Function )
fileContent
finalText
generateBatch -------( Function )
getList
href
i
id
innerHTML
innerText
inputEl
inputs
lang
length
link
loadSettings -------( Function )
m
max
min
modList
modVal
onclick
onload
originalText
pick
placeholder
resultText
row
s
savedCommon
savedMod
savedSubj
savedTime
saveSettings -------( Function )
style
subjList
subjVal
t
text
timeList
timeVal
type
val
value

Content-type: text/html error-smemo8

ERROR !

ファイルの差し替えに失敗しました: ./smemo8.log