merge: align main command editor with ref
# Conflicts: # app/game-frontend/e2e/mainNavigation.spec.ts
This commit is contained in:
@@ -19,6 +19,7 @@ export interface ReservedTurnView {
|
|||||||
export interface ReservedTurnSnapshot {
|
export interface ReservedTurnSnapshot {
|
||||||
revision: number;
|
revision: number;
|
||||||
turns: ReservedTurnView[];
|
turns: ReservedTurnView[];
|
||||||
|
autorunLimit?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReservedTurnUpdate {
|
export interface ReservedTurnUpdate {
|
||||||
@@ -170,13 +171,19 @@ export const listGeneralTurns = async (db: DatabaseClient, generalId: number): P
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getGeneralTurnSnapshot = async (db: DatabaseClient, generalId: number): Promise<ReservedTurnSnapshot> => {
|
export const getGeneralTurnSnapshot = async (db: DatabaseClient, generalId: number): Promise<ReservedTurnSnapshot> => {
|
||||||
const [turns, revisionRow] = await Promise.all([
|
const [turns, revisionRow, general] = await Promise.all([
|
||||||
loadGeneralTurns(db, generalId),
|
loadGeneralTurns(db, generalId),
|
||||||
db.generalTurnRevision.findUnique({ where: { generalId } }),
|
db.generalTurnRevision.findUnique({ where: { generalId } }),
|
||||||
|
db.general.findUnique({ where: { id: generalId }, select: { meta: true } }),
|
||||||
]);
|
]);
|
||||||
|
const rawAutorunLimit = isRecord(general?.meta) ? general.meta.autorun_limit : undefined;
|
||||||
return {
|
return {
|
||||||
revision: revisionRow?.revision ?? 0,
|
revision: revisionRow?.revision ?? 0,
|
||||||
turns: serializeTurnList(turns),
|
turns: serializeTurnList(turns),
|
||||||
|
autorunLimit:
|
||||||
|
typeof rawAutorunLimit === 'number' && Number.isFinite(rawAutorunLimit)
|
||||||
|
? Math.trunc(rawAutorunLimit)
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -824,7 +824,7 @@ describe('appRouter', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns reserved general turns', async () => {
|
it('returns reserved general turns', async () => {
|
||||||
const general = buildGeneralRow({ id: 11 });
|
const general = buildGeneralRow({ id: 11, meta: { autorun_limit: 2408 } });
|
||||||
const generalTurns: GeneralTurnRow[] = [
|
const generalTurns: GeneralTurnRow[] = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -839,6 +839,7 @@ describe('appRouter', () => {
|
|||||||
const response = await caller.turns.reserved.getGeneral({ generalId: 11 });
|
const response = await caller.turns.reserved.getGeneral({ generalId: 11 });
|
||||||
|
|
||||||
expect(response.revision).toBe(0);
|
expect(response.revision).toBe(0);
|
||||||
|
expect(response.autorunLimit).toBe(2408);
|
||||||
expect(response.turns[0]?.action).toBe('che_화계');
|
expect(response.turns[0]?.action).toBe('che_화계');
|
||||||
expect(response.turns[0]?.index).toBe(0);
|
expect(response.turns[0]?.index).toBe(0);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type NavigationFixture = {
|
|||||||
reservedTurns?: Array<{ index: number; action: string; args: Record<string, unknown> }>;
|
reservedTurns?: Array<{ index: number; action: string; args: Record<string, unknown> }>;
|
||||||
messages?: unknown;
|
messages?: unknown;
|
||||||
messageContacts?: unknown;
|
messageContacts?: unknown;
|
||||||
|
autorunLimit?: number | null;
|
||||||
dashboardResponses?: Array<{
|
dashboardResponses?: Array<{
|
||||||
bytes: number;
|
bytes: number;
|
||||||
contextKind: string | null;
|
contextKind: string | null;
|
||||||
@@ -405,7 +406,11 @@ const installFixture = async (page: Page, state: NavigationFixture) => {
|
|||||||
}
|
}
|
||||||
if (operation === 'turns.getCommandTable') return response({ general: [], nation: [] });
|
if (operation === 'turns.getCommandTable') return response({ general: [], nation: [] });
|
||||||
if (operation === 'turns.reserved.getGeneral' || operation === 'turns.reserved.getNation') {
|
if (operation === 'turns.reserved.getGeneral' || operation === 'turns.reserved.getNation') {
|
||||||
return response({ turns: state.reservedTurns ?? [], revision: 0 });
|
return response({
|
||||||
|
turns: state.reservedTurns ?? [],
|
||||||
|
revision: 0,
|
||||||
|
autorunLimit: state.autorunLimit ?? null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (operation === 'messages.getRecent') {
|
if (operation === 'messages.getRecent') {
|
||||||
return response(state.messages ?? emptyMessages(state.permission));
|
return response(state.messages ?? emptyMessages(state.permission));
|
||||||
@@ -729,11 +734,12 @@ test('main cards and command input stay inside their Ref-sized grid slots', asyn
|
|||||||
generalMeCalls: 0,
|
generalMeCalls: 0,
|
||||||
operations: [],
|
operations: [],
|
||||||
largeCommandTable: true,
|
largeCommandTable: true,
|
||||||
reservedTurns: Array.from({ length: 14 }, (_, index) => ({
|
reservedTurns: Array.from({ length: 30 }, (_, index) => ({
|
||||||
index,
|
index,
|
||||||
action: `command-${index}`,
|
action: index === 0 ? '휴식' : `command-${index}`,
|
||||||
args: {},
|
args: {},
|
||||||
})),
|
})),
|
||||||
|
autorunLimit: 2224,
|
||||||
};
|
};
|
||||||
await installFixture(page, state);
|
await installFixture(page, state);
|
||||||
await page.setViewportSize({ width: 1200, height: 900 });
|
await page.setViewportSize({ width: 1200, height: 900 });
|
||||||
@@ -816,6 +822,27 @@ test('main cards and command input stay inside their Ref-sized grid slots', asyn
|
|||||||
expect(new Set(desktopGeometry.visibleControlBoxes.map(({ y }) => y)).size).toBe(1);
|
expect(new Set(desktopGeometry.visibleControlBoxes.map(({ y }) => y)).size).toBe(1);
|
||||||
expect(desktopGeometry.bottomActionBoxes).toHaveLength(3);
|
expect(desktopGeometry.bottomActionBoxes).toHaveLength(3);
|
||||||
expect(new Set(desktopGeometry.bottomActionBoxes.map(({ y }) => y)).size).toBe(1);
|
expect(new Set(desktopGeometry.bottomActionBoxes.map(({ y }) => y)).size).toBe(1);
|
||||||
|
await expect(page.locator('[data-main-target="commands"] .edit-column button')).toHaveCount(15);
|
||||||
|
const autonomousRest = page.locator('[data-main-target="commands"] .action-column > div').first();
|
||||||
|
await expect(autonomousRest).toContainText('휴식(자율 행동)');
|
||||||
|
expect(await autonomousRest.evaluate((element) => getComputedStyle(element).color)).toBe('rgb(170, 255, 255)');
|
||||||
|
|
||||||
|
const tenthTurnButton = page.getByRole('button', { name: '10턴 명령 입력' });
|
||||||
|
await tenthTurnButton.click();
|
||||||
|
const quickPicker = page.getByTestId('command-picker');
|
||||||
|
await expect(quickPicker).toBeVisible();
|
||||||
|
const quickPickerAlignment = await quickPicker.evaluate((element) => {
|
||||||
|
const row = element
|
||||||
|
.closest('.reserved-command-editor')
|
||||||
|
?.querySelector<HTMLElement>('.action-column > div:nth-child(10)');
|
||||||
|
if (!row) throw new Error('10th command row missing');
|
||||||
|
return {
|
||||||
|
pickerTop: element.getBoundingClientRect().top,
|
||||||
|
rowTop: row.getBoundingClientRect().top,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
expect(quickPickerAlignment.pickerTop - quickPickerAlignment.rowTop).toBeCloseTo(30, 0);
|
||||||
|
await quickPicker.getByRole('button', { name: '명령 입력 닫기' }).click();
|
||||||
|
|
||||||
const modeButton = page.locator('[data-main-target="commands"] .control-pad').getByRole('button', {
|
const modeButton = page.locator('[data-main-target="commands"] .control-pad').getByRole('button', {
|
||||||
name: '고급 모드',
|
name: '고급 모드',
|
||||||
@@ -824,6 +851,27 @@ test('main cards and command input stay inside their Ref-sized grid slots', asyn
|
|||||||
await modeButton.focus();
|
await modeButton.focus();
|
||||||
await expect(modeButton).toBeFocused();
|
await expect(modeButton).toBeFocused();
|
||||||
await modeButton.click();
|
await modeButton.click();
|
||||||
|
const advancedControlGeometry = await page.locator('[data-main-target="commands"] .reserved-command-editor').evaluate(
|
||||||
|
(editor) => {
|
||||||
|
const range = editor.querySelector<HTMLElement>('.range-menu');
|
||||||
|
const recent = [...editor.querySelectorAll<HTMLElement>('.control-pad summary')].find((element) =>
|
||||||
|
element.textContent?.includes('최근 실행')
|
||||||
|
);
|
||||||
|
const advanced = editor.querySelector<HTMLElement>('.advanced-actions');
|
||||||
|
const queue = editor.querySelector<HTMLElement>('.queue-grid');
|
||||||
|
if (!range || !recent || !advanced || !queue) throw new Error('advanced command controls missing');
|
||||||
|
return {
|
||||||
|
rangeTop: range.getBoundingClientRect().top,
|
||||||
|
recentTop: recent.getBoundingClientRect().top,
|
||||||
|
advancedTop: advanced.getBoundingClientRect().top,
|
||||||
|
advancedBottom: advanced.getBoundingClientRect().bottom,
|
||||||
|
queueTop: queue.getBoundingClientRect().top,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(advancedControlGeometry.rangeTop).toBe(advancedControlGeometry.recentTop);
|
||||||
|
expect(advancedControlGeometry.advancedTop).toBeGreaterThan(advancedControlGeometry.rangeTop);
|
||||||
|
expect(advancedControlGeometry.advancedBottom).toBeLessThanOrEqual(advancedControlGeometry.queueTop);
|
||||||
await page.locator('[data-main-target="commands"] .select-command').click();
|
await page.locator('[data-main-target="commands"] .select-command').click();
|
||||||
const picker = page.getByTestId('command-picker');
|
const picker = page.getByTestId('command-picker');
|
||||||
await expect(picker).toBeVisible();
|
await expect(picker).toBeVisible();
|
||||||
@@ -853,6 +901,32 @@ test('main cards and command input stay inside their Ref-sized grid slots', asyn
|
|||||||
expect(pickerGeometry.horizontalOverflow).toBeLessThanOrEqual(0);
|
expect(pickerGeometry.horizontalOverflow).toBeLessThanOrEqual(0);
|
||||||
await picker.getByRole('button', { name: '명령 입력 닫기' }).click();
|
await picker.getByRole('button', { name: '명령 입력 닫기' }).click();
|
||||||
|
|
||||||
|
await page.locator('[data-main-target="commands"] .control-pad').getByRole('button', { name: '일반 모드' }).click();
|
||||||
|
const collapsedPanelHeight = await page
|
||||||
|
.locator('[data-main-target="commands"]')
|
||||||
|
.evaluate((element) => element.getBoundingClientRect().height);
|
||||||
|
await page.locator('[data-main-target="commands"] .bottom-actions').getByRole('button', { name: '펼치기' }).click();
|
||||||
|
await expect(page.locator('[data-main-target="commands"] .edit-column button')).toHaveCount(30);
|
||||||
|
const expandedDesktopGeometry = await page.locator('.layout-desktop').evaluate((layout) => {
|
||||||
|
const commands = layout.querySelector<HTMLElement>('[data-main-target="commands"]');
|
||||||
|
const city = layout.querySelector<HTMLElement>('[data-main-target="city"]');
|
||||||
|
const nation = layout.querySelector<HTMLElement>('[data-main-target="nation"]');
|
||||||
|
if (!commands || !city || !nation) throw new Error('expanded desktop panels missing');
|
||||||
|
return {
|
||||||
|
commandHeight: commands.getBoundingClientRect().height,
|
||||||
|
commandBottom: commands.getBoundingClientRect().bottom,
|
||||||
|
cityBottom: city.getBoundingClientRect().bottom,
|
||||||
|
nationTop: nation.getBoundingClientRect().top,
|
||||||
|
verticalOverflow: commands.scrollHeight - commands.clientHeight,
|
||||||
|
overflowY: getComputedStyle(commands).overflowY,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
expect(expandedDesktopGeometry.commandHeight).toBeGreaterThan(collapsedPanelHeight);
|
||||||
|
expect(expandedDesktopGeometry.verticalOverflow).toBeLessThanOrEqual(0);
|
||||||
|
expect(expandedDesktopGeometry.overflowY).toBe('visible');
|
||||||
|
expect(expandedDesktopGeometry.cityBottom).toBe(expandedDesktopGeometry.commandBottom);
|
||||||
|
expect(expandedDesktopGeometry.nationTop).toBeGreaterThanOrEqual(expandedDesktopGeometry.commandBottom);
|
||||||
|
|
||||||
const captureProgress = async (name: string) => {
|
const captureProgress = async (name: string) => {
|
||||||
if (!artifactRoot) return;
|
if (!artifactRoot) return;
|
||||||
await mkdir(artifactRoot, { recursive: true });
|
await mkdir(artifactRoot, { recursive: true });
|
||||||
@@ -940,9 +1014,9 @@ test('main cards and command input stay inside their Ref-sized grid slots', asyn
|
|||||||
};
|
};
|
||||||
await captureProgress('desktop-1200');
|
await captureProgress('desktop-1200');
|
||||||
|
|
||||||
await page.locator('[data-main-target="commands"] .control-pad').getByRole('button', { name: '일반 모드' }).click();
|
|
||||||
await page.setViewportSize({ width: 500, height: 900 });
|
await page.setViewportSize({ width: 500, height: 900 });
|
||||||
await expect(page.locator('.layout-mobile')).toBeVisible();
|
await expect(page.locator('.layout-mobile')).toBeVisible();
|
||||||
|
await page.locator('[data-main-target="commands"] .bottom-actions').getByRole('button', { name: '펼치기' }).click();
|
||||||
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(500);
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(500);
|
||||||
await expect(page.locator('[data-main-target="city"] [role="progressbar"]')).toHaveCount(8);
|
await expect(page.locator('[data-main-target="city"] [role="progressbar"]')).toHaveCount(8);
|
||||||
await expect(page.locator('[data-main-target="general"] [role="progressbar"]')).toHaveCount(4);
|
await expect(page.locator('[data-main-target="general"] [role="progressbar"]')).toHaveCount(4);
|
||||||
@@ -977,7 +1051,7 @@ test('main cards and command input stay inside their Ref-sized grid slots', asyn
|
|||||||
controlBoxes,
|
controlBoxes,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
expect(mobileGeometry.panelHeight).toBe(645);
|
expect(mobileGeometry.panelHeight).toBeGreaterThan(645);
|
||||||
expect(mobileGeometry.editorLeft).toBeGreaterThanOrEqual(mobileGeometry.panelLeft);
|
expect(mobileGeometry.editorLeft).toBeGreaterThanOrEqual(mobileGeometry.panelLeft);
|
||||||
expect(mobileGeometry.editorRight).toBeLessThanOrEqual(mobileGeometry.panelRight);
|
expect(mobileGeometry.editorRight).toBeLessThanOrEqual(mobileGeometry.panelRight);
|
||||||
expect(mobileGeometry.horizontalOverflow).toBeLessThanOrEqual(0);
|
expect(mobileGeometry.horizontalOverflow).toBeLessThanOrEqual(0);
|
||||||
@@ -985,6 +1059,7 @@ test('main cards and command input stay inside their Ref-sized grid slots', asyn
|
|||||||
expect(mobileGeometry.controlColumns.split(' ')).toHaveLength(3);
|
expect(mobileGeometry.controlColumns.split(' ')).toHaveLength(3);
|
||||||
expect(mobileGeometry.controlBoxes).toHaveLength(3);
|
expect(mobileGeometry.controlBoxes).toHaveLength(3);
|
||||||
expect(new Set(mobileGeometry.controlBoxes.map(({ y }) => y)).size).toBe(1);
|
expect(new Set(mobileGeometry.controlBoxes.map(({ y }) => y)).size).toBe(1);
|
||||||
|
await expect(page.locator('[data-main-target="commands"] .edit-column button')).toHaveCount(30);
|
||||||
await captureProgress('mobile-500');
|
await captureProgress('mobile-500');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ const commandArgsValid = ref(false);
|
|||||||
const expanded = ref(false);
|
const expanded = ref(false);
|
||||||
const menuRevision = ref(0);
|
const menuRevision = ref(0);
|
||||||
const pendingReservation = ref<CommandPatternEntry | null>(null);
|
const pendingReservation = ref<CommandPatternEntry | null>(null);
|
||||||
|
const collapsedRowCount = 15;
|
||||||
|
|
||||||
const loadStorage = (key: string) => {
|
const loadStorage = (key: string) => {
|
||||||
storage.value = new CommandStorage(key);
|
storage.value = new CommandStorage(key);
|
||||||
@@ -108,7 +109,11 @@ const labelMap = computed(() => {
|
|||||||
for (const group of groups) for (const command of group.values) map.set(command.key, command.name);
|
for (const group of groups) for (const command of group.values) map.set(command.key, command.name);
|
||||||
return map;
|
return map;
|
||||||
});
|
});
|
||||||
const displayRows = computed(() => props.rows.slice(0, expanded.value || props.compact ? props.rows.length : 14));
|
const displayRows = computed(() =>
|
||||||
|
props.rows.slice(0, expanded.value || props.compact ? props.rows.length : collapsedRowCount)
|
||||||
|
);
|
||||||
|
const quickPickerTop = computed(() => `${70 + (quickTarget.value ?? 0) * 34.4}px`);
|
||||||
|
const rowLabel = (row: ReservedCommandRow): string => row.label ?? labelMap.value.get(row.action) ?? row.action;
|
||||||
const selectedIndices = () => normalizedSelection(selected.value, previousSelected.value, props.rows.length);
|
const selectedIndices = () => normalizedSelection(selected.value, previousSelected.value, props.rows.length);
|
||||||
const pattern = () => extractPattern(props.rows, selectedIndices());
|
const pattern = () => extractPattern(props.rows, selectedIndices());
|
||||||
const touchMenus = () => (menuRevision.value += 1);
|
const touchMenus = () => (menuRevision.value += 1);
|
||||||
@@ -396,6 +401,87 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
</details>
|
</details>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
|
<div v-if="editMode" class="advanced-actions">
|
||||||
|
<details class="legacy-menu selected-menu">
|
||||||
|
<summary>선택한 턴을</summary>
|
||||||
|
<div class="menu-items">
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
cut();
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
잘라내기
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
copy();
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
복사하기
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
paste();
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
붙여넣기
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
textCopy();
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
텍스트 복사
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
saveTemplate();
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
보관하기
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
repeatPattern();
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
반복하기
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
clearSelection();
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
비우기
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
rearrange('pull');
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
지우고 당기기
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
rearrange('push');
|
||||||
|
clickOutsideMenu($event);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
뒤로 밀기
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<button type="button" class="select-command" @click="openPicker()">명령 선택 ▾</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="queue-area">
|
<div class="queue-area">
|
||||||
<div class="queue-grid" :class="{ advanced: editMode }">
|
<div class="queue-grid" :class="{ advanced: editMode }">
|
||||||
<DragSelect
|
<DragSelect
|
||||||
@@ -443,9 +529,11 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
<div
|
<div
|
||||||
v-for="row in displayRows"
|
v-for="row in displayRows"
|
||||||
:key="row.index"
|
:key="row.index"
|
||||||
:title="row.label ?? labelMap.get(row.action) ?? row.action"
|
:title="row.autonomous ? `${rowLabel(row)} · 자율 행동` : rowLabel(row)"
|
||||||
|
:class="{ autonomous: row.autonomous }"
|
||||||
>
|
>
|
||||||
{{ row.label ?? labelMap.get(row.action) ?? row.action }}
|
<span>{{ rowLabel(row) }}</span>
|
||||||
|
<small v-if="row.autonomous && row.action === '휴식'">(자율 행동)</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!editMode" class="edit-column">
|
<div v-if="!editMode" class="edit-column">
|
||||||
@@ -461,87 +549,6 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="editMode" class="advanced-actions">
|
|
||||||
<details class="legacy-menu selected-menu">
|
|
||||||
<summary>선택한 턴을</summary>
|
|
||||||
<div class="menu-items">
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
cut();
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
잘라내기
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
copy();
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
복사하기
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
paste();
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
붙여넣기
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
textCopy();
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
텍스트 복사
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
saveTemplate();
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
보관하기
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
repeatPattern();
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
반복하기
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
clearSelection();
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
비우기
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
rearrange('pull');
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
지우고 당기기
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
rearrange('push');
|
|
||||||
clickOutsideMenu($event);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
뒤로 밀기
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
<button type="button" class="select-command" @click="openPicker()">명령 선택 ▾</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="!props.compact" class="bottom-actions">
|
<div v-if="!props.compact" class="bottom-actions">
|
||||||
<button type="button" @click="emit('shift', -1)">당기기</button>
|
<button type="button" @click="emit('shift', -1)">당기기</button>
|
||||||
<button type="button" @click="emit('shift', 1)">미루기</button>
|
<button type="button" @click="emit('shift', 1)">미루기</button>
|
||||||
@@ -550,7 +557,12 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="pickerOpen" class="command-picker" data-testid="command-picker">
|
<div
|
||||||
|
v-if="pickerOpen"
|
||||||
|
class="command-picker"
|
||||||
|
data-testid="command-picker"
|
||||||
|
:style="quickTarget === null || props.compact ? undefined : { top: quickPickerTop }"
|
||||||
|
>
|
||||||
<header>
|
<header>
|
||||||
<strong>{{ quickTarget === null ? '선택한 턴' : `${quickTarget + 1}턴` }} 명령 입력</strong
|
<strong>{{ quickTarget === null ? '선택한 턴' : `${quickTarget + 1}턴` }} 명령 입력</strong
|
||||||
><button type="button" aria-label="명령 입력 닫기" @click="closePicker">×</button>
|
><button type="button" aria-label="명령 입력 닫기" @click="closePicker">×</button>
|
||||||
@@ -628,6 +640,9 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
gap: 4px;
|
gap: 4px;
|
||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
}
|
}
|
||||||
|
.queue-area {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
.control-pad > button,
|
.control-pad > button,
|
||||||
.clock,
|
.clock,
|
||||||
.legacy-menu > summary,
|
.legacy-menu > summary,
|
||||||
@@ -779,6 +794,13 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
.action-column > div:nth-child(even) {
|
.action-column > div:nth-child(even) {
|
||||||
background: #071638;
|
background: #071638;
|
||||||
}
|
}
|
||||||
|
.action-column > div.autonomous {
|
||||||
|
color: #aaffff;
|
||||||
|
}
|
||||||
|
.action-column small {
|
||||||
|
font-size: 0.72em;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
.edit-column button {
|
.edit-column button {
|
||||||
background: #444;
|
background: #444;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -786,6 +808,7 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
.advanced-actions {
|
.advanced-actions {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 5fr 7fr;
|
grid-template-columns: 5fr 7fr;
|
||||||
|
order: 1;
|
||||||
}
|
}
|
||||||
.advanced-actions > * {
|
.advanced-actions > * {
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
@@ -808,6 +831,10 @@ const clickOutsideMenu = (event: Event) => {
|
|||||||
background: #303030;
|
background: #303030;
|
||||||
box-shadow: 0 6px 16px #000;
|
box-shadow: 0 6px 16px #000;
|
||||||
}
|
}
|
||||||
|
.reserved-command-editor:not(.compact) .command-picker {
|
||||||
|
max-height: none;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
.command-picker > header {
|
.command-picker > header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export type ReservedCommandRow = {
|
|||||||
time?: string;
|
time?: string;
|
||||||
year?: number;
|
year?: number;
|
||||||
month?: number;
|
month?: number;
|
||||||
|
autonomous?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CommandPatternEntry = {
|
export type CommandPatternEntry = {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const props = defineProps<{
|
|||||||
currentYear?: number;
|
currentYear?: number;
|
||||||
currentMonth?: number;
|
currentMonth?: number;
|
||||||
turnTermMinutes?: number;
|
turnTermMinutes?: number;
|
||||||
|
autorunLimit?: number | null;
|
||||||
storageKey?: string;
|
storageKey?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ const rows = computed<ReservedCommandRow[]>(() => {
|
|||||||
label: labelMap.value.get(turn.action) ?? turn.action,
|
label: labelMap.value.get(turn.action) ?? turn.action,
|
||||||
year: Math.floor(absoluteMonth / 12),
|
year: Math.floor(absoluteMonth / 12),
|
||||||
month: (absoluteMonth % 12) + 1,
|
month: (absoluteMonth % 12) + 1,
|
||||||
|
autonomous: props.autorunLimit != null && absoluteMonth <= props.autorunLimit - 1,
|
||||||
time: date
|
time: date
|
||||||
? term >= 5
|
? term >= 5
|
||||||
? `${String(date.getUTCHours()).padStart(2, '0')}:${String(date.getUTCMinutes()).padStart(2, '0')}`
|
? `${String(date.getUTCHours()).padStart(2, '0')}:${String(date.getUTCMinutes()).padStart(2, '0')}`
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
boardAccess?: BoardAccess | null;
|
boardAccess?: BoardAccess | null;
|
||||||
reservedGeneralTurns?: ReservedTurnView[] | null;
|
reservedGeneralTurns?: ReservedTurnView[] | null;
|
||||||
reservedGeneralRevision?: number;
|
reservedGeneralRevision?: number;
|
||||||
|
reservedGeneralAutorunLimit?: number | null;
|
||||||
globalRecords?: RecentRecord[];
|
globalRecords?: RecentRecord[];
|
||||||
generalRecords?: RecentRecord[];
|
generalRecords?: RecentRecord[];
|
||||||
worldHistory?: RecentRecord[];
|
worldHistory?: RecentRecord[];
|
||||||
@@ -94,6 +95,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
const boardAccess = ref<BoardAccess | null>(null);
|
const boardAccess = ref<BoardAccess | null>(null);
|
||||||
const reservedGeneralTurns = ref<ReservedTurnView[] | null>(null);
|
const reservedGeneralTurns = ref<ReservedTurnView[] | null>(null);
|
||||||
const reservedGeneralRevision = ref(0);
|
const reservedGeneralRevision = ref(0);
|
||||||
|
const reservedGeneralAutorunLimit = ref<number | null>(null);
|
||||||
const globalRecords = ref<RecentRecord[]>([]);
|
const globalRecords = ref<RecentRecord[]>([]);
|
||||||
const generalRecords = ref<RecentRecord[]>([]);
|
const generalRecords = ref<RecentRecord[]>([]);
|
||||||
const worldHistory = ref<RecentRecord[]>([]);
|
const worldHistory = ref<RecentRecord[]>([]);
|
||||||
@@ -331,6 +333,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
boardAccess.value = null;
|
boardAccess.value = null;
|
||||||
reservedGeneralTurns.value = null;
|
reservedGeneralTurns.value = null;
|
||||||
reservedGeneralRevision.value = 0;
|
reservedGeneralRevision.value = 0;
|
||||||
|
reservedGeneralAutorunLimit.value = null;
|
||||||
resetRecentRecords(null);
|
resetRecentRecords(null);
|
||||||
commandTableRevision = null;
|
commandTableRevision = null;
|
||||||
boardAccessRevision = null;
|
boardAccessRevision = null;
|
||||||
@@ -351,6 +354,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
boardAccess.value = null;
|
boardAccess.value = null;
|
||||||
reservedGeneralTurns.value = null;
|
reservedGeneralTurns.value = null;
|
||||||
reservedGeneralRevision.value = 0;
|
reservedGeneralRevision.value = 0;
|
||||||
|
reservedGeneralAutorunLimit.value = null;
|
||||||
resetRecentRecords(null);
|
resetRecentRecords(null);
|
||||||
contextRevision = null;
|
contextRevision = null;
|
||||||
commandTableRevision = null;
|
commandTableRevision = null;
|
||||||
@@ -384,6 +388,9 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
if (patch.reservedGeneralRevision !== undefined) {
|
if (patch.reservedGeneralRevision !== undefined) {
|
||||||
reservedGeneralRevision.value = patch.reservedGeneralRevision;
|
reservedGeneralRevision.value = patch.reservedGeneralRevision;
|
||||||
}
|
}
|
||||||
|
if (patch.reservedGeneralAutorunLimit !== undefined) {
|
||||||
|
reservedGeneralAutorunLimit.value = patch.reservedGeneralAutorunLimit;
|
||||||
|
}
|
||||||
if (patch.globalRecords !== undefined) {
|
if (patch.globalRecords !== undefined) {
|
||||||
globalRecords.value = structurallyShare(globalRecords.value, patch.globalRecords);
|
globalRecords.value = structurallyShare(globalRecords.value, patch.globalRecords);
|
||||||
lastGeneralRecordId = Math.max(lastGeneralRecordId, patch.globalRecords[0]?.id ?? 0);
|
lastGeneralRecordId = Math.max(lastGeneralRecordId, patch.globalRecords[0]?.id ?? 0);
|
||||||
@@ -425,6 +432,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
patch.boardAccess = boardAccessSnapshot ?? null;
|
patch.boardAccess = boardAccessSnapshot ?? null;
|
||||||
patch.reservedGeneralTurns = toRaw(reservedGeneralTurns.value as unknown) as ReservedTurnView[] | null;
|
patch.reservedGeneralTurns = toRaw(reservedGeneralTurns.value as unknown) as ReservedTurnView[] | null;
|
||||||
patch.reservedGeneralRevision = reservedGeneralRevision.value;
|
patch.reservedGeneralRevision = reservedGeneralRevision.value;
|
||||||
|
patch.reservedGeneralAutorunLimit = reservedGeneralAutorunLimit.value;
|
||||||
patch.globalRecords = toRaw(globalRecords.value);
|
patch.globalRecords = toRaw(globalRecords.value);
|
||||||
patch.generalRecords = toRaw(generalRecords.value);
|
patch.generalRecords = toRaw(generalRecords.value);
|
||||||
patch.worldHistory = toRaw(worldHistory.value);
|
patch.worldHistory = toRaw(worldHistory.value);
|
||||||
@@ -552,6 +560,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
generalTurns.turns
|
generalTurns.turns
|
||||||
) as ReservedTurnView[];
|
) as ReservedTurnView[];
|
||||||
reservedGeneralRevision.value = generalTurns.revision;
|
reservedGeneralRevision.value = generalTurns.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = generalTurns.autorunLimit ?? null;
|
||||||
if (records) {
|
if (records) {
|
||||||
applyRecentRecords(records);
|
applyRecentRecords(records);
|
||||||
}
|
}
|
||||||
@@ -672,6 +681,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
if (generalTurns !== undefined) {
|
if (generalTurns !== undefined) {
|
||||||
patch.reservedGeneralTurns = generalTurns.turns;
|
patch.reservedGeneralTurns = generalTurns.turns;
|
||||||
patch.reservedGeneralRevision = generalTurns.revision;
|
patch.reservedGeneralRevision = generalTurns.revision;
|
||||||
|
patch.reservedGeneralAutorunLimit = generalTurns.autorunLimit ?? null;
|
||||||
}
|
}
|
||||||
if (records) {
|
if (records) {
|
||||||
const nextGlobalRecords = mergeRecentRecords(globalRecords.value, records.global);
|
const nextGlobalRecords = mergeRecentRecords(globalRecords.value, records.global);
|
||||||
@@ -836,12 +846,14 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
});
|
});
|
||||||
reservedGeneralTurns.value = result.turns;
|
reservedGeneralTurns.value = result.turns;
|
||||||
reservedGeneralRevision.value = result.revision;
|
reservedGeneralRevision.value = result.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = result.autorunLimit ?? null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = resolveErrorMessage(err);
|
error.value = resolveErrorMessage(err);
|
||||||
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
||||||
if (snapshot) {
|
if (snapshot) {
|
||||||
reservedGeneralTurns.value = snapshot.turns;
|
reservedGeneralTurns.value = snapshot.turns;
|
||||||
reservedGeneralRevision.value = snapshot.revision;
|
reservedGeneralRevision.value = snapshot.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = snapshot.autorunLimit ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -859,12 +871,14 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
});
|
});
|
||||||
reservedGeneralTurns.value = result.turns;
|
reservedGeneralTurns.value = result.turns;
|
||||||
reservedGeneralRevision.value = result.revision;
|
reservedGeneralRevision.value = result.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = result.autorunLimit ?? null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = resolveErrorMessage(err);
|
error.value = resolveErrorMessage(err);
|
||||||
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
||||||
if (snapshot) {
|
if (snapshot) {
|
||||||
reservedGeneralTurns.value = snapshot.turns;
|
reservedGeneralTurns.value = snapshot.turns;
|
||||||
reservedGeneralRevision.value = snapshot.revision;
|
reservedGeneralRevision.value = snapshot.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = snapshot.autorunLimit ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -882,12 +896,14 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
});
|
});
|
||||||
reservedGeneralTurns.value = result.turns;
|
reservedGeneralTurns.value = result.turns;
|
||||||
reservedGeneralRevision.value = result.revision;
|
reservedGeneralRevision.value = result.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = result.autorunLimit ?? null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = resolveErrorMessage(err);
|
error.value = resolveErrorMessage(err);
|
||||||
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
||||||
if (snapshot) {
|
if (snapshot) {
|
||||||
reservedGeneralTurns.value = snapshot.turns;
|
reservedGeneralTurns.value = snapshot.turns;
|
||||||
reservedGeneralRevision.value = snapshot.revision;
|
reservedGeneralRevision.value = snapshot.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = snapshot.autorunLimit ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -903,12 +919,14 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
});
|
});
|
||||||
reservedGeneralTurns.value = result.turns;
|
reservedGeneralTurns.value = result.turns;
|
||||||
reservedGeneralRevision.value = result.revision;
|
reservedGeneralRevision.value = result.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = result.autorunLimit ?? null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = resolveErrorMessage(err);
|
error.value = resolveErrorMessage(err);
|
||||||
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
const snapshot = await trpc.turns.reserved.getGeneral.query({ generalId: id }).catch(() => null);
|
||||||
if (snapshot) {
|
if (snapshot) {
|
||||||
reservedGeneralTurns.value = snapshot.turns;
|
reservedGeneralTurns.value = snapshot.turns;
|
||||||
reservedGeneralRevision.value = snapshot.revision;
|
reservedGeneralRevision.value = snapshot.revision;
|
||||||
|
reservedGeneralAutorunLimit.value = snapshot.autorunLimit ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1192,6 +1210,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
|||||||
messageContacts,
|
messageContacts,
|
||||||
boardAccess,
|
boardAccess,
|
||||||
reservedGeneralTurns,
|
reservedGeneralTurns,
|
||||||
|
reservedGeneralAutorunLimit,
|
||||||
globalRecords,
|
globalRecords,
|
||||||
generalRecords,
|
generalRecords,
|
||||||
worldHistory,
|
worldHistory,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ const {
|
|||||||
messages,
|
messages,
|
||||||
boardAccess,
|
boardAccess,
|
||||||
reservedGeneralTurns,
|
reservedGeneralTurns,
|
||||||
|
reservedGeneralAutorunLimit,
|
||||||
globalRecords,
|
globalRecords,
|
||||||
generalRecords,
|
generalRecords,
|
||||||
worldHistory,
|
worldHistory,
|
||||||
@@ -218,6 +219,7 @@ watch(
|
|||||||
:current-year="lobbyInfo?.year"
|
:current-year="lobbyInfo?.year"
|
||||||
:current-month="lobbyInfo?.month"
|
:current-month="lobbyInfo?.month"
|
||||||
:turn-term-minutes="lobbyInfo?.turnTerm"
|
:turn-term-minutes="lobbyInfo?.turnTerm"
|
||||||
|
:autorun-limit="reservedGeneralAutorunLimit"
|
||||||
@set-general-turns="reserveGeneralTurns"
|
@set-general-turns="reserveGeneralTurns"
|
||||||
@shift-general-turns="shiftGeneralTurns"
|
@shift-general-turns="shiftGeneralTurns"
|
||||||
@repeat-general-turns="repeatGeneralTurns"
|
@repeat-general-turns="repeatGeneralTurns"
|
||||||
@@ -341,6 +343,7 @@ watch(
|
|||||||
:current-year="lobbyInfo?.year"
|
:current-year="lobbyInfo?.year"
|
||||||
:current-month="lobbyInfo?.month"
|
:current-month="lobbyInfo?.month"
|
||||||
:turn-term-minutes="lobbyInfo?.turnTerm"
|
:turn-term-minutes="lobbyInfo?.turnTerm"
|
||||||
|
:autorun-limit="reservedGeneralAutorunLimit"
|
||||||
@set-general-turns="reserveGeneralTurns"
|
@set-general-turns="reserveGeneralTurns"
|
||||||
@shift-general-turns="shiftGeneralTurns"
|
@shift-general-turns="shiftGeneralTurns"
|
||||||
@repeat-general-turns="repeatGeneralTurns"
|
@repeat-general-turns="repeatGeneralTurns"
|
||||||
@@ -571,6 +574,7 @@ button {
|
|||||||
.layout-desktop {
|
.layout-desktop {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(10, minmax(0, 1fr));
|
grid-template-columns: repeat(10, minmax(0, 1fr));
|
||||||
|
grid-template-rows: 520px minmax(125px, auto) auto;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
@@ -584,32 +588,30 @@ button {
|
|||||||
|
|
||||||
.layout-desktop > [data-main-target='commands'] {
|
.layout-desktop > [data-main-target='commands'] {
|
||||||
grid-column: 8 / 11;
|
grid-column: 8 / 11;
|
||||||
grid-row: 1;
|
grid-row: 1 / 3;
|
||||||
height: 645px;
|
min-height: 645px;
|
||||||
width: 290px;
|
width: 290px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
overflow-y: auto;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-desktop > [data-main-target='city'] {
|
.layout-desktop > [data-main-target='city'] {
|
||||||
grid-column: 1 / 8;
|
grid-column: 1 / 8;
|
||||||
grid-row: 1;
|
grid-row: 2;
|
||||||
|
align-self: stretch;
|
||||||
min-height: 125px;
|
min-height: 125px;
|
||||||
margin-top: 520px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-desktop > [data-main-target='nation'] {
|
.layout-desktop > [data-main-target='nation'] {
|
||||||
grid-column: 1 / 6;
|
grid-column: 1 / 6;
|
||||||
grid-row: 1;
|
grid-row: 3;
|
||||||
min-height: 193px;
|
min-height: 193px;
|
||||||
margin-top: 645px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-desktop > [data-main-target='general'] {
|
.layout-desktop > [data-main-target='general'] {
|
||||||
grid-column: 6 / 11;
|
grid-column: 6 / 11;
|
||||||
grid-row: 1;
|
grid-row: 3;
|
||||||
min-height: 193px;
|
min-height: 193px;
|
||||||
margin-top: 645px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-desktop > [data-main-target],
|
.layout-desktop > [data-main-target],
|
||||||
@@ -719,8 +721,8 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.layout-mobile [data-main-target='commands'] {
|
.layout-mobile [data-main-target='commands'] {
|
||||||
height: 645px;
|
min-height: 645px;
|
||||||
overflow-y: auto;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mobile [data-main-target='nation'],
|
.layout-mobile [data-main-target='nation'],
|
||||||
|
|||||||
Reference in New Issue
Block a user