Compare commits

..

No commits in common. "6fcd879287a38973a4c3fced07fdfb3c02833050" and "b2e10d847e1e8113043612f692db4809e56375ed" have entirely different histories.

7 changed files with 51 additions and 87 deletions

View File

@ -1,10 +1,9 @@
import {createMemo, For} from 'solid-js'; import {createMemo, For} from 'solid-js';
import {parseMarkdown} from '../../markdown'; import { marked } from '../../markdown';
import { getLayerStyle } from './hooks/dimensions'; import { getLayerStyle } from './hooks/dimensions';
import type { CardData } from './types'; import type { CardData } from './types';
import {DeckStore} from "./hooks/deckStore"; import {DeckStore} from "./hooks/deckStore";
import {processVariables} from "../utils/csv-loader"; import {processVariables} from "../utils/csv-loader";
import {resolvePath} from "../utils/path";
export interface CardLayerProps { export interface CardLayerProps {
cardData: CardData; cardData: CardData;
@ -17,8 +16,7 @@ export function CardLayer(props: CardLayerProps) {
const showBounds = () => props.store.state.isEditing; const showBounds = () => props.store.state.isEditing;
function renderLayerContent(content: string) { function renderLayerContent(content: string) {
const iconPath = resolvePath(props.store.state.cards.sourcePath, props.cardData.iconPath); return marked.parse(processVariables(content, props.cardData, props.store.state.cards)) as string;
return parseMarkdown(processVariables(content, props.cardData, props.store.state.cards), iconPath) as string;
} }
return ( return (
<For each={layers()}> <For each={layers()}>

View File

@ -49,8 +49,6 @@ export function LayerEditorPanel(props: LayerEditorPanelProps) {
/> />
<span class="text-sm flex-1">{layer.prop}</span> <span class="text-sm flex-1">{layer.prop}</span>
</div> </div>
{layer.visible && (
<>
<button <button
onClick={() => store.actions.setEditingLayer(store.state.editingLayer === layer.prop ? null : layer.prop)} onClick={() => store.actions.setEditingLayer(store.state.editingLayer === layer.prop ? null : layer.prop)}
class={`text-xs px-2 py-1 rounded cursor-pointer ${ class={`text-xs px-2 py-1 rounded cursor-pointer ${
@ -89,8 +87,6 @@ export function LayerEditorPanel(props: LayerEditorPanelProps) {
min="0.1" min="0.1"
/> />
</div> </div>
</>
)}
</div> </div>
)} )}
</For> </For>

View File

@ -74,7 +74,7 @@ export interface DeckActions {
setPadding: (padding: number) => void; setPadding: (padding: number) => void;
// 数据设置 // 数据设置
setCards: (cards: CSV<CardData>) => void; setCards: (cards: CardData[]) => void;
setActiveTab: (index: number) => void; setActiveTab: (index: number) => void;
updateCardData: (index: number, key: string, value: string) => void; updateCardData: (index: number, key: string, value: string) => void;
@ -139,7 +139,7 @@ export function createDeckStore(
src: initialSrc, src: initialSrc,
rawSrc: initialSrc, rawSrc: initialSrc,
dimensions: null, dimensions: null,
cards: [] as any, cards: [],
activeTab: 0, activeTab: 0,
layerConfigs: [], layerConfigs: [],
isEditing: false, isEditing: false,
@ -195,7 +195,7 @@ export function createDeckStore(
updateDimensions(); updateDimensions();
}; };
const setCards = (cards: CSV<CardData>) => setState({ cards, activeTab: 0 }); const setCards = (cards: CardData[]) => setState({ cards, activeTab: 0 });
const setActiveTab = (index: number) => setState({ activeTab: index }); const setActiveTab = (index: number) => setState({ activeTab: index });
const updateCardData = (index: number, key: string, value: string) => { const updateCardData = (index: number, key: string, value: string) => {
setState('cards', index, key, value); setState('cards', index, key, value);
@ -269,22 +269,7 @@ export function createDeckStore(
const generateCode = () => { const generateCode = () => {
const layersStr = formatLayers(state.layerConfigs); const layersStr = formatLayers(state.layerConfigs);
const parts = [ return `:md-deck[${state.rawSrc || state.src}]{size="${state.sizeW}x${state.sizeH}" grid="${state.gridW}x${state.gridH}" bleed="${state.bleed}" padding="${state.padding}" layers="${layersStr}"}`;
`:md-deck[${state.rawSrc || state.src}]`,
`{size="${state.sizeW}x${state.sizeH} "`,
`grid="${state.gridW}x${state.gridH} "`
];
// 仅在非默认值时添加 bleed 和 padding
if (state.bleed !== DECK_DEFAULTS.BLEED) {
parts.push(`bleed="${state.bleed} "`);
}
if (state.padding !== DECK_DEFAULTS.PADDING) {
parts.push(`padding="${state.padding} "`);
}
parts.push(`layers="${layersStr}"}`);
return parts.join('');
}; };
const copyCode = async () => { const copyCode = async () => {

View File

@ -57,6 +57,9 @@ export function initLayerConfigs(
): LayerConfig[] { ): LayerConfig[] {
const parsed = parseLayers(existingLayersStr); const parsed = parseLayers(existingLayersStr);
const allProps = Object.keys(data[0] || {}).filter(k => k !== 'label'); const allProps = Object.keys(data[0] || {}).filter(k => k !== 'label');
if(data.frontmatter){
allProps.push(...Object.keys(data.frontmatter));
}
return allProps.map(prop => { return allProps.map(prop => {
const existing = parsed.find(l => l.prop === prop); const existing = parsed.find(l => l.prop === prop);

View File

@ -68,10 +68,9 @@ export async function loadCSV<T = Record<string, string>>(path: string): Promise
if (frontmatter) { if (frontmatter) {
csvResult.frontmatter = frontmatter; csvResult.frontmatter = frontmatter;
for(const each of result){ for(const each of result){
Object.assign(each, frontmatter); Object.setPrototypeOf(each, frontmatter);
} }
} }
csvResult.sourcePath = path;
csvCache.set(path, result); csvCache.set(path, result);
return csvResult; return csvResult;
@ -83,7 +82,6 @@ interface JSONObject extends Record<string, JSONData> {}
export type CSV<T> = T[] & { export type CSV<T> = T[] & {
frontmatter?: JSONObject; frontmatter?: JSONObject;
sourcePath: string;
} }
export function processVariables<T extends JSONObject> (body: string, currentRow: T, csv: CSV<T>, filtered?: T[], remix?: boolean): string { export function processVariables<T extends JSONObject> (body: string, currentRow: T, csv: CSV<T>, filtered?: T[], remix?: boolean): string {
@ -99,5 +97,5 @@ export function processVariables<T extends JSONObject> (body: string, currentRow
return `{{${key}}}`; return `{{${key}}}`;
} }
return body?.replace(/\{\{(\w+)\}\}/g, (_, key) => `${replaceProp(key)}`) || ''; return body.replace(/\{\{(\w+)\}\}/g, (_, key) => `${replaceProp(key)}`);
} }

View File

@ -5,15 +5,6 @@ import markedAlert from "marked-alert";
import markedMermaid from "./mermaid"; import markedMermaid from "./mermaid";
import {gfmHeadingId} from "marked-gfm-heading-id"; import {gfmHeadingId} from "marked-gfm-heading-id";
let globalIconPrefix: string | undefined = undefined;
function overrideIconPrefix(path?: string){
globalIconPrefix = path;
return {
[Symbol.dispose](){
globalIconPrefix = undefined;
}
}
}
// 使用 marked-directive 来支持指令语法 // 使用 marked-directive 来支持指令语法
const marked = new Marked() const marked = new Marked()
.use(gfmHeadingId()) .use(gfmHeadingId())
@ -35,8 +26,7 @@ const marked = new Marked()
// :[blah] becomes <i class="icon icon-blah"></i> // :[blah] becomes <i class="icon icon-blah"></i>
renderer(token) { renderer(token) {
if (!token.meta.name) { if (!token.meta.name) {
const style = globalIconPrefix ? `style="--icon-src: url('${globalIconPrefix}/${token.text}.png')"` : ''; return `<icon class="icon-${token.text}"></icon>`;
return `<icon ${style} class="icon-${token.text}"></icon>`;
} }
return false; return false;
} }
@ -99,8 +89,7 @@ const marked = new Marked()
}] }]
}); });
export function parseMarkdown(content: string, iconPrefix?: string): string { export function parseMarkdown(content: string): string {
using prefix = overrideIconPrefix(iconPrefix);
return marked.parse(content.trimStart()) as string; return marked.parse(content.trimStart()) as string;
} }

View File

@ -2,21 +2,16 @@
@plugin "@tailwindcss/typography"; @plugin "@tailwindcss/typography";
/* icon */ /* icon */
icon, pull{ icon{
@apply inline-block; @apply inline-block;
width: 1em; width: 1em;
height: 1.27em; height: 1em;
vertical-align: text-bottom;
--icon-src: ''; --icon-src: '';
background-image: var(--icon-src); background: var(--icon-src);
background-size: contain; background-size: contain;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
pull{
margin-right: -.5em;
width: 0;
}
/* prose */ /* prose */